You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@resilientdb.apache.org by ju...@apache.org on 2026/09/02 07:34:09 UTC
(incubator-resilientdb) 01/01: add thun
This is an automated email from the ASF dual-hosted git repository.
cjcchen pushed a commit to branch thun_merge
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git
commit 50e5c04d0560a414f865779d880c835ee15e6d85
Author: cjcchen <ic...@gmail.com>
AuthorDate: Wed Sep 2 15:33:53 2026 +0800
add thun
---
benchmark/bin/thunderbolt/BUILD | 13 +
benchmark/bin/thunderbolt/kv_server.cpp | 78 +
benchmark/protocols/thunderbolt/BUILD | 25 +
.../thunderbolt/kv_server_performance.cpp | 89 +
.../protocols/thunderbolt/kv_service_tools.cpp | 57 +
executor/common/transaction_manager.h | 19 +
.../consensus/execution/transaction_executor.cpp | 7 +
.../consensus/execution/transaction_executor.h | 3 +
.../common/framework/performance_manager.cpp | 5 +
.../common/framework/performance_manager.h | 3 +
.../consensus/ordering/thunderbolt/algorithm/BUILD | 36 +
.../thunderbolt/algorithm/proposal_manager.cpp | 258 +++
.../thunderbolt/algorithm/proposal_manager.h | 54 +
.../ordering/thunderbolt/algorithm/thunderbolt.cpp | 555 ++++++
.../ordering/thunderbolt/algorithm/thunderbolt.h | 79 +
.../algorithm/transaction_collector.cpp | 55 +
.../thunderbolt/algorithm/transaction_collector.h | 71 +
.../ordering/thunderbolt/executor/common/BUILD | 18 +
.../executor/common/contract_execute_info.h | 71 +
.../ordering/thunderbolt/executor/common/utils.h | 36 +
.../thunderbolt/executor/common/x_verifier.cpp | 187 ++
.../thunderbolt/executor/common/x_verifier.h | 72 +
.../ordering/thunderbolt/executor/eo_service/BUILD | 26 +
.../eo_service/contract_transaction_manager.cpp | 130 ++
.../eo_service/contract_transaction_manager.h | 56 +
.../contract_transaction_manager_test.cpp | 270 +++
.../executor/eo_service/test_data/BUILD | 1 +
.../executor/eo_service/test_data/contract.json | 19 +
.../ordering/thunderbolt/executor/manager/BUILD | 620 +++++++
.../executor/manager/address_manager.cpp | 81 +
.../thunderbolt/executor/manager/address_manager.h | 56 +
.../executor/manager/address_manager_test.cpp | 58 +
.../executor/manager/committer_context.cpp | 60 +
.../executor/manager/committer_context.h | 53 +
.../executor/manager/concurrency_controller.cpp | 16 +
.../executor/manager/concurrency_controller.h | 51 +
.../executor/manager/contract_committer.h | 80 +
.../executor/manager/contract_deployer.cpp | 186 ++
.../executor/manager/contract_deployer.h | 68 +
.../executor/manager/contract_deployer_test.cpp | 119 ++
.../executor/manager/contract_executor.cpp | 98 +
.../executor/manager/contract_executor.h | 73 +
.../executor/manager/contract_executor_test.cpp | 367 ++++
.../executor/manager/contract_manager.cpp | 225 +++
.../executor/manager/contract_manager.h | 95 +
.../executor/manager/contract_manager_test.cpp | 260 +++
.../executor/manager/contract_verifier.cpp | 50 +
.../executor/manager/contract_verifier.h | 59 +
.../thunderbolt/executor/manager/d_storage.cpp | 162 ++
.../thunderbolt/executor/manager/d_storage.h | 35 +
.../thunderbolt/executor/manager/data_storage.cpp | 72 +
.../thunderbolt/executor/manager/data_storage.h | 36 +
.../thunderbolt/executor/manager/evm_state.h | 23 +
.../thunderbolt/executor/manager/global_state.cpp | 46 +
.../thunderbolt/executor/manager/global_state.h | 43 +
.../thunderbolt/executor/manager/global_view.cpp | 23 +
.../thunderbolt/executor/manager/global_view.h | 25 +
.../executor/manager/level_d_storage.cpp | 207 +++
.../thunderbolt/executor/manager/level_d_storage.h | 36 +
.../thunderbolt/executor/manager/leveldb.cpp | 30 +
.../thunderbolt/executor/manager/leveldb.h | 25 +
.../executor/manager/leveldb_d_storage.cpp | 203 +++
.../executor/manager/leveldb_d_storage.h | 40 +
.../executor/manager/leveldb_storage.cpp | 111 ++
.../thunderbolt/executor/manager/leveldb_storage.h | 41 +
.../thunderbolt/executor/manager/local_state.cpp | 70 +
.../thunderbolt/executor/manager/local_state.h | 52 +
.../thunderbolt/executor/manager/local_view.cpp | 77 +
.../thunderbolt/executor/manager/local_view.h | 38 +
.../executor/manager/local_view_test.cpp | 122 ++
.../thunderbolt/executor/manager/mock_d_storage.h | 49 +
.../executor/manager/mock_data_storage.h | 47 +
.../thunderbolt/executor/manager/ooo_committer.cpp | 113 ++
.../thunderbolt/executor/manager/ooo_committer.h | 74 +
.../executor/manager/ooo_controller.cpp | 36 +
.../thunderbolt/executor/manager/ooo_controller.h | 17 +
.../executor/manager/sequential_cc_controller.cpp | 267 +++
.../executor/manager/sequential_cc_controller.h | 70 +
.../manager/sequential_cc_controller_test.cpp | 1011 +++++++++++
.../manager/sequential_concurrency_committer.cpp | 252 +++
.../manager/sequential_concurrency_committer.h | 113 ++
.../sequential_concurrency_committer_test.cpp | 258 +++
.../executor/manager/streaming_committer.cpp | 333 ++++
.../executor/manager/streaming_committer.h | 133 ++
.../executor/manager/streaming_controller.cpp | 232 +++
.../executor/manager/streaming_controller.h | 61 +
.../executor/manager/streaming_dq_committer.cpp | 370 ++++
.../executor/manager/streaming_dq_committer.h | 110 ++
.../manager/streaming_dq_committer_test.cpp | 1137 ++++++++++++
.../executor/manager/streaming_dq_controller.cpp | 249 +++
.../executor/manager/streaming_dq_controller.h | 76 +
.../manager/streaming_single_committer.cpp | 96 +
.../executor/manager/streaming_single_committer.h | 83 +
.../executor/manager/test_committer.cpp | 74 +
.../thunderbolt/executor/manager/test_committer.h | 62 +
.../executor/manager/test_controller.cpp | 38 +
.../thunderbolt/executor/manager/test_controller.h | 19 +
.../thunderbolt/executor/manager/test_data/BUILD | 4 +
.../executor/manager/test_data/compile.sh | 5 +
.../executor/manager/test_data/contract.json | 19 +
.../thunderbolt/executor/manager/test_data/kv.json | 18 +
.../thunderbolt/executor/manager/test_data/kv.sol | 59 +
.../executor/manager/two_phase_committer.cpp | 170 ++
.../executor/manager/two_phase_committer.h | 72 +
.../executor/manager/two_phase_committer_test.cpp | 352 ++++
.../executor/manager/two_phase_controller.cpp | 115 ++
.../executor/manager/two_phase_controller.h | 33 +
.../executor/manager/two_phase_controller_test.cpp | 435 +++++
.../executor/manager/two_phase_ooo_committer.cpp | 162 ++
.../executor/manager/two_phase_ooo_committer.h | 72 +
.../executor/manager/two_phase_ooo_controller.cpp | 89 +
.../executor/manager/two_phase_ooo_controller.h | 33 +
.../thunderbolt/executor/manager/v_controller.cpp | 87 +
.../thunderbolt/executor/manager/v_controller.h | 32 +
.../thunderbolt/executor/manager/x_committer.cpp | 206 +++
.../thunderbolt/executor/manager/x_committer.h | 89 +
.../executor/manager/x_committer_test.cpp | 258 +++
.../thunderbolt/executor/manager/x_controller.cpp | 237 +++
.../thunderbolt/executor/manager/x_controller.h | 79 +
.../thunderbolt/executor/manager/x_verifier.cpp | 188 ++
.../thunderbolt/executor/manager/x_verifier.h | 72 +
.../executor/manager/x_verifier_test.cpp | 236 +++
.../thunderbolt/executor/manager/xexecutor.cpp | 286 +++
.../thunderbolt/executor/manager/xexecutor.h | 108 ++
.../ordering/thunderbolt/executor/paral_sm/BUILD | 299 ++++
.../executor/paral_sm/address_manager.cpp | 75 +
.../executor/paral_sm/address_manager.h | 57 +
.../executor/paral_sm/address_manager_test.cpp | 58 +
.../executor/paral_sm/committer_context.cpp | 58 +
.../executor/paral_sm/committer_context.h | 54 +
.../executor/paral_sm/concurrency_controller.cpp | 16 +
.../executor/paral_sm/concurrency_controller.h | 48 +
.../executor/paral_sm/contract_committer.h | 79 +
.../executor/paral_sm/contract_deployer.cpp | 130 ++
.../executor/paral_sm/contract_deployer.h | 63 +
.../executor/paral_sm/contract_deployer_test.cpp | 119 ++
.../executor/paral_sm/contract_executor.cpp | 98 +
.../executor/paral_sm/contract_executor.h | 69 +
.../executor/paral_sm/contract_executor_test.cpp | 367 ++++
.../executor/paral_sm/contract_manager.cpp | 118 ++
.../executor/paral_sm/contract_manager.h | 80 +
.../executor/paral_sm/contract_manager_test.cpp | 260 +++
.../thunderbolt/executor/paral_sm/d_storage.cpp | 149 ++
.../thunderbolt/executor/paral_sm/d_storage.h | 37 +
.../thunderbolt/executor/paral_sm/data_storage.cpp | 49 +
.../thunderbolt/executor/paral_sm/data_storage.h | 35 +
.../thunderbolt/executor/paral_sm/db_view.cpp | 41 +
.../thunderbolt/executor/paral_sm/db_view.h | 41 +
.../thunderbolt/executor/paral_sm/evm_state.h | 23 +
.../thunderbolt/executor/paral_sm/executor_state.h | 54 +
.../thunderbolt/executor/paral_sm/global_state.cpp | 48 +
.../thunderbolt/executor/paral_sm/global_state.h | 45 +
.../thunderbolt/executor/paral_sm/global_view.cpp | 25 +
.../thunderbolt/executor/paral_sm/global_view.h | 27 +
.../thunderbolt/executor/paral_sm/leveldb.cpp | 30 +
.../thunderbolt/executor/paral_sm/leveldb.h | 25 +
.../thunderbolt/executor/paral_sm/local_state.cpp | 70 +
.../thunderbolt/executor/paral_sm/local_state.h | 52 +
.../thunderbolt/executor/paral_sm/local_view.cpp | 51 +
.../thunderbolt/executor/paral_sm/local_view.h | 38 +
.../executor/paral_sm/local_view_test.cpp | 122 ++
.../thunderbolt/executor/paral_sm/mock_d_storage.h | 54 +
.../executor/paral_sm/mock_data_storage.h | 47 +
.../executor/paral_sm/mock_e_controller.h | 50 +
.../executor/paral_sm/streaming_e_committer.cpp | 317 ++++
.../executor/paral_sm/streaming_e_committer.h | 110 ++
.../paral_sm/streaming_e_committer_test.cpp | 909 ++++++++++
.../executor/paral_sm/streaming_e_controller.cpp | 718 ++++++++
.../executor/paral_sm/streaming_e_controller.h | 112 ++
.../executor/paral_sm/test_committer.cpp | 74 +
.../thunderbolt/executor/paral_sm/test_committer.h | 62 +
.../executor/paral_sm/test_controller.cpp | 38 +
.../executor/paral_sm/test_controller.h | 19 +
.../thunderbolt/executor/paral_sm/test_data/BUILD | 4 +
.../executor/paral_sm/test_data/compile.sh | 5 +
.../executor/paral_sm/test_data/contract.json | 19 +
.../executor/paral_sm/test_data/kv.json | 18 +
.../thunderbolt/executor/paral_sm/test_data/kv.sol | 59 +
.../ordering/thunderbolt/executor/paral_sm/utils.h | 36 +
.../thunderbolt/executor/paral_sm/xcommitter.h | 110 ++
.../thunderbolt/executor/paral_sm/xcontroller.cpp | 626 +++++++
.../thunderbolt/executor/paral_sm/xcontroller.h | 75 +
.../thunderbolt/executor/paral_sm/xexecutor.cpp | 286 +++
.../thunderbolt/executor/paral_sm/xexecutor.h | 108 ++
.../ordering/thunderbolt/executor/service/BUILD | 26 +
.../service/contract_transaction_manager.cpp | 128 ++
.../service/contract_transaction_manager.h | 56 +
.../service/contract_transaction_manager_test.cpp | 270 +++
.../thunderbolt/executor/service/test_data/BUILD | 1 +
.../executor/service/test_data/contract.json | 19 +
.../executor/x_manager/2pl_committer.cpp | 246 +++
.../thunderbolt/executor/x_manager/2pl_committer.h | 106 ++
.../executor/x_manager/2pl_controller.cpp | 302 ++++
.../executor/x_manager/2pl_controller.h | 108 ++
.../ordering/thunderbolt/executor/x_manager/BUILD | 569 ++++++
.../executor/x_manager/address_manager.cpp | 83 +
.../executor/x_manager/address_manager.h | 58 +
.../executor/x_manager/address_manager_test.cpp | 58 +
.../executor/x_manager/committer_context.cpp | 62 +
.../executor/x_manager/committer_context.h | 57 +
.../executor/x_manager/concurrency_controller.cpp | 18 +
.../executor/x_manager/concurrency_controller.h | 56 +
.../executor/x_manager/contract_committer.h | 82 +
.../executor/x_manager/contract_deployer.cpp | 190 ++
.../executor/x_manager/contract_deployer.h | 70 +
.../executor/x_manager/contract_deployer_test.cpp | 119 ++
.../executor/x_manager/contract_executor.cpp | 98 +
.../executor/x_manager/contract_executor.h | 75 +
.../executor/x_manager/contract_executor_test.cpp | 367 ++++
.../executor/x_manager/contract_manager.cpp | 174 ++
.../executor/x_manager/contract_manager.h | 96 +
.../executor/x_manager/contract_manager_test.cpp | 260 +++
.../executor/x_manager/contract_verifier.cpp | 52 +
.../executor/x_manager/contract_verifier.h | 62 +
.../thunderbolt/executor/x_manager/d_storage.cpp | 171 ++
.../thunderbolt/executor/x_manager/d_storage.h | 37 +
.../executor/x_manager/data_storage.cpp | 81 +
.../thunderbolt/executor/x_manager/data_storage.h | 37 +
.../thunderbolt/executor/x_manager/db_view.cpp | 43 +
.../thunderbolt/executor/x_manager/db_view.h | 42 +
.../executor/x_manager/dx_committer.cpp | 270 +++
.../thunderbolt/executor/x_manager/dx_committer.h | 107 ++
.../executor/x_manager/dx_controller.cpp | 1794 +++++++++++++++++++
.../thunderbolt/executor/x_manager/dx_controller.h | 149 ++
.../thunderbolt/executor/x_manager/e_committer.cpp | 256 +++
.../thunderbolt/executor/x_manager/e_committer.h | 107 ++
.../executor/x_manager/e_committer_test.cpp | 293 +++
.../executor/x_manager/e_controller.cpp | 697 ++++++++
.../thunderbolt/executor/x_manager/e_controller.h | 111 ++
.../thunderbolt/executor/x_manager/evm_state.h | 23 +
.../executor/x_manager/executor_state.cpp | 75 +
.../executor/x_manager/executor_state.h | 54 +
.../executor/x_manager/fx_committer.cpp | 258 +++
.../thunderbolt/executor/x_manager/fx_committer.h | 107 ++
.../executor/x_manager/fx_controller.cpp | 1872 +++++++++++++++++++
.../executor/x_manager/fx_controller.cpp.bak2 | 1648 +++++++++++++++++
.../executor/x_manager/fx_controller.cpp.bak3 | 1891 ++++++++++++++++++++
.../thunderbolt/executor/x_manager/fx_controller.h | 161 ++
.../executor/x_manager/fx_controller.h.bak3 | 149 ++
.../executor/x_manager/global_state.cpp | 48 +
.../thunderbolt/executor/x_manager/global_state.h | 45 +
.../thunderbolt/executor/x_manager/global_view.cpp | 25 +
.../thunderbolt/executor/x_manager/global_view.h | 27 +
.../thunderbolt/executor/x_manager/leveldb.cpp | 30 +
.../thunderbolt/executor/x_manager/leveldb.h | 25 +
.../executor/x_manager/leveldb_d_storage.cpp | 210 +++
.../executor/x_manager/leveldb_d_storage.h | 42 +
.../executor/x_manager/leveldb_storage.cpp | 121 ++
.../executor/x_manager/leveldb_storage.h | 43 +
.../thunderbolt/executor/x_manager/local_state.cpp | 72 +
.../thunderbolt/executor/x_manager/local_state.h | 54 +
.../thunderbolt/executor/x_manager/local_view.cpp | 59 +
.../thunderbolt/executor/x_manager/local_view.h | 40 +
.../executor/x_manager/local_view_test.cpp | 122 ++
.../executor/x_manager/mock_d_storage.h | 54 +
.../executor/x_manager/mock_data_storage.h | 47 +
.../executor/x_manager/mock_e_controller.h | 50 +
.../executor/x_manager/seq_committer.cpp | 85 +
.../thunderbolt/executor/x_manager/seq_committer.h | 92 +
.../executor/x_manager/seq_controller.cpp | 1792 +++++++++++++++++++
.../executor/x_manager/seq_controller.h | 149 ++
.../executor/x_manager/streaming_e_committer.cpp | 337 ++++
.../executor/x_manager/streaming_e_committer.h | 112 ++
.../x_manager/streaming_e_committer_test.cpp | 873 +++++++++
.../executor/x_manager/streaming_e_controller.cpp | 618 +++++++
.../executor/x_manager/streaming_e_controller.h | 153 ++
.../executor/x_manager/test_committer.cpp | 74 +
.../executor/x_manager/test_committer.h | 62 +
.../executor/x_manager/test_controller.cpp | 38 +
.../executor/x_manager/test_controller.h | 19 +
.../thunderbolt/executor/x_manager/test_data/BUILD | 4 +
.../executor/x_manager/test_data/compile.sh | 5 +
.../executor/x_manager/test_data/contract.json | 19 +
.../executor/x_manager/test_data/kv.json | 18 +
.../executor/x_manager/test_data/kv.sol | 59 +
.../thunderbolt/executor/x_manager/utils.h | 36 +
.../executor/x_manager/v_controller.cpp | 89 +
.../thunderbolt/executor/x_manager/v_controller.h | 34 +
.../thunderbolt/executor/x_manager/x_committer.cpp | 254 +++
.../thunderbolt/executor/x_manager/x_committer.h | 107 ++
.../executor/x_manager/x_controller.cpp | 1793 +++++++++++++++++++
.../thunderbolt/executor/x_manager/x_controller.h | 149 ++
.../thunderbolt/executor/x_manager/x_verifier.cpp | 214 +++
.../thunderbolt/executor/x_manager/x_verifier.h | 74 +
.../consensus/ordering/thunderbolt/framework/BUILD | 19 +
.../ordering/thunderbolt/framework/consensus.cpp | 217 +++
.../ordering/thunderbolt/framework/consensus.h | 84 +
.../thunderbolt/framework/consensus_test.cpp | 179 ++
.../framework/performance_manager.cpp | 159 +-
.../framework/performance_manager.h | 66 +-
.../thunderbolt/framework/response_manager.cpp | 240 +++
.../thunderbolt/framework/response_manager.h | 83 +
.../consensus/ordering/thunderbolt/proto/BUILD | 18 +
.../ordering/thunderbolt/proto/proposal.proto | 101 ++
.../consensus/ordering/thunderbolt/protocol/BUILD | 35 +
.../thunderbolt/protocol/proposal_manager.cpp | 414 +++++
.../thunderbolt/protocol/proposal_manager.h | 76 +
.../ordering/thunderbolt/protocol/thunderbolt.cpp | 923 ++++++++++
.../ordering/thunderbolt/protocol/thunderbolt.h | 120 ++
.../thunderbolt/protocol/transaction_collector.cpp | 55 +
.../thunderbolt/protocol/transaction_collector.h | 71 +
platform/proto/resdb.proto | 9 +-
scripts/deploy/config/thunderbolt.config | 10 +
.../deploy/performance/thunderbolt_performance.sh | 53 +
.../performance/thunderboltcc_performance.sh | 2 +
service/contract/thunderbolt_service/BUILD | 53 +
.../thunderbolt_service/contract_server.cpp | 288 +++
.../contract_transaction_manager.cpp | 377 ++++
.../contract_transaction_manager.h | 79 +
.../thunderbolt_service/execution_helper.cpp | 156 ++
.../thunderbolt_service/execution_helper.h | 71 +
.../contract/thunderbolt_service/test_data/BUILD | 4 +
.../thunderbolt_service/test_data/compile.sh | 5 +
.../thunderbolt_service/test_data/contract.json | 19 +
.../contract/thunderbolt_service/test_data/kv.json | 18 +
.../contract/thunderbolt_service/test_data/kv.sol | 59 +
.../thunderbolt_service/thunderbolt_service.cpp | 189 ++
.../thunderbolt_service/thunderbolt_service.h | 71 +
318 files changed, 49131 insertions(+), 113 deletions(-)
diff --git a/benchmark/bin/thunderbolt/BUILD b/benchmark/bin/thunderbolt/BUILD
new file mode 100644
index 000000000..a528a08f0
--- /dev/null
+++ b/benchmark/bin/thunderbolt/BUILD
@@ -0,0 +1,13 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_binary(
+ name = "kv_server",
+ srcs = ["kv_server.cpp"],
+ deps = [
+ "//platform/config:resdb_config_utils",
+ "//platform/consensus/ordering/thunderbolt/framework:consensus",
+ "//executor/kv:kv_executor",
+ "//chain/storage:memory_db",
+ "//service/utils:server_factory",
+ ],
+)
diff --git a/benchmark/bin/thunderbolt/kv_server.cpp b/benchmark/bin/thunderbolt/kv_server.cpp
new file mode 100644
index 000000000..1aca9a12b
--- /dev/null
+++ b/benchmark/bin/thunderbolt/kv_server.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <glog/logging.h>
+
+#include "chain/storage/memory_db.h"
+#include "executor/kv/kv_executor.h"
+#include "platform/config/resdb_config_utils.h"
+#include "platform/consensus/ordering/thunderbolt/framework/consensus.h"
+#include "platform/statistic/stats.h"
+#include "service/utils/server_factory.h"
+
+using resdb::CustomGenerateResDBServer;
+using resdb::GenerateResDBConfig;
+using resdb::KVExecutor;
+using resdb::ResConfigData;
+using resdb::ResDBConfig;
+using resdb::ResDBServer;
+using resdb::Stats;
+using resdb::storage::MemoryDB;
+using resdb::thunderbolt::ThunderboltConsensus;
+
+void ShowUsage() {
+ printf(
+ "<config> <private_key> <cert_file> <durability_option> [logging_dir]\n");
+}
+
+int main(int argc, char** argv) {
+ if (argc < 4) {
+ ShowUsage();
+ exit(0);
+ }
+
+ char* config_file = argv[1];
+ char* private_key_file = argv[2];
+ char* cert_file = argv[3];
+ char* logging_dir = nullptr;
+
+ if (argc >= 7) {
+ logging_dir = argv[5];
+ }
+
+ if (argc >= 6) {
+ auto monitor_port = Stats::GetGlobalStats(5);
+ monitor_port->SetPrometheus(argv[4]);
+ }
+
+ std::unique_ptr<ResDBConfig> config =
+ GenerateResDBConfig(config_file, private_key_file, cert_file);
+ ResConfigData config_data = config->GetConfigData();
+
+ auto server = CustomGenerateResDBServer<ThunderboltConsensus>(
+ config_file, private_key_file, cert_file,
+ std::make_unique<KVExecutor>(std::make_unique<MemoryDB>()), logging_dir);
+ server->Run();
+}
diff --git a/benchmark/protocols/thunderbolt/BUILD b/benchmark/protocols/thunderbolt/BUILD
new file mode 100644
index 000000000..09fcf2698
--- /dev/null
+++ b/benchmark/protocols/thunderbolt/BUILD
@@ -0,0 +1,25 @@
+package(default_visibility = ["//visibility:private"])
+
+load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
+
+cc_binary(
+ name = "kv_server_performance",
+ srcs = ["kv_server_performance.cpp"],
+ deps = [
+ "//chain/storage:memory_db",
+ "//executor/kv:kv_executor",
+ "//platform/config:resdb_config_utils",
+ "//platform/consensus/ordering/thunderbolt/framework:consensus",
+ "//service/utils:server_factory",
+ ],
+)
+
+cc_binary(
+ name = "kv_service_tools",
+ srcs = ["kv_service_tools.cpp"],
+ deps = [
+ "//common/proto:signature_info_cc_proto",
+ "//interface/kv:kv_client",
+ "//platform/config:resdb_config_utils",
+ ],
+)
diff --git a/benchmark/protocols/thunderbolt/kv_server_performance.cpp b/benchmark/protocols/thunderbolt/kv_server_performance.cpp
new file mode 100644
index 000000000..6693df82d
--- /dev/null
+++ b/benchmark/protocols/thunderbolt/kv_server_performance.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <glog/logging.h>
+
+#include "chain/storage/memory_db.h"
+#include "executor/kv/kv_executor.h"
+#include "platform/config/resdb_config_utils.h"
+#include "platform/consensus/ordering/thunderbolt/framework/consensus.h"
+#include "platform/networkstrate/service_network.h"
+#include "platform/statistic/stats.h"
+#include "proto/kv/kv.pb.h"
+
+using namespace resdb;
+using namespace resdb::thunderbolt;
+using namespace resdb::storage;
+
+void ShowUsage() {
+ printf("<config> <private_key> <cert_file> [logging_dir]\n");
+}
+
+std::string GetRandomKey() {
+ int num1 = rand() % 10;
+ int num2 = rand() % 10;
+ return std::to_string(num1) + std::to_string(num2);
+}
+
+int main(int argc, char** argv) {
+ if (argc < 3) {
+ ShowUsage();
+ exit(0);
+ }
+
+ // google::InitGoogleLogging(argv[0]);
+ // FLAGS_minloglevel = google::GLOG_WARNING;
+
+ char* config_file = argv[1];
+ char* private_key_file = argv[2];
+ char* cert_file = argv[3];
+
+ if (argc >= 5) {
+ auto monitor_port = Stats::GetGlobalStats(5);
+ monitor_port->SetPrometheus(argv[4]);
+ }
+
+ std::unique_ptr<ResDBConfig> config =
+ GenerateResDBConfig(config_file, private_key_file, cert_file);
+
+ config->RunningPerformance(true);
+ ResConfigData config_data = config->GetConfigData();
+
+ auto performance_consens = std::make_unique<ThunderboltConsensus>(
+ *config, std::make_unique<KVExecutor>(std::make_unique<MemoryDB>()));
+ performance_consens->SetupPerformanceDataFunc([]() {
+ KVRequest request;
+ request.set_cmd(KVRequest::SET);
+ request.set_key(GetRandomKey());
+ request.set_value("helloworld");
+ std::string request_data;
+ request.SerializeToString(&request_data);
+ return request_data;
+ });
+
+ auto server =
+ std::make_unique<ServiceNetwork>(*config, std::move(performance_consens));
+ server->Run();
+}
diff --git a/benchmark/protocols/thunderbolt/kv_service_tools.cpp b/benchmark/protocols/thunderbolt/kv_service_tools.cpp
new file mode 100644
index 000000000..17858ef21
--- /dev/null
+++ b/benchmark/protocols/thunderbolt/kv_service_tools.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+
+#include "common/proto/signature_info.pb.h"
+#include "interface/kv/kv_client.h"
+#include "platform/config/resdb_config_utils.h"
+
+using resdb::GenerateReplicaInfo;
+using resdb::GenerateResDBConfig;
+using resdb::KVClient;
+using resdb::ReplicaInfo;
+using resdb::ResDBConfig;
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ printf("<config path>\n");
+ return 0;
+ }
+ std::string client_config_file = argv[1];
+ ResDBConfig config = GenerateResDBConfig(client_config_file);
+
+ config.SetClientTimeoutMs(100000);
+
+ KVClient client(config);
+
+ client.Set("start", "value");
+ printf("start benchmark\n");
+}
diff --git a/executor/common/transaction_manager.h b/executor/common/transaction_manager.h
index 33c23389c..294f13926 100644
--- a/executor/common/transaction_manager.h
+++ b/executor/common/transaction_manager.h
@@ -20,6 +20,7 @@
#pragma once
#include <cstdint>
+#include <functional>
#include <memory>
#include "chain/storage/storage.h"
@@ -44,6 +45,23 @@ class TransactionManager {
virtual std::unique_ptr<BatchUserResponse> ExecuteBatch(
const BatchUserRequest& request);
+ virtual std::unique_ptr<BatchUserResponse> ExecutePreparedData(
+ const BatchUserRequest&) {
+ return nullptr;
+ }
+
+ virtual void SetAsyncCallback(
+ std::function<void(const BatchUserRequest, std::unique_ptr<Request>,
+ std::unique_ptr<BatchUserResponse>)>) {}
+
+ virtual void Attach(std::unique_ptr<Request> request) {
+ request_ = std::move(request);
+ }
+
+ virtual std::unique_ptr<Request> FetchRequest() {
+ return std::move(request_);
+ }
+
std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>
Prepare(const BatchUserRequest& request);
@@ -69,6 +87,7 @@ class TransactionManager {
uint64_t seq_ = 0;
std::unique_ptr<Storage> storage_;
+ std::unique_ptr<Request> request_;
private:
bool is_out_of_order_ = false;
diff --git a/platform/consensus/execution/transaction_executor.cpp b/platform/consensus/execution/transaction_executor.cpp
index bf29a0fb5..46b0028fc 100644
--- a/platform/consensus/execution/transaction_executor.cpp
+++ b/platform/consensus/execution/transaction_executor.cpp
@@ -320,6 +320,9 @@ void TransactionExecutor::Execute(std::unique_ptr<Request> request,
if (execute_thread_num_ == 1) {
response = transaction_manager_->ExecuteBatchWithSeq(request->seq(),
*batch_request_p);
+ if (request->flag() > 0 && user_func_) {
+ user_func_(request->flag());
+ }
} else {
std::vector<std::unique_ptr<std::string>> response_v;
@@ -350,6 +353,10 @@ void TransactionExecutor::Execute(std::unique_ptr<Request> request,
}
FinishExecute(request->seq());
+ if (request->flag() > 0 && user_func_) {
+ user_func_(request->flag());
+ }
+
if (response == nullptr) {
response = std::make_unique<BatchUserResponse>();
for (auto& s : response_v) {
diff --git a/platform/consensus/execution/transaction_executor.h b/platform/consensus/execution/transaction_executor.h
index e181920b1..597656d27 100644
--- a/platform/consensus/execution/transaction_executor.h
+++ b/platform/consensus/execution/transaction_executor.h
@@ -72,6 +72,8 @@ class TransactionExecutor {
void WaitForExecute(int64_t seq);
void FinishExecute(int64_t seq);
+ void SetUserFunc(std::function<void(int)> func) { user_func_ = std::move(func); }
+
void Prepare(std::unique_ptr<Request> request);
private:
@@ -104,6 +106,7 @@ class TransactionExecutor {
std::atomic<uint64_t> next_execute_seq_ = 1;
PreExecuteFunc pre_exec_func_ = nullptr;
SeqUpdateNotifyFunc seq_update_notify_func_ = nullptr;
+ std::function<void(int)> user_func_ = nullptr;
PostExecuteFunc post_exec_func_ = nullptr;
SystemInfo* system_info_ = nullptr;
std::unique_ptr<TransactionManager> transaction_manager_ = nullptr;
diff --git a/platform/consensus/ordering/common/framework/performance_manager.cpp b/platform/consensus/ordering/common/framework/performance_manager.cpp
index 21454e4b5..86fd1ddcb 100644
--- a/platform/consensus/ordering/common/framework/performance_manager.cpp
+++ b/platform/consensus/ordering/common/framework/performance_manager.cpp
@@ -93,6 +93,11 @@ void PerformanceManager::SetDataFunc(std::function<std::string()> func) {
data_func_ = std::move(func);
}
+void PerformanceManager::SetPreprocessFunc(
+ std::function<std::vector<std::string>()> preprocess_func) {
+ preprocess_func_ = std::move(preprocess_func);
+}
+
int PerformanceManager::StartEval() {
if (eval_started_) {
return 0;
diff --git a/platform/consensus/ordering/common/framework/performance_manager.h b/platform/consensus/ordering/common/framework/performance_manager.h
index dba5fd8f8..3a6441f6f 100644
--- a/platform/consensus/ordering/common/framework/performance_manager.h
+++ b/platform/consensus/ordering/common/framework/performance_manager.h
@@ -46,6 +46,8 @@ class PerformanceManager {
int ProcessResponseMsg(std::unique_ptr<Context> context,
std::unique_ptr<Request> request);
void SetDataFunc(std::function<std::string()> func);
+ void SetPreprocessFunc(
+ std::function<std::vector<std::string>()> preprocess_func);
protected:
virtual void SendMessage(const Request& request);
@@ -85,6 +87,7 @@ class PerformanceManager {
SignatureVerifier* verifier_;
SignatureInfo sig_;
std::function<std::string()> data_func_;
+ std::function<std::vector<std::string>()> preprocess_func_;
std::future<bool> eval_ready_future_;
std::promise<bool> eval_ready_promise_;
std::atomic<int64_t> eval_ready_counter_{0};
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/BUILD b/platform/consensus/ordering/thunderbolt/algorithm/BUILD
new file mode 100644
index 000000000..289235db4
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/BUILD
@@ -0,0 +1,36 @@
+package(default_visibility = ["//platform/consensus/ordering/thunderbolt:__subpackages__"])
+
+cc_library(
+ name = "proposal_manager",
+ srcs = ["proposal_manager.cpp"],
+ hdrs = ["proposal_manager.h"],
+ deps = [
+ "//common:comm",
+ "//common/crypto:signature_verifier",
+ "//common/utils",
+ "//platform/consensus/ordering/thunderbolt/proto:proposal_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "thunderbolt",
+ srcs = ["thunderbolt.cpp"],
+ hdrs = ["thunderbolt.h"],
+ deps = [
+ ":proposal_manager",
+ "//common:comm",
+ "//common/crypto:signature_verifier",
+ "//platform/common/queue:lock_free_queue",
+ "//platform/consensus/ordering/common/algorithm:protocol_base",
+ "//platform/statistic:stats",
+ ],
+)
+
+cc_library(
+ name = "transaction_collector",
+ srcs = ["transaction_collector.cpp"],
+ hdrs = ["transaction_collector.h"],
+ deps = [
+ "//platform/statistic:stats",
+ ],
+)
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.cpp b/platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.cpp
new file mode 100644
index 000000000..6679baefc
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.cpp
@@ -0,0 +1,258 @@
+#include "platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.h"
+
+#include <glog/logging.h>
+
+#include "common/crypto/signature_verifier.h"
+#include "common/utils/utils.h"
+
+namespace resdb {
+namespace thunderbolt {
+
+ProposalManager::ProposalManager(int32_t id, int limit_count)
+ : id_(id), limit_count_(limit_count) {
+ round_ = 0;
+}
+
+bool ProposalManager::VerifyHash(const Proposal& proposal) {
+ std::string data;
+ for (const auto& txn : proposal.transactions()) {
+ std::string tmp;
+ txn.SerializeToString(&tmp);
+ data += tmp;
+ }
+
+ std::string header_data;
+ proposal.header().SerializeToString(&header_data);
+ data += header_data;
+
+ std::string hash = SignatureVerifier::CalculateHash(data);
+ return hash == proposal.hash();
+}
+
+std::unique_ptr<Proposal> ProposalManager::GenerateProposal(
+ const std::vector<std::unique_ptr<Transaction>>& txns) {
+ std::unique_ptr<Proposal> proposal = std::make_unique<Proposal>();
+ std::string data;
+ {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ for (const auto& txn : txns) {
+ *proposal->add_transactions() = *txn;
+ std::string tmp;
+ txn->SerializeToString(&tmp);
+ data += tmp;
+ }
+ proposal->mutable_header()->set_proposer_id(id_);
+ proposal->mutable_header()->set_create_time(GetCurrentTime());
+ proposal->mutable_header()->set_round(round_);
+ proposal->set_sender(id_);
+
+ GetMetaData(proposal.get());
+ }
+
+ std::string header_data;
+ proposal->header().SerializeToString(&header_data);
+ data += header_data;
+
+ std::string hash = SignatureVerifier::CalculateHash(data);
+ proposal->set_hash(hash);
+
+ round_++;
+ return proposal;
+}
+
+int ProposalManager::CurrentRound() { return round_; }
+
+void ProposalManager::AddLocalBlock(std::unique_ptr<Proposal> proposal) {
+ std::unique_lock<std::mutex> lk(local_mutex_);
+ local_block_[proposal->hash()] = std::move(proposal);
+}
+
+const Proposal* ProposalManager::GetLocalBlock(const std::string& hash) {
+ std::unique_lock<std::mutex> lk(local_mutex_);
+ auto bit = local_block_.find(hash);
+ if (bit == local_block_.end()) {
+ LOG(ERROR) << " block not exist:" << hash.size();
+ return nullptr;
+ }
+ return bit->second.get();
+}
+
+std::unique_ptr<Proposal> ProposalManager::FetchLocalBlock(
+ const std::string& hash) {
+ std::unique_lock<std::mutex> lk(local_mutex_);
+ auto bit = local_block_.find(hash);
+ if (bit == local_block_.end()) {
+ // LOG(ERROR) << " block not exist:" << hash.size();
+ return nullptr;
+ }
+ auto tmp = std::move(bit->second);
+ local_block_.erase(bit);
+ return tmp;
+}
+
+void ProposalManager::AddBlock(std::unique_ptr<Proposal> proposal) {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ // LOG(ERROR) << "add block hash :" << proposal->hash().size()
+ // << " round:" << proposal->header().round()
+ // << " proposer:" << proposal->header().proposer_id();
+ block_[proposal->hash()] = std::move(proposal);
+}
+
+bool ProposalManager::CheckBlock(const std::string& hash) {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ // LOG(ERROR)<<"add block hash :"<<proposal->hash().size()<<"
+ // round:"<<proposal->header().round()<<"
+ // proposer:"<<proposal->header().proposer_id();
+ return block_.find(hash) != block_.end();
+}
+
+int ProposalManager::GetReferenceNum(const Proposal& req) {
+ int round = req.header().round();
+ int proposer = req.header().proposer_id();
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ return reference_[std::make_pair(round, proposer)];
+}
+
+std::unique_ptr<Proposal> ProposalManager::FetchRequest(int round, int sender) {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ auto it = cert_list_[round].find(sender);
+ if (it == cert_list_[round].end()) {
+ // LOG(ERROR)<<" cert from sender:"<<sender<<" round:"<<round<<" not exist";
+ return nullptr;
+ }
+ std::string hash = it->second->hash();
+ auto bit = block_.find(hash);
+ if (bit == block_.end()) {
+ LOG(ERROR) << " block from sender:" << sender << " round:" << round
+ << " not exist";
+ assert(1 == 0);
+ return nullptr;
+ }
+ auto tmp = std::move(bit->second);
+ // cert_list_[round].erase(sender);
+ // LOG(ERROR)<<" featch sender done, round:"<<round<<" sender:"<<sender;
+ if (sender == id_) {
+ FetchLocalBlock(hash);
+ }
+ return tmp;
+}
+
+const Proposal* ProposalManager::GetRequest(int round, int sender) {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ auto it = cert_list_[round].find(sender);
+ if (it == cert_list_[round].end()) {
+ // LOG(ERROR) << " cert from sender:" << sender << " round:" << round
+ // << " not exist";
+ return nullptr;
+ }
+ std::string hash = it->second->hash();
+ auto bit = block_.find(hash);
+ if (bit == block_.end()) {
+ LOG(ERROR) << " block from sender:" << sender << " round:" << round
+ << " not exist";
+ return nullptr;
+ }
+ return bit->second.get();
+}
+
+void ProposalManager::AddCert(std::unique_ptr<Certificate> cert) {
+ int proposer = cert->proposer();
+ int round = cert->round();
+ std::string hash = cert->hash();
+
+ // LOG(ERROR)<<"add cert sender:"<<proposer<<" round:"<<round;
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+
+ // LOG(ERROR)<<"strong cert size:"<<cert->strong_cert().cert_size();
+ for (auto& link : cert->strong_cert().cert()) {
+ int link_round = link.round();
+ int link_proposer = link.proposer();
+ // LOG(ERROR)<<"refer round:"<<link_round<<" proposer:"<<link_proposer;
+ reference_[std::make_pair(link_round, link_proposer)]++;
+ }
+
+ cert->mutable_strong_cert()->Clear();
+ cert->mutable_metadata()->Clear();
+
+ auto tmp = std::make_unique<Certificate>(*cert);
+ cert_list_[round][proposer] = std::move(cert);
+ latest_cert_from_sender_[proposer] = std::move(tmp);
+}
+
+bool ProposalManager::CheckCert(int round, int sender) {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ return cert_list_[round].find(sender) != cert_list_[round].end();
+}
+
+void ProposalManager::GetMetaData(Proposal* proposal) {
+ if (round_ == 0) {
+ return;
+ }
+ assert(cert_list_[round_ - 1].size() >= limit_count_);
+ assert(cert_list_[round_ - 1].find(id_) != cert_list_[round_ - 1].end());
+
+ // LOG(ERROR)<<"get metadata:"<<" proposal
+ // round:"<<proposal->header().round();
+ std::set<int> meta_ids;
+ for (const auto& preview_cert : cert_list_[round_ - 1]) {
+ *proposal->mutable_header()->mutable_strong_cert()->add_cert() =
+ *preview_cert.second;
+ meta_ids.insert(preview_cert.first);
+ // LOG(ERROR)<<"add strong round:"<<preview_cert.second->round()
+ //<<" id:"<<preview_cert.second->proposer()<<"
+ //first:"<<preview_cert.first<<" limit:"<<limit_count_<<" proposal
+ //round:"<<proposal->header().round();
+ if (meta_ids.size() == limit_count_) {
+ break;
+ }
+ }
+ // LOG(ERROR)<<"strong link:"<<proposal->header().strong_cert().cert_size()<<"
+ // round:"<<proposal->header().round();
+
+ for (const auto& meta : latest_cert_from_sender_) {
+ // LOG(ERROR)<<"check:"<<meta.first<<" proposal
+ // round:"<<proposal->header().round();
+ if (meta_ids.find(meta.first) != meta_ids.end()) {
+ continue;
+ }
+ if (meta.second->round() >= round_) {
+ for (int j = round_ - 1; j >= 0; --j) {
+ if (cert_list_[j].find(meta.first) != cert_list_[j].end()) {
+ // LOG(ERROR) << " add weak cert from his:" << j
+ // << " proposer:" << meta.first<< " cert
+ // round:"<<cert_list_[j][meta.first]->round()<< " proposal
+ // round:"<<proposal->header().round();
+ *proposal->mutable_header()->mutable_weak_cert()->add_cert() =
+ *cert_list_[j][meta.first];
+ break;
+ }
+ }
+ } else {
+ assert(meta.second->round() <= round_);
+ // LOG(ERROR)<<"add weak cert:"<<meta.second->round()<<"
+ // proposer:"<<meta.second->proposer()<<" proposal
+ // round:"<<proposal->header().round();
+ *proposal->mutable_header()->mutable_weak_cert()->add_cert() =
+ *meta.second;
+ }
+ }
+ // LOG(ERROR)<<"weak link:"<<proposal->header().weak_cert().cert_size()<<"
+ // round:"<<proposal->header().round();
+}
+
+bool ProposalManager::Ready() {
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ if (round_ == 0) {
+ return true;
+ }
+ if (cert_list_[round_ - 1].size() < limit_count_) {
+ return false;
+ }
+ if (cert_list_[round_ - 1].find(id_) == cert_list_[round_ - 1].end()) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace thunderbolt
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.h b/platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.h
new file mode 100644
index 000000000..344562c42
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "platform/consensus/ordering/thunderbolt/proto/proposal.pb.h"
+
+namespace resdb {
+namespace thunderbolt {
+
+class ProposalManager {
+ public:
+ ProposalManager(int32_t id, int limit_count);
+
+ std::unique_ptr<Proposal> GenerateProposal(
+ const std::vector<std::unique_ptr<Transaction>>& txns);
+
+ int CurrentRound();
+ void AddLocalBlock(std::unique_ptr<Proposal> proposal);
+ const Proposal* GetLocalBlock(const std::string& hash);
+ std::unique_ptr<Proposal> FetchLocalBlock(const std::string& hash);
+
+ void AddBlock(std::unique_ptr<Proposal> proposal);
+ void AddCert(std::unique_ptr<Certificate> cert);
+ bool Ready();
+
+ const Proposal* GetRequest(int round, int sender);
+ std::unique_ptr<Proposal> FetchRequest(int round, int sender);
+ int GetReferenceNum(const Proposal& req);
+
+ bool VerifyHash(const Proposal& proposal);
+
+ bool CheckCert(int round, int sender);
+ bool CheckBlock(const std::string& hash);
+
+ void SetCommittedRound(int r);
+
+ protected:
+ void GetMetaData(Proposal* proposal);
+
+ private:
+ int32_t id_;
+ int round_;
+ int limit_count_;
+ std::map<std::string, std::unique_ptr<Proposal>> block_, local_block_;
+
+ std::map<int64_t, std::map<int, std::unique_ptr<Certificate>>> cert_list_;
+ std::map<int, std::unique_ptr<Certificate>> latest_cert_from_sender_;
+
+ std::mutex txn_mutex_, local_mutex_;
+ std::map<std::pair<int, int>, int> reference_;
+
+ std::atomic<int> committed_round_ = 0;
+};
+
+} // namespace thunderbolt
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.cpp b/platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.cpp
new file mode 100644
index 000000000..64cf81034
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.cpp
@@ -0,0 +1,555 @@
+#include "platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.h"
+
+#include <glog/logging.h>
+
+#include "common/utils/utils.h"
+
+namespace resdb {
+namespace thunderbolt {
+
+Thunderbolt::Thunderbolt(int id, int f, int total_num, SignatureVerifier* verifier)
+ : ProtocolBase(id, f, total_num), verifier_(verifier) {
+ limit_count_ = 2 * f + 1;
+ batch_size_ = 5;
+ proposal_manager_ = std::make_unique<ProposalManager>(id, limit_count_);
+
+ execute_id_ = 1;
+ start_ = 0;
+ queue_size_ = 0;
+
+ send_thread_ = std::thread(&Thunderbolt::AsyncSend, this);
+ commit_thread_ = std::thread(&Thunderbolt::AsyncCommit, this);
+ execute_thread_ = std::thread(&Thunderbolt::AsyncExecute, this);
+ cert_thread_ = std::thread(&Thunderbolt::AsyncProcessCert, this);
+
+ global_stats_ = Stats::GetGlobalStats();
+
+ LOG(ERROR) << "id:" << id << " f:" << f << " total:" << total_num;
+}
+
+Thunderbolt::~Thunderbolt() {
+ if (send_thread_.joinable()) {
+ send_thread_.join();
+ }
+ if (commit_thread_.joinable()) {
+ commit_thread_.join();
+ }
+ if (cert_thread_.joinable()) {
+ cert_thread_.join();
+ }
+}
+
+int Thunderbolt::GetLeader(int64_t r) { return r / 2 % total_num_ + 1; }
+
+void Thunderbolt::AsyncSend() {
+ uint64_t last_time = 0;
+ while (!IsStop()) {
+ auto txn = txns_.Pop();
+ if (txn == nullptr) {
+ if (start_) {
+ // LOG(ERROR)<<"not enough txn";
+ // break;
+ }
+ continue;
+ }
+
+ queue_size_--;
+ // LOG(ERROR)<<"txn before waiting time:"<<GetCurrentTime() -
+ // txn->create_time()<<" queue size:"<<queue_size_;
+ while (!IsStop()) {
+ int current_round = proposal_manager_->CurrentRound();
+ std::unique_lock<std::mutex> lk(mutex_);
+ vote_cv_.wait_for(lk, std::chrono::microseconds(10000),
+ [&] { return proposal_manager_->Ready(); });
+
+ if (proposal_manager_->Ready()) {
+ start_ = 1;
+ break;
+ }
+ }
+
+ // LOG(ERROR)<<"txn waiting time:"<<GetCurrentTime() - txn->create_time();
+ txn->set_queuing_time(GetCurrentTime() - txn->create_time());
+ global_stats_->AddQueuingLatency(GetCurrentTime() - txn->create_time());
+ global_stats_->AddRoundLatency(GetCurrentTime() - last_time);
+ last_time = GetCurrentTime();
+
+ std::vector<std::unique_ptr<Transaction>> txns;
+ txns.push_back(std::move(txn));
+ for (int i = 1; i < batch_size_; ++i) {
+ auto txn = txns_.Pop(10);
+ if (txn == nullptr) {
+ continue;
+ break;
+ }
+ txn->set_queuing_time(GetCurrentTime() - txn->create_time());
+ queue_size_--;
+ global_stats_->AddQueuingLatency(GetCurrentTime() - txn->create_time());
+ txns.push_back(std::move(txn));
+ }
+
+ global_stats_->ConsumeTransactions(queue_size_);
+
+ auto proposal = proposal_manager_->GenerateProposal(txns);
+ Broadcast(MessageType::NewBlock, *proposal);
+
+ std::string block_data;
+ proposal->SerializeToString(&block_data);
+ global_stats_->AddBlockSize(block_data.size());
+
+ proposal_manager_->AddLocalBlock(std::move(proposal));
+
+ int round = proposal_manager_->CurrentRound() - 1;
+ // LOG(ERROR) << "bc txn:" << txns.size() << " round:" << round;
+ if (round > 1) {
+ if (round % 2 == 0) {
+ CommitRound(round - 2);
+ }
+ }
+ }
+}
+
+void Thunderbolt::AsyncCommit() {
+ int previous_round = -2;
+ while (!IsStop()) {
+ std::unique_ptr<int> round_or = commit_queue_.Pop();
+ if (round_or == nullptr) {
+ continue;
+ }
+
+ int round = *round_or;
+ // int64_t start_time = GetCurrentTime();
+ // LOG(ERROR) << "commit round:" << round;
+
+ int new_round = previous_round;
+ for (int r = previous_round + 2; r <= round; r += 2) {
+ int leader = GetLeader(r);
+ const Proposal* req = nullptr;
+ while (!IsStop()) {
+ req = proposal_manager_->GetRequest(r, leader);
+ // req:"<<(req==nullptr);
+ if (req == nullptr) {
+ // LOG(ERROR)<<" get leader:"<<leader<<" round:"<<r<<" not exit";
+ // usleep(1000);
+ std::unique_lock<std::mutex> lk(mutex_);
+ vote_cv_.wait_for(lk, std::chrono::microseconds(100),
+ [&] { return true; });
+
+ continue;
+ }
+ break;
+ }
+ // LOG(ERROR)<<" get leader:"<<leader<<" round:"<<r<<"
+ // delay:"<<(GetCurrentTime() - req->header().create_time());
+ int reference_num = proposal_manager_->GetReferenceNum(*req);
+ // LOG(ERROR)<<" get leader:"<<leader<<" round:"<<r<<"
+ // ref:"<<reference_num;
+ if (reference_num < limit_count_) {
+ continue;
+ } else {
+ // LOG(ERROR) << "go to commit r:" << r << " previous:" <<
+ // previous_round;
+ for (int j = new_round + 2; j <= r; j += 2) {
+ int pre_leader = GetLeader(j);
+
+ auto req = proposal_manager_->GetRequest(j, pre_leader);
+ if (req == nullptr) {
+ continue;
+ }
+ int reference_num = proposal_manager_->GetReferenceNum(*req);
+ if (reference_num < limit_count_) {
+ continue;
+ }
+
+ CommitProposal(j, pre_leader);
+ }
+ }
+ new_round = r;
+ }
+ // int64_t end_time = GetCurrentTime();
+ // global_stats_->AddCommitRuntime(end_time-commit_time);
+ previous_round = new_round;
+ }
+}
+
+void Thunderbolt::AsyncExecute() {
+ int64_t last_commit_time = 0;
+ int last_round = 0;
+ while (!IsStop()) {
+ std::unique_ptr<Proposal> proposal = execute_queue_.Pop();
+ if (proposal == nullptr) {
+ continue;
+ }
+
+ int commit_round = proposal->header().round();
+ int64_t commit_time = GetCurrentTime();
+ int64_t waiting_time = commit_time - proposal->queuing_time();
+ global_stats_->AddCommitQueuingLatency(waiting_time);
+ // global_stats_->AddCommitInterval(commit_time - last_commit_time);
+ // last_commit_time = commit_time;
+ std::map<int, std::vector<std::unique_ptr<Proposal>>> ps;
+ std::queue<std::unique_ptr<Proposal>> q;
+ q.push(std::move(proposal));
+
+ // LOG(ERROR)<<" commit round:"<<commit_round;
+ // proposal_manager_->SetCommittedRound(commit_round);
+
+ // global_stats_->AddCommitRoundLatency(commit_round - last_round);
+ // last_round = commit_round;
+
+ // int64_t start_time = GetCurrentTime();
+ while (!q.empty()) {
+ std::unique_ptr<Proposal> p = std::move(q.front());
+ q.pop();
+
+ for (auto& link : p->header().strong_cert().cert()) {
+ int link_round = link.round();
+ int link_proposer = link.proposer();
+ auto next_p =
+ proposal_manager_->FetchRequest(link_round, link_proposer);
+ if (next_p == nullptr) {
+ continue;
+ }
+ q.push(std::move(next_p));
+ }
+
+ for (auto& link : p->header().weak_cert().cert()) {
+ int link_round = link.round();
+ int link_proposer = link.proposer();
+ auto next_p =
+ proposal_manager_->FetchRequest(link_round, link_proposer);
+ if (next_p == nullptr) {
+ // LOG(ERROR)<<"no data round:"<<link_round<<" link
+ // proposer:"<<link_proposer;
+ continue;
+ }
+ q.push(std::move(next_p));
+ }
+ ps[p->header().round()].push_back(std::move(p));
+ }
+
+ int num = 0;
+ int pro = 0;
+ for (auto& it : ps) {
+ for (auto& p : it.second) {
+ // LOG(ERROR) << "=============== commit proposal round :"
+ // << p->header().round()
+ // << " header round:"<<p->header().round()
+ // << " commit round:"<<commit_round
+ // << " proposer:" << p->header().proposer_id()
+ // << " transaction size:" << p->transactions_size()
+ // << " commit time:"
+ // << (GetCurrentTime() - p->header().create_time())
+ // << " create time:" << p->header().create_time()
+ // <<" execute id:"<<execute_id_
+ // <<" round delay:"<<(commit_round - p->header().round());
+
+ global_stats_->AddCommitLatency(
+ commit_time - p->header().create_time() - waiting_time);
+ global_stats_->AddCommitRoundLatency(commit_round -
+ p->header().round());
+ for (auto& tx : *p->mutable_transactions()) {
+ tx.set_id(execute_id_++);
+ num++;
+ // LOG(ERROR)<<" commit txn create time:"<<tx.create_time();
+ Commit(tx);
+ }
+ pro++;
+ }
+ }
+ int64_t end_time = GetCurrentTime();
+ global_stats_->AddCommitRuntime(end_time - commit_time);
+ global_stats_->AddCommitTxn(num);
+ global_stats_->AddCommitBlock(pro);
+ }
+}
+
+void Thunderbolt::CommitProposal(int round, int proposer) {
+ // LOG(ERROR) << "commit round:" << round << " proposer:" << proposer;
+
+ // int64_t last_commit_time = 0;
+ int64_t commit_time = GetCurrentTime();
+ global_stats_->AddCommitInterval(commit_time - last_commit_time_);
+ last_commit_time_ = commit_time;
+
+ std::unique_ptr<Proposal> p =
+ proposal_manager_->FetchRequest(round, proposer);
+ if (p == nullptr) {
+ LOG(ERROR) << "commit round:" << round << " proposer:" << proposer
+ << " not exist";
+ assert(1 == 0);
+ return;
+ }
+ assert(p != nullptr);
+ p->set_queuing_time(GetCurrentTime());
+ execute_queue_.Push(std::move(p));
+}
+
+void Thunderbolt::CommitRound(int round) {
+ // LOG(ERROR)<<" commit round:"<<round;
+ commit_queue_.Push(std::make_unique<int>(round));
+}
+
+bool Thunderbolt::ReceiveTransaction(std::unique_ptr<Transaction> txn) {
+ // LOG(ERROR)<<"recv txn";
+ txn->set_create_time(GetCurrentTime());
+ txns_.Push(std::move(txn));
+ queue_size_++;
+ if (start_ == 0) {
+ std::unique_lock<std::mutex> lk(mutex_);
+ vote_cv_.notify_all();
+ }
+ return true;
+}
+
+bool Thunderbolt::ReceiveBlock(std::unique_ptr<Proposal> proposal) {
+ // LOG(ERROR) << "recv block from " << proposal->header().proposer_id()
+ // << " round:" << proposal->header().round();
+
+ std::unique_lock<std::mutex> lk(check_block_mutex_);
+ {
+ proposal->set_queuing_time(GetCurrentTime());
+ // std::unique_lock<std::mutex> lk(check_block_mutex_);
+ if (!CheckBlock(*proposal)) {
+ std::unique_lock<std::mutex> lk(future_block_mutex_);
+ // LOG(ERROR)<<"add future block:"<<proposal->header().round()<<"
+ // sender:"<<proposal->header().proposer_id();
+ future_block_[proposal->header().round()][proposal->hash()] =
+ std::move(proposal);
+ return false;
+ }
+ }
+ return SendBlockAck(std::move(proposal));
+}
+
+void Thunderbolt::ReceiveBlockACK(std::unique_ptr<Metadata> metadata) {
+ std::string hash = metadata->hash();
+ int round = metadata->round();
+ int sender = metadata->sender();
+ std::unique_lock<std::mutex> lk(txn_mutex_);
+ received_num_[hash][sender] = std::move(metadata);
+ // LOG(ERROR) << "recv block ack from:" << sender << " num:" <<
+ // received_num_[hash].size()<<" round:"<<round;
+ if (received_num_[hash].size() == limit_count_) {
+ Certificate cert;
+ for (auto& it : received_num_[hash]) {
+ *cert.add_metadata() = *it.second;
+ }
+ cert.set_hash(hash);
+ cert.set_round(round);
+ cert.set_proposer(id_);
+ const Proposal* p = proposal_manager_->GetLocalBlock(hash);
+ assert(p != nullptr);
+ assert(p->header().proposer_id() == id_);
+ assert(p->header().round() == round);
+ global_stats_->AddExecutePrepareDelay(GetCurrentTime() -
+ p->header().create_time());
+ // global_stats_->AddCommitLatency(GetCurrentTime() -
+ // p->header().create_time());
+ *cert.mutable_strong_cert() = p->header().strong_cert();
+ // LOG(ERROR)<<"send cert, round:"<<p->header().round();
+ Broadcast(MessageType::Cert, cert);
+ }
+}
+
+bool Thunderbolt::VerifyCert(const Certificate& cert) {
+ std::map<std::string, int> hash_num;
+ bool vote_num = false;
+ for (auto& metadata : cert.metadata()) {
+ bool valid = verifier_->VerifyMessage(metadata.hash(), metadata.sign());
+ if (!valid) {
+ return false;
+ }
+ hash_num[metadata.hash()]++;
+ if (hash_num[metadata.hash()] >= 2 * f_ + 1) {
+ vote_num = true;
+ }
+ }
+ return vote_num;
+}
+
+bool Thunderbolt::CheckBlock(const Proposal& p) {
+ for (auto& link : p.header().strong_cert().cert()) {
+ int link_round = link.round();
+ int link_proposer = link.proposer();
+ if (!proposal_manager_->CheckCert(link_round, link_proposer)) {
+ // LOG(ERROR)<<" check block round:"<<p.header().round()<<"
+ // proposer:"<<p.header().proposer_id()<<" strong link:"<<link_proposer<<"
+ // link round:"<<link_round<<" not exist";
+ return false;
+ }
+ }
+
+ for (auto& link : p.header().weak_cert().cert()) {
+ int link_round = link.round();
+ int link_proposer = link.proposer();
+ if (!proposal_manager_->CheckCert(link_round, link_proposer)) {
+ // LOG(ERROR)<<" check block round:"<<p.header().round()<<"
+ // proposer:"<<p.header().proposer_id()<<" weak link:"<<link_proposer<<"
+ // link round:"<<link_round<<" not exist";
+ return false;
+ }
+ }
+ // LOG(ERROR)<<" check cert round:"<<p.header().round()<<"
+ // proposer:"<<p.header().proposer_id()<<" strong link
+ // size:"<<p.header().strong_cert().cert_size()<<" weak link
+ // size:"<<p.header().weak_cert().cert_size();
+ return true;
+}
+
+bool Thunderbolt::CheckCert(const Certificate& cert) {
+ if (!proposal_manager_->CheckBlock(cert.hash())) {
+ // future_cert_[cert->round()][cert->hash()] = std::move(cert);
+ return false;
+ }
+ return true;
+}
+
+bool Thunderbolt::SendBlockAck(std::unique_ptr<Proposal> proposal) {
+ Metadata metadata;
+ metadata.set_sender(id_);
+ metadata.set_hash(proposal->hash());
+ metadata.set_round(proposal->header().round());
+ metadata.set_proposer(proposal->header().proposer_id());
+
+ std::string data_str = proposal->hash();
+ auto hash_signature_or = verifier_->SignMessage(data_str);
+ if (!hash_signature_or.ok()) {
+ LOG(ERROR) << "Sign message fail";
+ return false;
+ }
+ *metadata.mutable_sign() = *hash_signature_or;
+ metadata.set_sender(id_);
+
+ {
+ // std::unique_lock<std::mutex> lk(txn_mutex_);
+ // LOG(ERROR) << "recv block from " << proposal->header().proposer_id()
+ // << " round:" << proposal->header().round();
+ int round = proposal->header().round();
+ std::string hash = proposal->hash();
+ int proposer = proposal->header().proposer_id();
+ global_stats_->AddCommitWaitingLatency(GetCurrentTime() -
+ proposal->queuing_time());
+ proposal->set_queuing_time(0);
+ {
+ // std::unique_lock<std::mutex> lk(check_block_mutex_);
+ proposal_manager_->AddBlock(std::move(proposal));
+ CheckFutureCert(round, hash, proposer);
+ }
+ }
+ SendMessage(MessageType::BlockACK, metadata, metadata.proposer());
+ return true;
+}
+
+void Thunderbolt::CheckFutureBlock(int round) {
+ // LOG(ERROR)<<" check block round from cert:"<<round;
+ std::map<std::string, std::unique_ptr<Proposal>> hashs;
+ {
+ std::unique_lock<std::mutex> lk(future_block_mutex_);
+ if (future_block_.find(round) == future_block_.end()) {
+ return;
+ }
+ for (auto& it : future_block_[round]) {
+ if (CheckBlock(*it.second)) {
+ // LOG(ERROR)<<" add new block round:"<<it.second->header().round();
+ hashs[it.first] = std::move(it.second);
+ }
+ }
+
+ // LOG(ERROR)<<" check round:"<<round<<" hash size:"<<hashs.size();
+ for (auto& it : hashs) {
+ future_block_[round].erase(future_block_[round].find(it.first));
+ }
+
+ if (future_block_[round].size() == 0) {
+ future_block_.erase(future_block_.find(round));
+ }
+ }
+
+ for (auto& it : hashs) {
+ // LOG(ERROR)<<"send future block round:"<<it.second->header().round()<<"
+ // proposer:"<<it.second->header().proposer_id();
+ int block_round = it.second->header().round();
+ // std::unique_lock<std::mutex> lk(check_block_mutex_);
+ {
+ std::unique_lock<std::mutex> lk(future_cert_mutex_);
+ if (future_cert_[block_round].find(it.first) !=
+ future_cert_[block_round].end()) {
+ std::unique_ptr<Certificate> cert =
+ std::move(future_cert_[block_round][it.first]);
+ // LOG(ERROR)<<" add new cert:"<<block_round<<"
+ // from:"<<cert->proposer();
+ cert_queue_.Push(std::move(cert));
+ future_cert_[block_round].erase(
+ future_cert_[block_round].find(it.first));
+ if (future_cert_[block_round].size() == 0) {
+ future_cert_.erase(future_cert_.find(block_round));
+ }
+ }
+ }
+ SendBlockAck(std::move(it.second));
+ }
+}
+
+void Thunderbolt::CheckFutureCert(int round, const std::string& hash, int proposer) {
+ std::unique_lock<std::mutex> lk(future_cert_mutex_);
+ auto it = future_cert_[round].find(hash);
+ if (it != future_cert_[round].end()) {
+ // LOG(ERROR)<<" add back future cert, round:"<<round<<"
+ // proposer:"<<proposer;
+ cert_queue_.Push(std::move(it->second));
+ future_cert_[round].erase(it);
+ if (future_cert_[round].empty()) {
+ future_cert_.erase(future_cert_.find(round));
+ }
+ }
+}
+
+void Thunderbolt::AsyncProcessCert() {
+ while (!IsStop()) {
+ std::unique_ptr<Certificate> cert = cert_queue_.Pop();
+ if (cert == nullptr) {
+ continue;
+ }
+
+ int round = cert->round();
+ int cert_sender = cert->proposer();
+
+ // LOG(ERROR)<<" add cert, round:"<<round<<" from:"<<cert_sender;
+ std::unique_lock<std::mutex> clk(check_block_mutex_);
+ proposal_manager_->AddCert(std::move(cert));
+ {
+ std::unique_lock<std::mutex> lk(mutex_);
+ vote_cv_.notify_all();
+ }
+
+ CheckFutureBlock(round + 1);
+ }
+}
+
+void Thunderbolt::ReceiveBlockCert(std::unique_ptr<Certificate> cert) {
+ int64_t start_time = GetCurrentTime();
+ if (!VerifyCert(*cert)) {
+ assert(1 == 0);
+ return;
+ }
+
+ int64_t end_time = GetCurrentTime();
+ global_stats_->AddVerifyLatency(end_time - start_time);
+
+ {
+ std::unique_lock<std::mutex> lk(check_block_mutex_);
+ if (!CheckCert(*cert)) {
+ // LOG(ERROR)<<" add future cert round:"<<cert->round()<<"
+ // proposer:"<<cert->proposer();
+ std::unique_lock<std::mutex> lk(future_cert_mutex_);
+ future_cert_[cert->round()][cert->hash()] = std::move(cert);
+ return;
+ }
+ }
+
+ cert_queue_.Push(std::move(cert));
+}
+
+} // namespace thunderbolt
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.h b/platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.h
new file mode 100644
index 000000000..63fd2009f
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/thunderbolt.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <deque>
+#include <map>
+#include <queue>
+#include <thread>
+
+#include "common/crypto/signature_verifier.h"
+#include "platform/common/queue/lock_free_queue.h"
+#include "platform/consensus/ordering/common/algorithm/protocol_base.h"
+#include "platform/consensus/ordering/thunderbolt/algorithm/proposal_manager.h"
+#include "platform/consensus/ordering/thunderbolt/proto/proposal.pb.h"
+#include "platform/statistic/stats.h"
+
+namespace resdb {
+namespace thunderbolt {
+
+class Thunderbolt : public common::ProtocolBase {
+ public:
+ Thunderbolt(int id, int f, int total_num, SignatureVerifier* verifier);
+ ~Thunderbolt();
+
+ bool ReceiveTransaction(std::unique_ptr<Transaction> txn);
+ bool ReceiveBlock(std::unique_ptr<Proposal> proposal);
+ void ReceiveBlockACK(std::unique_ptr<Metadata> metadata);
+ void ReceiveBlockCert(std::unique_ptr<Certificate> cert);
+
+ private:
+ void CommitProposal(int round, int proposer);
+ void CommitRound(int round);
+ void AsyncCommit();
+ void AsyncSend();
+ void AsyncExecute();
+
+ bool VerifyCert(const Certificate& cert);
+
+ bool CheckBlock(const Proposal& p);
+ void CheckFutureBlock(int round);
+ void CheckFutureCert(const Proposal& proposal);
+ void CheckFutureCert(int round, const std::string& hash, int proposer);
+ bool CheckCert(const Certificate& cert);
+ bool SendBlockAck(std::unique_ptr<Proposal> proposal);
+
+ void AsyncProcessCert();
+
+ int GetLeader(int64_t r);
+
+ private:
+ LockFreeQueue<Proposal> execute_queue_, pending_block_;
+ LockFreeQueue<int> commit_queue_;
+ LockFreeQueue<Transaction> txns_;
+
+ std::unique_ptr<ProposalManager> proposal_manager_;
+ SignatureVerifier* verifier_;
+
+ std::thread send_thread_;
+ std::thread commit_thread_, execute_thread_;
+ std::mutex txn_mutex_, mutex_;
+ int limit_count_;
+ std::map<std::string, std::map<int, std::unique_ptr<Metadata>>> received_num_;
+ std::condition_variable vote_cv_;
+ int start_ = 0;
+ int batch_size_ = 0;
+ int execute_id_ = 1;
+ std::atomic<int> queue_size_;
+
+ Stats* global_stats_;
+
+ std::thread cert_thread_;
+ LockFreeQueue<Certificate> cert_queue_;
+ std::mutex future_block_mutex_, future_cert_mutex_, check_block_mutex_;
+ std::map<int, std::map<std::string, std::unique_ptr<Proposal>>> future_block_;
+ std::map<int, std::map<std::string, std::unique_ptr<Certificate>>>
+ future_cert_;
+ int64_t last_commit_time_ = 0;
+};
+
+} // namespace thunderbolt
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.cpp b/platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.cpp
new file mode 100644
index 000000000..3d3c5e41b
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+
+TransactionStatue TransactionCollector::GetStatus() const { return status_; }
+
+int TransactionCollector::AddRequest(
+ std::unique_ptr<google::protobuf::Message> request, int sender_id, int type,
+ std::function<void(const google::protobuf::Message&, int received_count,
+ std::atomic<TransactionStatue>* status)>
+ call_back) {
+ if (status_.load() == EXECUTED) {
+ return -2;
+ }
+
+ if (request) {
+ request_ = std::move(request);
+ call_back(*request, 1, &status_);
+ } else {
+ senders_[type].insert(sender_id);
+ if (request_) {
+ call_back(*request_, senders_[type].size(), &status_);
+ }
+ }
+ return 0;
+}
+
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.h b/platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.h
new file mode 100644
index 000000000..b38a41f62
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/algorithm/transaction_collector.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <google/protobuf/message.h>
+
+#include "platform/statistic/stats.h"
+
+namespace resdb {
+
+enum TransactionStatue {
+ None = 0,
+ Prepare = -999,
+ READY_PREPARE = 1,
+ READY_COMMIT = 2,
+ READY_EXECUTE = 3,
+ EXECUTED = 4,
+};
+
+class TransactionCollector {
+ public:
+ TransactionCollector(int64_t seq)
+ : seq_(seq), status_(TransactionStatue::None) {}
+
+ ~TransactionCollector() = default;
+
+ int AddRequest(
+ std::unique_ptr<google::protobuf::Message> request, int sender_id,
+ int type,
+ std::function<void(const google::protobuf::Message&, int received_count,
+ std::atomic<TransactionStatue>* status)>
+ call_back);
+
+ TransactionStatue GetStatus() const;
+ int64_t GetSeq() { return seq_; }
+
+ std::unique_ptr<google::protobuf::Message> GetData() {
+ return std::move(request_);
+ }
+
+ private:
+ int64_t seq_;
+ std::unique_ptr<google::protobuf::Message> request_;
+ std::atomic<TransactionStatue> status_ = TransactionStatue::None;
+ std::set<int> senders_[10];
+};
+
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/common/BUILD b/platform/consensus/ordering/thunderbolt/executor/common/BUILD
new file mode 100644
index 000000000..769670a06
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/common/BUILD
@@ -0,0 +1,18 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "utils",
+ hdrs = ["utils.h"],
+ deps = [
+ "//third_party:evm_lib",
+ ],
+)
+
+cc_library(
+ name = "contract_execute_info",
+ hdrs = ["contract_execute_info.h"],
+ deps = [
+ ":utils",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
diff --git a/platform/consensus/ordering/thunderbolt/executor/common/contract_execute_info.h b/platform/consensus/ordering/thunderbolt/executor/common/contract_execute_info.h
new file mode 100644
index 000000000..4db40bf3d
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/common/contract_execute_info.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "absl/status/statusor.h"
+#include "eEVM/address.h"
+#include "eEVM/opcode.h"
+#include "service/contract/executor/common/utils.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+struct ContractExecuteInfo {
+ eevm::Address caller_address;
+ eevm::Address contract_address;
+ std::string func_addr;
+ Params func_params;
+ int64_t commit_id;
+ uint64_t user_id;
+ bool is_only;
+ ContractExecuteInfo() {}
+ ContractExecuteInfo(eevm::Address caller_address,
+ eevm::Address contract_address, std::string func_addr,
+ Params func_params, int64_t commit_id)
+ : caller_address(caller_address),
+ contract_address(contract_address),
+ func_addr(func_addr),
+ func_params(func_params),
+ commit_id(commit_id),
+ is_only(false) {}
+};
+
+struct ExecuteResp {
+ int ret;
+ absl::Status state;
+ int64_t commit_id;
+ Address contract_address;
+ // ConcurrencyController :: ModifyMap rws;
+ std::string result;
+ int retry_time = 0;
+ uint64_t user_id = 0;
+ double runtime = 0;
+ double delay = 0;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/common/utils.h b/platform/consensus/ordering/thunderbolt/executor/common/utils.h
new file mode 100644
index 000000000..2d243d66f
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/common/utils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "eEVM/address.h"
+
+namespace resdb {
+namespace contract {
+
+typedef eevm::Address Address;
+
+}
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/common/x_verifier.cpp b/platform/consensus/ordering/thunderbolt/executor/common/x_verifier.cpp
new file mode 100644
index 000000000..fbee05b41
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/common/x_verifier.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/x_verifier.h"
+
+#include <queue>
+
+#include "common/utils/utils.h"
+#include "eEVM/processor.h"
+#include "glog/logging.h"
+#include "service/contract/executor/manager/local_state.h"
+
+namespace resdb {
+namespace contract {
+
+XVerifier::XVerifier(DataStorage* storage, GlobalState* global_state,
+ int worker_num)
+ : storage_(storage), gs_(global_state), worker_num_(worker_num) {
+ controller_ = std::make_unique<VController>(storage);
+ is_stop_ = false;
+
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_.push_back(std::thread([&]() {
+ while (!is_stop_) {
+ auto request = request_queue_.Pop();
+ if (request == nullptr) {
+ continue;
+ }
+
+ LocalState local_state(controller_.get());
+ local_state.Set(
+ gs_->GetAccount(
+ request->GetContractExecuteInfo()->contract_address),
+ request->GetContractExecuteInfo()->commit_id);
+
+ std::unique_ptr<ExecuteResp> resp = std::make_unique<ExecuteResp>();
+ auto ret = ExecContract(
+ request->GetContractExecuteInfo()->caller_address,
+ request->GetContractExecuteInfo()->contract_address,
+ request->GetContractExecuteInfo()->func_addr,
+ request->GetContractExecuteInfo()->func_params, &local_state);
+ resp->state = ret.status();
+ resp->contract_address =
+ request->GetContractExecuteInfo()->contract_address;
+ resp->commit_id = request->GetContractExecuteInfo()->commit_id;
+ resp->user_id = request->GetContractExecuteInfo()->user_id;
+ if (ret.ok()) {
+ resp->ret = 0;
+ resp->result = *ret;
+ if (request->IsRedo()) {
+ resp->retry_time++;
+ }
+ local_state.Flesh(request->GetContractExecuteInfo()->contract_address,
+ request->GetContractExecuteInfo()->commit_id);
+ } else {
+ resp->ret = -1;
+ }
+ resp_queue_.Push(std::move(resp));
+ }
+ }));
+ }
+}
+
+XVerifier::~XVerifier() {
+ is_stop_ = true;
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_[i].join();
+ }
+}
+
+bool XVerifier::VerifyContract(
+ const std::vector<ContractExecuteInfo>& request_list,
+ const std::vector<ConcurrencyController ::ModifyMap>& rws_list) {
+ std::vector<int> d;
+ std::map<int, std::vector<int> > g;
+ std::map<Address, int> id;
+
+ for (int i = 0; i < rws_list.size(); ++i) {
+ d.push_back(0);
+ for (auto it : rws_list[i]) {
+ const Address& address = it.first;
+ // LOG(ERROR)<<"i ="<<i<<" address:"<<address;
+ if (id.find(address) == id.end() || id[address] == i) {
+ id[address] = i;
+ continue;
+ }
+ g[id[address]].push_back(i);
+ // LOG(ERROR)<<"add edge:"<<id[address]<<" to "<<i;
+ id[address] = i;
+ d[i]++;
+ }
+ }
+
+ std::queue<int> q;
+ for (int i = 0; i < request_list.size(); ++i) {
+ if (d[i] == 0) {
+ auto context = std::make_unique<ExecutionContext>(request_list[i]);
+ context->GetContractExecuteInfo()->commit_id = i;
+ request_queue_.Push(std::move(context));
+ // LOG(ERROR)<<"add:"<<i;
+ }
+ }
+
+ int process_num = request_list.size();
+ while (process_num > 0) {
+ auto resp = resp_queue_.Pop();
+ if (resp == nullptr) {
+ continue;
+ }
+ process_num--;
+ int resp_commit_id = resp->commit_id;
+ bool ret = controller_->Commit(resp_commit_id);
+ if (!ret) {
+ return false;
+ }
+ // LOG(ERROR)<<"verify:"<<resp_commit_id;
+ auto* rws = controller_->GetChangeList(resp_commit_id);
+ if (!RWSEqual(*rws, rws_list[resp_commit_id])) {
+ LOG(ERROR) << "rws not equal";
+ return false;
+ }
+ for (int n_id : g[resp_commit_id]) {
+ // LOG(ERROR)<<"next id:"<<n_id;
+ d[n_id]--;
+ if (d[n_id] == 0) {
+ auto context = std::make_unique<ExecutionContext>(request_list[n_id]);
+ context->GetContractExecuteInfo()->commit_id = n_id;
+ request_queue_.Push(std::move(context));
+ // LOG(ERROR)<<"add next:"<<n_id;
+ }
+ }
+ }
+ // LOG(ERROR)<<"verified";
+ return true;
+}
+
+bool XVerifier::RWSEqual(const ConcurrencyController ::ModifyMap& a,
+ const ConcurrencyController ::ModifyMap& b) {
+ // LOG(ERROR)<<"size:"<<a.size()<<" "<<b.size();
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (auto it1 = a.begin(), it2 = b.begin(); it1 != a.end() && it2 != b.end();
+ it1++, it2++) {
+ if (it1->first != it2->first) {
+ LOG(ERROR) << "address not equal:" << it1->first << " " << it2->first;
+ return false;
+ }
+ if (it1->second.size() != it2->second.size()) {
+ LOG(ERROR) << "item size not equal:" << it1->second.size() << " "
+ << it2->second.size();
+ return false;
+ }
+ for (int i = 0; i < it1->second.size(); i++) {
+ if (it1->second[i] != it2->second[i]) {
+ LOG(ERROR) << "data not equal";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/common/x_verifier.h b/platform/consensus/ordering/thunderbolt/executor/common/x_verifier.h
new file mode 100644
index 000000000..7413d2893
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/common/x_verifier.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <future>
+#include <shared_mutex>
+
+#include "absl/status/statusor.h"
+#include "eEVM/opcode.h"
+#include "platform/common/queue/lock_free_queue.h"
+#include "service/contract/executor/manager/committer_context.h"
+#include "service/contract/executor/manager/contract_committer.h"
+#include "service/contract/executor/manager/contract_verifier.h"
+#include "service/contract/executor/manager/global_state.h"
+#include "service/contract/executor/manager/utils.h"
+#include "service/contract/executor/manager/v_controller.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+class XVerifier : public ContractVerifier {
+ public:
+ XVerifier(DataStorage* storage, GlobalState* global_state,
+ int worker_num = 2);
+
+ ~XVerifier();
+
+ bool VerifyContract(
+ const std::vector<ContractExecuteInfo>& request_list,
+ const std::vector<ConcurrencyController ::ModifyMap>& rws_list);
+
+ bool RWSEqual(const ConcurrencyController ::ModifyMap& a,
+ const ConcurrencyController ::ModifyMap& b);
+
+ private:
+ DataStorage* storage_;
+ GlobalState* gs_;
+ std::vector<std::thread> workers_;
+ std::unique_ptr<VController> controller_;
+ std::atomic<bool> is_stop_;
+
+ LockFreeQueue<ExecutionContext> request_queue_;
+ LockFreeQueue<ExecuteResp> resp_queue_;
+ const int worker_num_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/eo_service/BUILD b/platform/consensus/ordering/thunderbolt/executor/eo_service/BUILD
new file mode 100644
index 000000000..46776a78a
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/eo_service/BUILD
@@ -0,0 +1,26 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "contract_transaction_manager",
+ srcs = ["contract_transaction_manager.cpp"],
+ hdrs = ["contract_transaction_manager.h"],
+ deps = [
+ "//platform/config:resdb_config_utils",
+ "//service/contract/executor/manager:address_manager",
+ "//service/contract/executor/manager:contract_manager",
+ "//service/contract/proto:rpc_cc_proto",
+ "//service/utils:server_factory",
+ ],
+)
+
+cc_test(
+ name = "contract_transaction_manager_test",
+ srcs = ["contract_transaction_manager_test.cpp"],
+ data = [
+ "//service/contract/executor/service/test_data:contract.json",
+ ],
+ deps = [
+ ":contract_transaction_manager",
+ "//common/test:test_main",
+ ],
+)
diff --git a/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager.cpp b/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager.cpp
new file mode 100644
index 000000000..163c369fa
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/service/contract_transaction_manager.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+ContractTransactionManager::ContractTransactionManager(void)
+ : contract_manager_(
+ std::make_unique<ContractManager>(std::make_unique<DataStorage>())),
+ address_manager_(std::make_unique<AddressManager>()) {}
+
+std::unique_ptr<std::string> ContractTransactionManager::ExecuteData(
+ const std::string& client_request) {
+ Request request;
+ Response response;
+
+ if (!request.ParseFromString(client_request)) {
+ LOG(ERROR) << "parse data fail";
+ return nullptr;
+ }
+
+ int ret = 0;
+ if (request.cmd() == Request::CREATE_ACCOUNT) {
+ LOG(ERROR) << " create account";
+ absl::StatusOr<Account> account_or = CreateAccount();
+ if (account_or.ok()) {
+ response.mutable_account()->Swap(&(*account_or));
+ } else {
+ ret = -1;
+ }
+ } else if (request.cmd() == Request::DEPLOY) {
+ LOG(ERROR) << " deploy";
+ absl::StatusOr<Contract> contract_or = Deploy(request);
+ if (contract_or.ok()) {
+ response.mutable_contract()->Swap(&(*contract_or));
+ } else {
+ ret = -1;
+ }
+ } else if (request.cmd() == Request::EXECUTE) {
+ auto res_or = Execute(request);
+ if (res_or.ok()) {
+ response.set_res(*res_or);
+ } else {
+ ret = -1;
+ }
+ }
+
+ response.set_ret(ret);
+
+ std::unique_ptr<std::string> resp_str = std::make_unique<std::string>();
+ if (!response.SerializeToString(resp_str.get())) {
+ return nullptr;
+ }
+
+ return resp_str;
+}
+
+absl::StatusOr<Account> ContractTransactionManager::CreateAccount() {
+ std::string address =
+ AddressManager::AddressToHex(address_manager_->CreateRandomAddress());
+ Account account;
+ account.set_address(address);
+ return account;
+}
+
+absl::StatusOr<Contract> ContractTransactionManager::Deploy(
+ const Request& request) {
+ Address caller_address =
+ AddressManager::HexToAddress(request.caller_address());
+ if (!address_manager_->Exist(caller_address)) {
+ LOG(ERROR) << "caller doesn't have an account";
+ return absl::InvalidArgumentError("Account not exist.");
+ }
+
+ Address contract_address =
+ contract_manager_->DeployContract(caller_address, request.deploy_info());
+
+ if (contract_address > 0) {
+ Contract contract;
+ contract.set_owner_address(request.caller_address());
+ contract.set_contract_address(
+ AddressManager::AddressToHex(contract_address));
+ contract.set_contract_name(request.deploy_info().contract_name());
+ return contract;
+ }
+ return absl::InternalError("Deploy Contract fail.");
+}
+
+absl::StatusOr<std::string> ContractTransactionManager::Execute(
+ const Request& request) {
+ Address caller_address =
+ AddressManager::HexToAddress(request.caller_address());
+ if (!address_manager_->Exist(caller_address)) {
+ LOG(ERROR) << "caller doesn't have an account";
+ return absl::InvalidArgumentError("Account not exist.");
+ }
+
+ return contract_manager_->ExecContract(
+ caller_address, AddressManager::HexToAddress(request.contract_address()),
+ request.func_params());
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager.h b/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager.h
new file mode 100644
index 000000000..33638c2f4
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "platform/config/resdb_config_utils.h"
+#include "platform/consensus/execution/transaction_manager.h"
+#include "service/contract/executor/manager/address_manager.h"
+#include "service/contract/executor/manager/contract_manager.h"
+#include "service/contract/proto/func_params.pb.h"
+#include "service/contract/proto/rpc.pb.h"
+
+namespace resdb {
+namespace contract {
+
+class ContractTransactionManager : public TransactionManager {
+ public:
+ ContractTransactionManager(void);
+ virtual ~ContractTransactionManager() = default;
+
+ std::unique_ptr<std::string> ExecuteData(const std::string& request) override;
+
+ private:
+ absl::StatusOr<Account> CreateAccount();
+ absl::StatusOr<Contract> Deploy(const Request& request);
+ absl::StatusOr<std::string> Execute(const Request& request);
+
+ private:
+ std::unique_ptr<ContractManager> contract_manager_;
+ std::unique_ptr<AddressManager> address_manager_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager_test.cpp b/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager_test.cpp
new file mode 100644
index 000000000..e0d59e186
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/eo_service/contract_transaction_manager_test.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/service/contract_transaction_manager.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Test;
+
+const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
+ std::string(getenv("TEST_WORKSPACE")) +
+ "/service/contract/executor/service/";
+
+std::string ToString(const Request& request) {
+ std::string ret;
+ request.SerializeToString(&ret);
+ return ret;
+}
+
+class ContractTransactionManagerTest : public Test {
+ public:
+ ContractTransactionManagerTest() {
+ std::string contract_path = test_dir + "test_data/contract.json";
+
+ std::ifstream contract_fstream(contract_path);
+ if (!contract_fstream) {
+ throw std::runtime_error(fmt::format(
+ "Unable to open contract definition file {}", contract_path));
+ }
+
+ nlohmann::json definition = nlohmann::json::parse(contract_fstream);
+ contracts_json_ = definition["contracts"];
+ }
+
+ Account CreateAccount() {
+ Request request;
+ Response response;
+
+ request.set_cmd(Request::CREATE_ACCOUNT);
+ std::unique_ptr<std::string> ret = executor_.ExecuteData(ToString(request));
+ EXPECT_TRUE(ret != nullptr);
+ response.ParseFromString(*ret);
+ return response.account();
+ }
+
+ absl::StatusOr<Contract> Deploy(const Account& account,
+ DeployInfo deploy_info) {
+ Request request;
+ Response response;
+
+ request.set_caller_address(account.address());
+ *request.mutable_deploy_info() = deploy_info;
+ request.set_cmd(Request::DEPLOY);
+
+ std::unique_ptr<std::string> ret = executor_.ExecuteData(ToString(request));
+ EXPECT_TRUE(ret != nullptr);
+
+ response.ParseFromString(*ret);
+ if (response.ret() == 0) {
+ return response.contract();
+ } else {
+ return absl::InternalError("DeployFail.");
+ }
+ }
+
+ absl::StatusOr<uint256_t> Execute(const std::string& caller_address,
+ const std::string& contract_address,
+ const Params& params) {
+ Request request;
+ Response response;
+
+ request.set_caller_address(caller_address);
+ request.set_contract_address(contract_address);
+ request.set_cmd(Request::EXECUTE);
+ *request.mutable_func_params() = params;
+
+ std::unique_ptr<std::string> ret = executor_.ExecuteData(ToString(request));
+ EXPECT_TRUE(ret != nullptr);
+
+ response.ParseFromString(*ret);
+
+ if (response.ret() == 0) {
+ return eevm::to_uint256(response.res());
+ } else {
+ return absl::InternalError("DeployFail.");
+ }
+ }
+
+ protected:
+ nlohmann::json contracts_json_;
+ ContractTransactionManager executor_;
+};
+
+TEST_F(ContractTransactionManagerTest, ExecContract) {
+ // create an account.
+ Account account = CreateAccount();
+ EXPECT_FALSE(account.address().empty());
+
+ std::string contract_name = "ERC20.sol:ERC20Token";
+ std::string contract_code = contracts_json_[contract_name]["bin"];
+ nlohmann::json func_hashes = contracts_json_[contract_name]["hashes"];
+
+ // deploy
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_code);
+ deploy_info.set_contract_name(contract_name);
+
+ for (auto& func : func_hashes.items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+ deploy_info.add_init_param("1000");
+
+ absl::StatusOr<Contract> contract_or = Deploy(account, deploy_info);
+ EXPECT_TRUE(contract_or.ok());
+ Contract contract = *contract_or;
+
+ // query owner should return 1000
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(account.address());
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_EQ(*result, 0x3e8);
+ }
+
+ Account transfer_receiver = CreateAccount();
+ EXPECT_FALSE(account.address().empty());
+ // receiver 0
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(transfer_receiver.address());
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_EQ(*result, 0);
+ }
+
+ // transfer 400 to receiver
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(transfer_receiver.address());
+ func_params.add_param("400");
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_EQ(*result, 1);
+ }
+
+ // query owner should return 600
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(account.address());
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_EQ(*result, 600);
+ }
+
+ // receiver 400
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(transfer_receiver.address());
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_EQ(*result, 400);
+ }
+}
+
+TEST_F(ContractTransactionManagerTest, DeployFail) {
+ // create an account.
+ Account account = CreateAccount();
+ EXPECT_FALSE(account.address().empty());
+
+ std::string contract_name = "ERC20.sol:ERC20Token";
+ std::string contract_code = contracts_json_[contract_name]["bin"];
+ nlohmann::json func_hashes = contracts_json_[contract_name]["hashes"];
+
+ // deploy
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_code);
+ deploy_info.set_contract_name(contract_name);
+
+ for (auto& func : func_hashes.items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+ // deploy_info.add_init_param("1000");
+
+ absl::StatusOr<Contract> contract_or = Deploy(account, deploy_info);
+ EXPECT_FALSE(contract_or.ok());
+}
+
+TEST_F(ContractTransactionManagerTest, NoFunc) {
+ // create an account.
+ Account account = CreateAccount();
+ EXPECT_FALSE(account.address().empty());
+
+ std::string contract_name = "ERC20.sol:ERC20Token";
+ std::string contract_code = contracts_json_[contract_name]["bin"];
+ nlohmann::json func_hashes = contracts_json_[contract_name]["hashes"];
+
+ // deploy
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_code);
+ deploy_info.set_contract_name(contract_name);
+
+ for (auto& func : func_hashes.items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+ deploy_info.add_init_param("1000");
+
+ absl::StatusOr<Contract> contract_or = Deploy(account, deploy_info);
+ EXPECT_TRUE(contract_or.ok());
+ Contract contract = *contract_or;
+
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf()");
+ func_params.add_param(account.address());
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_FALSE(result.ok());
+ }
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/eo_service/test_data/BUILD b/platform/consensus/ordering/thunderbolt/executor/eo_service/test_data/BUILD
new file mode 100644
index 000000000..65e3dc3d9
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/eo_service/test_data/BUILD
@@ -0,0 +1 @@
+exports_files(["contract.json"])
diff --git a/platform/consensus/ordering/thunderbolt/executor/eo_service/test_data/contract.json b/platform/consensus/ordering/thunderbolt/executor/eo_service/test_data/contract.json
new file mode 100644
index 000000000..e9c0d972f
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/eo_service/test_data/contract.json
@@ -0,0 +1,19 @@
+{
+ "contracts":
+ {
+ "ERC20.sol:ERC20Token":
+ {
+ "bin": "608060405234801561001057600080fd5b506040516104423803806104428339818101604052602081101561003357600080fd5b50516000818155338152600160205260409020556103ec806100566000396000f3fe608060405234801561001057600080fd5b506004361061007e577c01000000000000000000000000000000000000000000000000000000006000350463095ea7b3811461008357806318160ddd146100c357806323b872dd146100dd57806370a0823114610113578063a9059cbb14610139578063dd62ed3e14610165575b600080fd5b6100af6004803603604081101561009957600080fd [...]
+ "hashes":
+ {
+ "allowance(address,address)": "dd62ed3e",
+ "approve(address,uint256)": "095ea7b3",
+ "balanceOf(address)": "70a08231",
+ "totalSupply()": "18160ddd",
+ "transfer(address,uint256)": "a9059cbb",
+ "transferFrom(address,address,uint256)": "23b872dd"
+ }
+ }
+ },
+ "version": "0.5.16+commit.9c3226ce.Linux.g++"
+}
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/BUILD b/platform/consensus/ordering/thunderbolt/executor/manager/BUILD
new file mode 100644
index 000000000..64b36e2d0
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/BUILD
@@ -0,0 +1,620 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "address_manager",
+ srcs = ["address_manager.cpp"],
+ hdrs = ["address_manager.h"],
+ deps = [
+ "//common:comm",
+ "//service/contract/executor/common:utils",
+ ],
+)
+
+cc_test(
+ name = "address_manager_test",
+ srcs = ["address_manager_test.cpp"],
+ deps = [
+ ":address_manager",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "data_storage",
+ srcs = ["data_storage.cpp"],
+ hdrs = ["data_storage.h"],
+ deps = [
+ "//common:comm",
+ "//service/contract/executor/common:utils",
+ ],
+)
+
+cc_library(
+ name = "leveldb_storage",
+ srcs = ["leveldb_storage.cpp"],
+ hdrs = ["leveldb_storage.h"],
+ deps = [
+ ":data_storage",
+ "//common:comm",
+ "//storage:res_leveldb",
+ ],
+)
+
+cc_library(
+ name = "mock_data_storage",
+ hdrs = ["mock_data_storage.h"],
+ deps = [
+ ":data_storage",
+ "//common/test",
+ ],
+)
+
+cc_library(
+ name = "mock_d_storage",
+ hdrs = ["mock_d_storage.h"],
+ deps = [
+ ":d_storage",
+ "//common/test",
+ ],
+)
+
+cc_library(
+ name = "d_storage",
+ srcs = ["d_storage.cpp"],
+ hdrs = ["d_storage.h"],
+ deps = [
+ ":data_storage",
+ "//common:comm",
+ ],
+)
+
+cc_library(
+ name = "leveldb_d_storage",
+ srcs = ["leveldb_d_storage.cpp"],
+ hdrs = ["leveldb_d_storage.h"],
+ deps = [
+ ":data_storage",
+ "//common:comm",
+ "//storage:res_leveldb",
+ ],
+)
+
+cc_library(
+ name = "leveldb",
+ srcs = ["leveldb.cpp"],
+ hdrs = ["leveldb.h"],
+ deps = [
+ ":data_storage",
+ "//common:comm",
+ "//storage:res_leveldb",
+ ],
+)
+
+cc_library(
+ name = "global_view",
+ srcs = ["global_view.cpp"],
+ hdrs = ["global_view.h"],
+ deps = [
+ ":data_storage",
+ "//common:comm",
+ ],
+)
+
+cc_library(
+ name = "local_view",
+ srcs = ["local_view.cpp"],
+ hdrs = ["local_view.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ ],
+)
+
+cc_test(
+ name = "local_view_test",
+ srcs = ["local_view_test.cpp"],
+ deps = [
+ ":local_view",
+ ":two_phase_controller",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "evm_state",
+ hdrs = ["evm_state.h"],
+ deps = [
+ "//common:comm",
+ "//service/contract/executor/common:utils",
+ ],
+)
+
+cc_library(
+ name = "global_state",
+ srcs = ["global_state.cpp"],
+ hdrs = ["global_state.h"],
+ deps = [
+ ":evm_state",
+ ":global_view",
+ "//common:comm",
+ "//service/contract/executor/common:utils",
+ ],
+)
+
+cc_library(
+ name = "local_state",
+ srcs = ["local_state.cpp"],
+ hdrs = ["local_state.h"],
+ deps = [
+ ":evm_state",
+ ":local_view",
+ "//common:comm",
+ "//service/contract/executor/common:utils",
+ ],
+)
+
+cc_library(
+ name = "concurrency_controller",
+ srcs = ["concurrency_controller.cpp"],
+ hdrs = ["concurrency_controller.h"],
+ deps = [
+ ":data_storage",
+ ],
+)
+
+cc_library(
+ name = "two_phase_ooo_controller",
+ srcs = ["two_phase_ooo_controller.cpp"],
+ hdrs = ["two_phase_ooo_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ ],
+)
+
+cc_library(
+ name = "two_phase_ooo_committer",
+ srcs = ["two_phase_ooo_committer.cpp"],
+ hdrs = ["two_phase_ooo_committer.h"],
+ deps = [
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":two_phase_ooo_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "two_phase_controller",
+ srcs = ["two_phase_controller.cpp"],
+ hdrs = ["two_phase_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ ],
+)
+
+cc_test(
+ name = "two_phase_controller_test",
+ srcs = ["two_phase_controller_test.cpp"],
+ deps = [
+ ":two_phase_controller",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "ooo_controller",
+ srcs = ["ooo_controller.cpp"],
+ hdrs = ["ooo_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ ],
+)
+
+cc_library(
+ name = "sequential_cc_controller",
+ srcs = ["sequential_cc_controller.cpp"],
+ hdrs = ["sequential_cc_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ ],
+)
+
+cc_test(
+ name = "sequential_cc_controller_test",
+ srcs = ["sequential_cc_controller_test.cpp"],
+ deps = [
+ ":sequential_cc_controller",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "streaming_dq_controller",
+ srcs = ["streaming_dq_controller.cpp"],
+ hdrs = ["streaming_dq_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ ":d_storage",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ ],
+)
+
+cc_library(
+ name = "test_controller",
+ testonly = True,
+ srcs = ["test_controller.cpp"],
+ hdrs = ["test_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ ],
+)
+
+cc_library(
+ name = "contract_executor",
+ srcs = ["contract_executor.cpp"],
+ hdrs = ["contract_executor.h"],
+ deps = [
+ ":concurrency_controller",
+ ":evm_state",
+ "//common:comm",
+ "//service/contract/executor/common:contract_execute_info",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "committer_context",
+ srcs = ["committer_context.cpp"],
+ hdrs = ["committer_context.h"],
+ deps = [
+ ":contract_committer",
+ ],
+)
+
+cc_library(
+ name = "contract_committer",
+ hdrs = ["contract_committer.h"],
+ deps = [
+ ":contract_executor",
+ "//service/contract/executor/common:contract_execute_info",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "contract_verifier",
+ srcs = ["contract_verifier.cpp"],
+ hdrs = ["contract_verifier.h"],
+ deps = [
+ ":committer_context",
+ ":contract_committer",
+ ":contract_executor",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "ooo_committer",
+ srcs = ["ooo_committer.cpp"],
+ hdrs = ["ooo_committer.h"],
+ deps = [
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":ooo_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "two_phase_committer",
+ srcs = ["two_phase_committer.cpp"],
+ hdrs = ["two_phase_committer.h"],
+ deps = [
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":two_phase_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_test(
+ name = "two_phase_committer_test",
+ srcs = ["two_phase_committer_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ ],
+ deps = [
+ ":address_manager",
+ ":contract_deployer",
+ ":two_phase_committer",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "sequential_concurrency_committer",
+ srcs = ["sequential_concurrency_committer.cpp"],
+ hdrs = ["sequential_concurrency_committer.h"],
+ deps = [
+ ":committer_context",
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":sequential_cc_controller",
+ "//common/utils",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "x_committer",
+ srcs = ["x_committer.cpp"],
+ hdrs = ["x_committer.h"],
+ deps = [
+ ":committer_context",
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":streaming_dq_controller",
+ ":x_controller",
+ "//common/utils",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "x_controller",
+ srcs = ["x_controller.cpp"],
+ hdrs = ["x_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ ],
+)
+
+cc_library(
+ name = "v_controller",
+ srcs = ["v_controller.cpp"],
+ hdrs = ["v_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ ],
+)
+
+cc_library(
+ name = "x_verifier",
+ srcs = ["x_verifier.cpp"],
+ hdrs = ["x_verifier.h"],
+ deps = [
+ ":contract_verifier",
+ ":global_state",
+ ":local_state",
+ ":v_controller",
+ "//common/utils",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_test(
+ name = "x_committer_test",
+ srcs = ["x_committer_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ ],
+ deps = [
+ ":address_manager",
+ ":contract_deployer",
+ ":mock_data_storage",
+ ":x_committer",
+ "//common/test:test_main",
+ ],
+)
+
+cc_test(
+ name = "x_verifier_test",
+ srcs = ["x_verifier_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ "//service/contract/executor/manager/test_data:kv.json",
+ ],
+ deps = [
+ ":address_manager",
+ ":contract_deployer",
+ ":mock_data_storage",
+ ":x_committer",
+ ":x_verifier",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "streaming_single_committer",
+ srcs = ["streaming_single_committer.cpp"],
+ hdrs = ["streaming_single_committer.h"],
+ deps = [
+ ":committer_context",
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ "//common/utils",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "streaming_dq_committer",
+ srcs = ["streaming_dq_committer.cpp"],
+ hdrs = ["streaming_dq_committer.h"],
+ deps = [
+ ":committer_context",
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":streaming_dq_controller",
+ "//common/utils",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_test(
+ name = "streaming_dq_committer_test",
+ srcs = ["streaming_dq_committer_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ "//service/contract/executor/manager/test_data:kv.json",
+ ],
+ deps = [
+ ":address_manager",
+ ":contract_deployer",
+ ":mock_d_storage",
+ ":streaming_dq_committer",
+ "//common/test:test_main",
+ ],
+)
+
+cc_test(
+ name = "sequential_concurrency_committer_test",
+ srcs = ["sequential_concurrency_committer_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ ],
+ deps = [
+ ":address_manager",
+ ":contract_deployer",
+ ":mock_data_storage",
+ ":sequential_concurrency_committer",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "streaming_controller",
+ srcs = ["streaming_controller.cpp"],
+ hdrs = ["streaming_controller.h"],
+ deps = [
+ ":concurrency_controller",
+ "//common:comm",
+ "//platform/common/queue:lock_free_queue",
+ ],
+)
+
+cc_library(
+ name = "streaming_committer",
+ srcs = ["streaming_committer.cpp"],
+ hdrs = ["streaming_committer.h"],
+ deps = [
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":local_state",
+ ":streaming_controller",
+ "//common/utils",
+ "//platform/common/queue:lock_free_queue",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "test_committer",
+ testonly = True,
+ srcs = ["test_committer.cpp"],
+ hdrs = ["test_committer.h"],
+ deps = [
+ ":contract_committer",
+ ":contract_executor",
+ ":global_state",
+ ":test_controller",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_library(
+ name = "contract_deployer",
+ srcs = ["contract_deployer.cpp"],
+ hdrs = ["contract_deployer.h"],
+ deps = [
+ ":address_manager",
+ ":concurrency_controller",
+ ":contract_committer",
+ ":global_state",
+ ],
+)
+
+cc_test(
+ name = "contract_deployer_test",
+ srcs = ["contract_deployer_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ ],
+ deps = [
+ ":contract_deployer",
+ ":test_committer",
+ "//common/test:test_main",
+ ],
+)
+
+cc_library(
+ name = "contract_manager",
+ srcs = ["contract_manager.cpp"],
+ hdrs = ["contract_manager.h"],
+ deps = [
+ ":address_manager",
+ ":concurrency_controller",
+ ":contract_deployer",
+ ":global_state",
+ ":ooo_committer",
+ ":sequential_concurrency_committer",
+ ":streaming_committer",
+ ":streaming_dq_committer",
+ ":streaming_single_committer",
+ ":two_phase_committer",
+ ":two_phase_ooo_committer",
+ ":x_committer",
+ ":x_verifier",
+ "//common:comm",
+ "//service/contract/executor/common:utils",
+ "//service/contract/proto:func_params_cc_proto",
+ ],
+)
+
+cc_test(
+ name = "contract_manager_test",
+ srcs = ["contract_manager_test.cpp"],
+ data = [
+ "//service/contract/executor/manager/test_data:contract.json",
+ ],
+ deps = [
+ ":contract_manager",
+ "//common/test:test_main",
+ ],
+)
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/address_manager.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/address_manager.cpp
new file mode 100644
index 000000000..67a2281bd
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/address_manager.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/address_manager.h"
+
+#include <glog/logging.h>
+
+#include "eEVM/util.h"
+
+namespace resdb {
+namespace contract {
+
+Address AddressManager::CreateRandomAddress() {
+ std::vector<uint8_t> raw(20);
+ std::generate(raw.begin(), raw.end(), []() { return rand(); });
+ Address address = eevm::from_big_endian(raw.data(), raw.size());
+ users_.insert(address);
+ return address;
+}
+
+bool AddressManager::CreateAddress(const Address& address) {
+ if (users_.find(address) != users_.end()) {
+ return false;
+ }
+ users_.insert(address);
+ return true;
+}
+
+bool AddressManager::Exist(const Address& address) {
+ return users_.find(address) != users_.end();
+}
+
+Address AddressManager::CreateContractAddress(const Address& owner) {
+ return eevm::generate_address(owner, 0u);
+}
+
+std::string AddressManager::AddressToHex(const Address& address) {
+ return eevm::to_hex_string(address);
+}
+
+Address AddressManager::HexToAddress(const std::string& address) {
+ return eevm::to_uint256(address);
+}
+
+uint256_t AddressManager::AddressToSHAKey(const Address& address) {
+ std::vector<uint8_t> code;
+ code.resize(64u);
+ eevm::to_big_endian(address, code.data());
+ // code[63]=1;
+ // LOG(ERROR)<<"code size:"<<code.size();
+
+ uint8_t h[32];
+ eevm::keccak_256(code.data(), static_cast<unsigned int>(code.size()), h);
+ // LOG(ERROR)<<"get h:"<<eevm::from_big_endian(h, sizeof(h));
+ return eevm::from_big_endian(h, sizeof(h));
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/address_manager.h b/platform/consensus/ordering/thunderbolt/executor/manager/address_manager.h
new file mode 100644
index 000000000..c3aa11db2
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/address_manager.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <set>
+
+#include "service/contract/executor/common/utils.h"
+
+namespace resdb {
+namespace contract {
+
+class AddressManager {
+ public:
+ AddressManager() {}
+
+ // Create an address holding a 20 byte value
+ Address CreateRandomAddress();
+ bool CreateAddress(const Address& address);
+ bool Exist(const Address& address);
+
+ static Address CreateContractAddress(const Address& owner);
+
+ static std::string AddressToHex(const Address& address);
+ static Address HexToAddress(const std::string& address);
+
+ static uint256_t AddressToSHAKey(const Address& address);
+
+ private:
+ std::set<Address> users_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/address_manager_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/address_manager_test.cpp
new file mode 100644
index 000000000..cb7d7454c
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/address_manager_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/address_manager.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include "eEVM/util.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+TEST(AddressManagerTest, CreateAddress) {
+ Address address = AddressManager().CreateRandomAddress();
+ std::array<uint8_t, 32> raw;
+ eevm::to_big_endian(address, raw.data());
+ Address m = eevm::from_big_endian(raw.data() + 12, raw.size() - 12);
+ EXPECT_EQ(m, address);
+}
+
+TEST(AddressManagerTest, CreateContractAddress) {
+ Address address = AddressManager().CreateRandomAddress();
+
+ Address contract_address = AddressManager::CreateContractAddress(address);
+
+ std::array<uint8_t, 32> raw;
+ eevm::to_big_endian(contract_address, raw.data());
+ Address m = eevm::from_big_endian(raw.data() + 12, raw.size() - 12);
+ EXPECT_EQ(m, contract_address);
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/committer_context.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/committer_context.cpp
new file mode 100644
index 000000000..0b9d4bd77
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/committer_context.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/committer_context.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+ExecutionContext::ExecutionContext(const ContractExecuteInfo& info) {
+ info_ = std::make_unique<ContractExecuteInfo>(info);
+}
+
+const ContractExecuteInfo* ExecutionContext::GetContractExecuteInfo() const {
+ return info_.get();
+}
+
+ContractExecuteInfo* ExecutionContext::GetContractExecuteInfo() {
+ return info_.get();
+}
+
+void ExecutionContext::SetResult(std::unique_ptr<ExecuteResp> result) {
+ result_ = std::move(result);
+}
+
+bool ExecutionContext::IsRedo() { return is_redo_; }
+
+void ExecutionContext::SetRedo() { is_redo_++; }
+
+int ExecutionContext::RedoTime() { return is_redo_; }
+
+std::unique_ptr<ExecuteResp> ExecutionContext::FetchResult() {
+ return std::move(result_);
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/committer_context.h b/platform/consensus/ordering/thunderbolt/executor/manager/committer_context.h
new file mode 100644
index 000000000..0a62a7fb7
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/committer_context.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "service/contract/executor/manager/contract_committer.h"
+
+namespace resdb {
+namespace contract {
+
+class ExecutionContext {
+ public:
+ ExecutionContext(const ContractExecuteInfo& info);
+ const ContractExecuteInfo* GetContractExecuteInfo() const;
+ ContractExecuteInfo* GetContractExecuteInfo();
+
+ void SetRedo();
+ bool IsRedo();
+ int RedoTime();
+
+ void SetResult(std::unique_ptr<ExecuteResp> result);
+ std::unique_ptr<ExecuteResp> FetchResult();
+
+ private:
+ int is_redo_ = 0;
+ std::unique_ptr<ExecuteResp> result_;
+ std::unique_ptr<ContractExecuteInfo> info_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/concurrency_controller.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/concurrency_controller.cpp
new file mode 100644
index 000000000..923617519
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/concurrency_controller.cpp
@@ -0,0 +1,16 @@
+#include "service/contract/executor/manager/concurrency_controller.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+ConcurrencyController::ConcurrencyController(DataStorage* storage)
+ : storage_(storage) {}
+
+const DataStorage* ConcurrencyController::GetStorage() const {
+ return storage_;
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/concurrency_controller.h b/platform/consensus/ordering/thunderbolt/executor/manager/concurrency_controller.h
new file mode 100644
index 000000000..a2ff27cef
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/concurrency_controller.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "service/contract/executor/manager/data_storage.h"
+
+namespace resdb {
+namespace contract {
+
+enum State {
+ LOAD = 0,
+ STORE = 1,
+ REMOVE = 2,
+};
+
+struct Data {
+ State state;
+ uint256_t data;
+ int64_t version;
+ uint256_t old_data;
+ Data() {}
+ Data(const State& state) : state(state) {}
+ Data(const State& state, const uint256_t& data, int64_t version = 0)
+ : state(state), data(data), version(version) {}
+ Data(const State& state, const uint256_t& data, int64_t version,
+ const uint256_t& old_data)
+ : state(state), data(data), version(version), old_data(old_data) {}
+ bool operator!=(const Data& d) const {
+ return d.state != this->state || d.data != this->data ||
+ d.version != this->version;
+ }
+};
+
+class ConcurrencyController {
+ public:
+ ConcurrencyController(DataStorage* storage);
+
+ typedef std::map<uint256_t, std::vector<Data>> ModifyMap;
+
+ virtual void PushCommit(int64_t commit_id,
+ const ModifyMap& local_changes_) = 0;
+
+ const DataStorage* GetStorage() const;
+
+ protected:
+ DataStorage* storage_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_committer.h b/platform/consensus/ordering/thunderbolt/executor/manager/contract_committer.h
new file mode 100644
index 000000000..b6c874a0e
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_committer.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <thread>
+
+#include "absl/status/statusor.h"
+#include "eEVM/address.h"
+#include "eEVM/opcode.h"
+#include "service/contract/executor/common/contract_execute_info.h"
+#include "service/contract/executor/manager/contract_executor.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+/*
+struct ContractExecuteInfo {
+ eevm::Address caller_address;
+ eevm::Address contract_address;
+ std::string func_addr;
+ Params func_params;
+ int64_t commit_id;
+ uint64_t user_id;
+ ContractExecuteInfo(){}
+ ContractExecuteInfo(
+ eevm::Address caller_address,
+ eevm::Address contract_address,
+ std::string func_addr,
+ Params func_params,
+ int64_t commit_id): caller_address(caller_address),
+contract_address(contract_address), func_addr(func_addr),
+func_params(func_params), commit_id(commit_id){}
+};
+*/
+
+class ContractCommitter {
+ public:
+ ContractCommitter() = default;
+ virtual ~ContractCommitter() = default;
+
+ virtual std::vector<std::unique_ptr<ExecuteResp>> ExecContract(
+ std::vector<ContractExecuteInfo>& request) = 0;
+
+ virtual void AsyncExecContract(std::vector<ContractExecuteInfo>& request){};
+
+ virtual absl::StatusOr<std::string> ExecContract(
+ const Address& caller_address, const Address& contract_address,
+ const std::string& func_addr, const Params& func_param,
+ EVMState* state) = 0;
+
+ virtual void SetExecuteCallBack(
+ std::function<void(std::unique_ptr<ExecuteResp>)>){};
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer.cpp
new file mode 100644
index 000000000..8a2ae4f9b
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/contract_deployer.h"
+
+#include <glog/logging.h>
+
+#include "eEVM/processor.h"
+#include "service/contract/executor/manager/address_manager.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+std::string U256ToString(uint256_t v) { return eevm::to_hex_string(v); }
+
+void AppendArgToInput(std::vector<uint8_t>& code, const uint256_t& arg) {
+ const auto pre_size = code.size();
+ code.resize(pre_size + 32u);
+ eevm::to_big_endian(arg, code.data() + pre_size);
+ // LOG(ERROR)<<"add arg:"<<arg;
+}
+
+void AppendArgToInput(std::vector<uint8_t>& code, const std::string& arg) {
+ AppendArgToInput(code, eevm::to_uint256(arg));
+}
+
+} // namespace
+
+ContractDeployer::ContractDeployer(ContractCommitter* committer,
+ GlobalState* gs)
+ : committer_(committer), gs_(gs) {}
+
+std::string ContractDeployer::GetFuncAddress(const Address& contract_address,
+ const std::string& func_name) {
+ return func_address_[contract_address][func_name];
+}
+
+void ContractDeployer::SetFuncAddress(const Address& contract_address,
+ const FuncInfo& func) {
+ func_address_[contract_address][func.func_name()] = func.hash();
+}
+
+Address ContractDeployer::DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info) {
+ const auto contract_address =
+ AddressManager::CreateContractAddress(owner_address);
+
+ auto contract_constructor = eevm::to_bytes(deploy_info.contract_bin());
+ for (const std::string& param : deploy_info.init_param()) {
+ AppendArgToInput(contract_constructor, param);
+ }
+
+ try {
+ auto contract = gs_->create(contract_address, 0u, contract_constructor);
+ absl::StatusOr<std::string> result =
+ committer_->ExecContract(owner_address, contract_address, "", {}, gs_);
+
+ if (result.ok()) {
+ // set the initialized class context code.
+ contract.acc.set_code(eevm::to_bytes(*result));
+
+ for (const auto& info : deploy_info.func_info()) {
+ SetFuncAddress(contract_address, info);
+ }
+ // LOG(ERROR)<<"contract create:"<<contract_address<<"
+ // addr:"<<contract.acc.get_address();
+ return contract.acc.get_address();
+ } else {
+ gs_->remove(contract_address);
+ return 0;
+ }
+ } catch (...) {
+ LOG(ERROR) << "Deploy throw expection";
+ return 0;
+ }
+}
+
+bool ContractDeployer::DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info,
+ const Address& contract_address) {
+ LOG(ERROR) << "deploy address:" << contract_address;
+ auto contract_constructor = eevm::to_bytes(deploy_info.contract_bin());
+ for (const std::string& param : deploy_info.init_param()) {
+ AppendArgToInput(contract_constructor, param);
+ }
+
+ try {
+ LOG(ERROR) << "deploy:" << (gs_ == nullptr);
+ auto contract = gs_->create(contract_address, 0u, contract_constructor);
+
+ LOG(ERROR) << "create:";
+ absl::StatusOr<std::string> result =
+ committer_->ExecContract(owner_address, contract_address, "", {}, gs_);
+
+ LOG(ERROR) << "deploy result:" << result.ok() << " code:" << *result;
+ if (result.ok()) {
+ // set the initialized class context code.
+ contract.acc.set_code(eevm::to_bytes(*result));
+
+ for (const auto& info : deploy_info.func_info()) {
+ SetFuncAddress(contract_address, info);
+ }
+ return true;
+ } else {
+ gs_->remove(contract_address);
+ return false;
+ }
+ } catch (...) {
+ LOG(ERROR) << "Deploy throw expection";
+ return false;
+ }
+}
+
+Address ContractDeployer::DeployContract(
+ const Address& owner_address, const nlohmann::json& contract_json,
+ const std::vector<uint256_t>& init_params) {
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json["bin"]);
+
+ for (auto& func : contract_json["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ for (const uint256_t& param : init_params) {
+ deploy_info.add_init_param(U256ToString(param));
+ }
+
+ return DeployContract(owner_address, deploy_info);
+}
+
+bool ContractDeployer::DeployContract(const Address& owner_address,
+ const nlohmann::json& contract_json,
+ const std::vector<uint256_t>& init_params,
+ const Address& contract_address) {
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json["bin"]);
+
+ for (auto& func : contract_json["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ for (const uint256_t& param : init_params) {
+ deploy_info.add_init_param(U256ToString(param));
+ }
+
+ return DeployContract(owner_address, deploy_info, contract_address);
+}
+
+absl::StatusOr<eevm::AccountState> ContractDeployer::GetContract(
+ const Address& address) {
+ if (!gs_->Exists(address)) {
+ return absl::InvalidArgumentError("Contract not exist.");
+ }
+
+ return gs_->get(address);
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer.h b/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer.h
new file mode 100644
index 000000000..6c6626b26
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "service/contract/executor/manager/contract_committer.h"
+#include "service/contract/executor/manager/global_state.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+class ContractDeployer {
+ public:
+ ContractDeployer(ContractCommitter* committer, GlobalState* gs);
+
+ public:
+ Address DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info);
+ bool DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info,
+ const Address& contract_address);
+
+ Address DeployContract(const Address& owner_address,
+ const nlohmann::json& contract_json,
+ const std::vector<uint256_t>& init_params);
+ bool DeployContract(const Address& owner_address,
+ const nlohmann::json& contract_json,
+ const std::vector<uint256_t>& init_params,
+ const Address& contract_address);
+
+ absl::StatusOr<eevm::AccountState> GetContract(const Address& address);
+ std::string GetFuncAddress(const Address& contract_address,
+ const std::string& func_name);
+
+ private:
+ void SetFuncAddress(const Address& contract_address, const FuncInfo& func);
+
+ private:
+ ContractCommitter* committer_;
+ GlobalState* gs_;
+ std::map<Address, std::map<std::string, std::string>> func_address_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer_test.cpp
new file mode 100644
index 000000000..4ce4426d4
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_deployer_test.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/contract_deployer.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "service/contract/executor/manager/address_manager.h"
+#include "service/contract/executor/manager/test_committer.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Test;
+
+const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
+ std::string(getenv("TEST_WORKSPACE")) +
+ "/service/contract/executor/manager/";
+
+Address get_random_address() { return AddressManager().CreateRandomAddress(); }
+
+std::string U256ToString(uint256_t v) { return eevm::to_hex_string(v); }
+
+class ContractDeployerTest : public Test {
+ public:
+ ContractDeployerTest() : owner_address_(get_random_address()) {
+ storage_ = std::make_unique<DataStorage>();
+ gs_ = std::make_unique<GlobalState>(storage_.get());
+ execotor_ = std::make_unique<TestCommitter>(storage_.get(), gs_.get());
+
+ LOG(ERROR) << "owner:" << owner_address_;
+ std::string contract_path = test_dir + "test_data/contract.json";
+
+ std::ifstream contract_fstream(contract_path);
+ if (!contract_fstream) {
+ throw std::runtime_error(fmt::format(
+ "Unable to open contract definition file {}", contract_path));
+ }
+
+ const auto contracts_definition = nlohmann::json::parse(contract_fstream);
+ const auto all_contracts = contracts_definition["contracts"];
+ const auto contract_code = all_contracts["ERC20.sol:ERC20Token"];
+ contract_json_ = contract_code;
+ }
+
+ protected:
+ Address owner_address_;
+ nlohmann::json contract_json_;
+
+ std::unique_ptr<DataStorage> storage_;
+ std::unique_ptr<GlobalState> gs_;
+ std::unique_ptr<ContractCommitter> execotor_;
+};
+
+TEST_F(ContractDeployerTest, NoContract) {
+ ContractDeployer deployer(execotor_.get(), gs_.get());
+ auto account = deployer.GetContract(1234);
+ EXPECT_FALSE(account.ok());
+}
+
+TEST_F(ContractDeployerTest, DeployContract) {
+ ContractDeployer deployer(execotor_.get(), gs_.get());
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ deployer.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = deployer.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+}
+
+TEST_F(ContractDeployerTest, DeployContractFromJson) {
+ ContractDeployer deployer(execotor_.get(), gs_.get());
+
+ Address contract_address =
+ deployer.DeployContract(owner_address_, contract_json_, {1000});
+ EXPECT_GT(contract_address, 0);
+ auto account = deployer.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor.cpp
new file mode 100644
index 000000000..c94d9e0ec
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/contract_executor.h"
+
+//#include "common/utils/utils.h"
+
+#include "eEVM/processor.h"
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+void AppendArgToInput(std::vector<uint8_t>& code, const uint256_t& arg) {
+ const auto pre_size = code.size();
+ code.resize(pre_size + 32u);
+ eevm::to_big_endian(arg, code.data() + pre_size);
+}
+
+void AppendArgToInput(std::vector<uint8_t>& code, const std::string& arg) {
+ AppendArgToInput(code, eevm::to_uint256(arg));
+}
+
+absl::StatusOr<std::string> ContractExecutor::ExecContract(
+ const Address& caller_address, const Address& contract_address,
+ const std::string& func_addr, const Params& func_param, EVMState* state) {
+ std::vector<uint8_t> inputs;
+ if (!func_addr.empty()) {
+ inputs = eevm::to_bytes(func_addr);
+ }
+ for (const std::string& param : func_param.param()) {
+ AppendArgToInput(inputs, param);
+ }
+
+ auto result = Execute(caller_address, contract_address, inputs, state);
+
+ if (result.ok()) {
+ return eevm::to_hex_string(*result);
+ } else {
+ LOG(ERROR) << "execute fail:" << result.status();
+ }
+ return result.status();
+}
+
+absl::StatusOr<std::vector<uint8_t>> ContractExecutor::Execute(
+ const Address& caller_address, const Address& contract_address,
+ const std::vector<uint8_t>& input, EVMState* state) {
+ // Ignore any logs produced by this transaction
+ eevm::NullLogHandler ignore;
+ eevm::Transaction tx(caller_address, ignore);
+
+ // Record a trace to aid debugging
+ eevm::Trace tr;
+ eevm::Processor p(*state);
+
+ // Run the transaction
+ try {
+ const auto exec_result =
+ p.run(tx, caller_address, state->get(contract_address), input, 0u, &tr);
+
+ if (exec_result.er != eevm::ExitReason::returned) {
+ // Print the trace if nothing was returned
+ if (exec_result.er == eevm::ExitReason::threw) {
+ return absl::InternalError(
+ fmt::format("Execution error: {}", exec_result.exmsg));
+ }
+ return absl::InternalError("Deployment did not return");
+ }
+ return exec_result.output;
+ } catch (...) {
+ return absl::InternalError(fmt::format("Execution error:"));
+ }
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor.h b/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor.h
new file mode 100644
index 000000000..eebb1c22c
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <thread>
+
+#include "absl/status/statusor.h"
+#include "eEVM/opcode.h"
+#include "service/contract/executor/common/contract_execute_info.h"
+#include "service/contract/executor/common/utils.h"
+#include "service/contract/executor/manager/concurrency_controller.h"
+#include "service/contract/executor/manager/evm_state.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+/*
+struct ExecuteResp {
+ int ret;
+ absl::Status state;
+ int64_t commit_id;
+ Address contract_address;
+ ConcurrencyController :: ModifyMap rws;
+ std::string result;
+ int retry_time = 0;
+ uint64_t user_id = 0;
+ double runtime = 0;
+};
+*/
+
+class ContractExecutor {
+ public:
+ ContractExecutor() = default;
+
+ ~ContractExecutor() = default;
+
+ absl::StatusOr<std::string> ExecContract(const Address& caller_address,
+ const Address& contract_address,
+ const std::string& func_addr,
+ const Params& func_param,
+ EVMState* state);
+
+ absl::StatusOr<std::vector<uint8_t>> Execute(
+ const Address& owner_address, const Address& contract_address,
+ const std::vector<uint8_t>& func_params, EVMState* state);
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor_test.cpp
new file mode 100644
index 000000000..1b35fd4f7
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_executor_test.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "service/contract/executor/manager/address_manager.h"
+#include "service/contract/executor/manager/contract_manager.h"
+#include "service/contract/executor/manager/multi_contract_executor.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Test;
+
+const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
+ std::string(getenv("TEST_WORKSPACE")) +
+ "/service/contract/executor/manager/";
+
+Address get_random_address() { return AddressManager().CreateRandomAddress(); }
+
+std::string U256ToString(uint256_t v) { return eevm::to_hex_string(v); }
+uint256_t HexToInt(const std::string& v) { return eevm::to_uint256(v); }
+
+uint256_t GetAddressHash(uint256_t address) {
+ std::vector<uint8_t> code;
+ code.resize(64u);
+ eevm::to_big_endian(address, code.data());
+ code[63] = 1;
+
+ uint8_t h[32];
+ eevm::keccak_256(code.data(), static_cast<unsigned int>(code.size()), h);
+ return eevm::from_big_endian(h, sizeof(h));
+}
+
+class MultiContractExecutorTest : public Test {
+ public:
+ MultiContractExecutorTest() : owner_address_(get_random_address()) {
+ std::string contract_path = test_dir + "test_data/contract.json";
+ LOG(ERROR) << "test dir:" << test_dir;
+
+ std::ifstream contract_fstream(contract_path);
+ if (!contract_fstream) {
+ throw std::runtime_error(fmt::format(
+ "Unable to open contract definition file {}", contract_path));
+ }
+
+ const auto contracts_definition = nlohmann::json::parse(contract_fstream);
+ const auto all_contracts = contracts_definition["contracts"];
+ const auto contract_code = all_contracts["ERC20.sol:ERC20Token"];
+ contract_json_ = contract_code;
+ }
+
+ protected:
+ Address owner_address_;
+ nlohmann::json contract_json_;
+};
+
+TEST_F(MultiContractExecutorTest, ExecContract) {
+ std::unique_ptr<DataStorage> storage = std::make_unique<DataStorage>();
+ DataStorage* storage_ptr = storage.get();
+ ContractManager manager(std::move(storage));
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+
+ Address transfer_receiver = get_random_address();
+ Address transfer_receiver2 = get_random_address();
+ LOG(ERROR) << "owner address:" << owner_address_;
+ LOG(ERROR) << "receive 1:" << transfer_receiver;
+ LOG(ERROR) << "receive 2:" << transfer_receiver2;
+
+ uint256_t owner_key = GetAddressHash(owner_address_);
+ uint256_t transfer_key = GetAddressHash(transfer_receiver);
+ uint256_t transfer2_key = GetAddressHash(transfer_receiver2);
+
+ // owner 1000
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(owner_address_));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ LOG(ERROR) << "result:" << *result;
+ EXPECT_EQ(HexToInt(*result), 1000);
+
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 1000);
+ }
+
+ /*
+ // receiver 0
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(transfer_receiver));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 0);
+
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 0);
+ }
+
+ // transfer 400 to receiver
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(400));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1);
+
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 400);
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 600);
+ }
+
+ // owner 600
+ {
+ Address caller = get_random_address();
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(owner_address_));
+
+ auto result = manager.ExecContract(caller, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 600);
+
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 400);
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 600);
+ }
+
+ // transfer 200 to receiver2 from receiver
+ {
+ Params func_params;
+ func_params.set_func_name("approve(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(100));
+
+ auto result =
+ manager.ExecContract(transfer_receiver, contract_address,
+ func_params); EXPECT_EQ(HexToInt(*result), 1);
+
+ EXPECT_EQ(storage_ptr->Load(transfer2_key).first, 0);
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 400);
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 600);
+ }
+ {
+ Params func_params;
+ func_params.set_func_name("transferFrom(address,address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(transfer_receiver2));
+ func_params.add_param(U256ToString(100));
+
+ auto result =
+ manager.ExecContract(transfer_receiver, contract_address,
+ func_params); EXPECT_EQ(HexToInt(*result), 1);
+
+ EXPECT_EQ(storage_ptr->Load(transfer2_key).first, 100);
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 300);
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 600);
+ }
+ */
+}
+/*
+
+TEST_F(MultiContractExecutorTest, ExecMultiContractNoConflict) {
+
+ std::unique_ptr<DataStorage> storage = std::make_unique<DataStorage>();
+ DataStorage * storage_ptr = storage.get();
+ ContractManager manager(std::move(storage));
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+
+
+ Address transfer_receiver = get_random_address();
+ Address transfer_receiver2 = get_random_address();
+ Address transfer_receiver3 = get_random_address();
+
+ uint256_t owner_key = GetAddressHash(owner_address_);
+ uint256_t transfer_key = GetAddressHash(transfer_receiver);
+ uint256_t transfer2_key = GetAddressHash(transfer_receiver2);
+ uint256_t transfer3_key = GetAddressHash(transfer_receiver3);
+
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(400));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1);
+
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 400);
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 600);
+ }
+
+ // transfer 200 to receiver2 from receiver
+ {
+ Params func_params;
+ func_params.set_func_name("approve(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(200));
+
+ auto result =
+ manager.ExecContract(transfer_receiver, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1);
+ }
+
+ std::vector<ContractExecuteInfo> info;
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver3));
+ func_params.add_param(U256ToString(100));
+
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address, "",
+func_params, 0));
+ }
+
+ {
+ Params func_params;
+ func_params.set_func_name("transferFrom(address,address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(transfer_receiver2));
+ func_params.add_param(U256ToString(200));
+
+ info.push_back(ContractExecuteInfo(transfer_receiver, contract_address, "",
+func_params, 0));
+ }
+ std::vector<std::unique_ptr<ExecuteResp>> resp = manager.ExecContract(info);
+ EXPECT_EQ(storage_ptr->Load(transfer2_key).first, 200);
+ EXPECT_EQ(storage_ptr->Load(transfer3_key).first, 100);
+
+ LOG(ERROR)<<"resp size:"<<resp.size();
+ EXPECT_EQ(resp.size(), 2);
+ EXPECT_EQ(resp[0]->ret, 0);
+ EXPECT_EQ(resp[1]->ret, 0);
+
+ EXPECT_EQ(HexToInt(resp[0]->result), 1);
+ EXPECT_EQ(HexToInt(resp[1]->result), 1);
+}
+
+TEST_F(MultiContractExecutorTest, ExecMultiContractHaveConflict) {
+
+ std::unique_ptr<DataStorage> storage = std::make_unique<DataStorage>();
+ DataStorage * storage_ptr = storage.get();
+ ContractManager manager(std::move(storage));
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+
+
+ Address transfer_receiver = get_random_address();
+ Address transfer_receiver2 = get_random_address();
+ Address transfer_receiver3 = get_random_address();
+
+ uint256_t owner_key = GetAddressHash(owner_address_);
+ uint256_t transfer_key = GetAddressHash(transfer_receiver);
+ uint256_t transfer2_key = GetAddressHash(transfer_receiver2);
+ uint256_t transfer3_key = GetAddressHash(transfer_receiver3);
+
+ std::vector<ContractExecuteInfo> info;
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(100));
+
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address, "",
+func_params, 0));
+ }
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver2));
+ func_params.add_param(U256ToString(100));
+
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address, "",
+func_params, 0));
+ }
+
+ std::vector<std::unique_ptr<ExecuteResp>> resp = manager.ExecContract(info);
+ EXPECT_EQ(storage_ptr->Load(owner_key).first, 800);
+ EXPECT_EQ(storage_ptr->Load(transfer_key).first, 100);
+ EXPECT_EQ(storage_ptr->Load(transfer2_key).first, 100);
+
+ LOG(ERROR)<<"resp size:"<<resp.size();
+ EXPECT_EQ(resp.size(), 2);
+ EXPECT_EQ(resp[0]->ret, 0);
+ EXPECT_EQ(resp[1]->ret, 0);
+
+ EXPECT_EQ(HexToInt(resp[0]->result), 1);
+ EXPECT_EQ(HexToInt(resp[1]->result), 1);
+}
+*/
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager.cpp
new file mode 100644
index 000000000..c6e397da1
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/contract_manager.h"
+
+#include "service/contract/executor/manager/address_manager.h"
+#include "service/contract/executor/manager/two_phase_committer.h"
+//#include
+//"service/contract/executor/manager/sequential_concurrency_committer.h"
+#include <glog/logging.h>
+
+#include "eEVM/processor.h"
+#include "service/contract/executor/manager/ooo_committer.h"
+#include "service/contract/executor/manager/streaming_committer.h"
+#include "service/contract/executor/manager/streaming_dq_committer.h"
+#include "service/contract/executor/manager/streaming_single_committer.h"
+#include "service/contract/executor/manager/two_phase_ooo_committer.h"
+#include "service/contract/executor/manager/x_committer.h"
+#include "service/contract/executor/manager/x_verifier.h"
+
+namespace resdb {
+namespace contract {
+
+ContractManager::ContractManager(std::unique_ptr<DataStorage> storage,
+ int worker_num, Options op) {
+ storage_ = std::move(storage);
+ gs_ = std::make_unique<GlobalState>(storage_.get());
+
+ switch (op) {
+ case TwoPL:
+ committer_ = std::make_unique<TwoPhaseCommitter>(storage_.get(),
+ gs_.get(), worker_num);
+ break;
+ case TwoPLOOO:
+ committer_ = std::make_unique<TwoPhaseOOOCommitter>(
+ storage_.get(), gs_.get(), worker_num);
+ break;
+ case OOO:
+ committer_ =
+ std::make_unique<OOOCommitter>(storage_.get(), gs_.get(), worker_num);
+ break;
+ case Streaming:
+ committer_ = std::make_unique<streaming::StreamingCommitter>(
+ storage_.get(), gs_.get(), 500, nullptr, worker_num);
+ break;
+ case SCC:
+ // committer_ =
+ // std::make_unique<SequentialConcurrencyCommitter>(storage_.get(),
+ // gs_.get(), worker_num);
+ break;
+ case SingleStreaming:
+ committer_ = std::make_unique<streaming::StreamingSingleCommitter>(
+ storage_.get(), gs_.get(), worker_num);
+ break;
+ case MultiStreaming:
+ committer_ = std::make_unique<streaming::StreamingDQCommitter>(
+ storage_.get(), gs_.get(), 1500, nullptr, worker_num);
+ break;
+ case XE:
+ committer_ =
+ std::make_unique<XCommitter>(storage_.get(), gs_.get(), worker_num);
+ break;
+ case XEO:
+ committer_ =
+ std::make_unique<XCommitter>(storage_.get(), gs_.get(), worker_num);
+ //((XCommitter*)committer_.get())->UseOCC();
+ break;
+ }
+
+ deployer_ = std::make_unique<ContractDeployer>(committer_.get(), gs_.get());
+
+ verifier_ =
+ std::make_unique<XVerifier>(storage_.get(), gs_.get(), worker_num);
+}
+
+void ContractManager::SetExecuteCallBack(
+ std::function<void(std::unique_ptr<ExecuteResp> resp)> func) {
+ committer_->SetExecuteCallBack(std::move(func));
+}
+
+Address ContractManager::DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info) {
+ return deployer_->DeployContract(owner_address, deploy_info);
+}
+
+bool ContractManager::DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info,
+ const Address& contract_address) {
+ return deployer_->DeployContract(owner_address, deploy_info,
+ contract_address);
+}
+
+absl::StatusOr<eevm::AccountState> ContractManager::GetContract(
+ const Address& address) {
+ return deployer_->GetContract(address);
+}
+
+std::vector<std::unique_ptr<ExecuteResp>> ContractManager::ExecContract(
+ std::vector<ContractExecuteInfo>& execute_info) {
+ std::map<std::string, std::set<int>> ct;
+ std::map<int, int> cct;
+ for (int i = 0; i < execute_info.size(); ++i) {
+ std::string func_addr =
+ deployer_->GetFuncAddress(execute_info[i].contract_address,
+ execute_info[i].func_params.func_name());
+ if (func_addr.empty()) {
+ LOG(ERROR) << "no fouction:" << execute_info[i].func_params.func_name();
+ execute_info[i].contract_address = 0;
+ continue;
+ }
+ execute_info[i].func_addr = func_addr;
+ execute_info[i].commit_id = i + 1;
+ }
+
+ return committer_->ExecContract(execute_info);
+}
+
+void ContractManager::AsyncExecContract(
+ std::vector<ContractExecuteInfo>& execute_info) {
+ std::map<std::string, std::set<int>> ct;
+ std::map<int, int> cct;
+ for (int i = 0; i < execute_info.size(); ++i) {
+ std::string func_addr =
+ deployer_->GetFuncAddress(execute_info[i].contract_address,
+ execute_info[i].func_params.func_name());
+ if (func_addr.empty()) {
+ LOG(ERROR) << "no fouction:" << execute_info[i].func_params.func_name();
+ execute_info[i].contract_address = 0;
+ continue;
+ }
+ execute_info[i].func_addr = func_addr;
+ execute_info[i].commit_id = i + 1;
+
+ /*
+ cct[i]=0;
+ if(execute_info[i].func_params.param_size()>0){
+ for(int j = 0; j < execute_info[i].func_params.param_size()-1; j++){
+ auto& p = execute_info[i].func_params.param(j);
+ //LOG(ERROR)<<"get idx:"<<i<<" param:"<<p;
+ ct[p].insert(i);
+ }
+ }
+ */
+ }
+
+ /*
+ for(auto it : ct){
+ if(it.second.size()>2){
+ for(auto id : it.second){
+ cct[id]=1;
+ }
+ }
+ }
+
+ int tot = 0, num = 0;
+ for(auto x : cct){
+ if(x.second==1)num++;
+ tot++;
+ }
+ LOG(ERROR)<<"tot:"<<tot<<" num:"<<num<<" p:"<<(double)num/tot;
+ */
+
+ committer_->AsyncExecContract(execute_info);
+}
+
+absl::StatusOr<std::string> ContractManager::ExecContract(
+ const Address& caller_address, const Address& contract_address,
+ const Params& func_param) {
+ std::string func_addr =
+ deployer_->GetFuncAddress(contract_address, func_param.func_name());
+ if (func_addr.empty()) {
+ LOG(ERROR) << "no fouction:" << func_param.func_name();
+ return absl::InvalidArgumentError("Func not exist.");
+ }
+
+ absl::StatusOr<std::string> result = committer_->ExecContract(
+ caller_address, contract_address, func_addr, func_param, gs_.get());
+ if (result.ok()) {
+ return *result;
+ }
+ return result.status();
+}
+
+bool ContractManager::VerifyContract(
+ std::vector<ContractExecuteInfo>& ordered_info,
+ std::vector<ConcurrencyController ::ModifyMap> rws_list) {
+ return true;
+ for (int i = 0; i < ordered_info.size(); ++i) {
+ std::string func_addr =
+ deployer_->GetFuncAddress(ordered_info[i].contract_address,
+ ordered_info[i].func_params.func_name());
+ if (func_addr.empty()) {
+ LOG(ERROR) << "no fouction:" << ordered_info[i].func_params.func_name();
+ ordered_info[i].contract_address = 0;
+ continue;
+ }
+ ordered_info[i].func_addr = func_addr;
+ }
+ return verifier_->VerifyContract(ordered_info, rws_list);
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager.h b/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager.h
new file mode 100644
index 000000000..ac19e5ffc
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "absl/status/statusor.h"
+#include "eEVM/opcode.h"
+#include "service/contract/executor/common/utils.h"
+#include "service/contract/executor/manager/contract_committer.h"
+#include "service/contract/executor/manager/contract_deployer.h"
+#include "service/contract/executor/manager/contract_verifier.h"
+#include "service/contract/executor/manager/global_state.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+class ContractManager {
+ public:
+ enum Options {
+ TwoPL = 1,
+ SCC = 2,
+ OOO = 3,
+ TwoPLOOO = 4,
+ Streaming = 5,
+ SingleStreaming = 6,
+ MultiStreaming = 7,
+ XE = 8,
+ XEO = 9,
+ };
+ ContractManager(std::unique_ptr<DataStorage> storage, int worker_num = 2,
+ Options op = TwoPL);
+
+ public:
+ Address DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info);
+
+ bool DeployContract(const Address& owner_address,
+ const DeployInfo& deploy_info,
+ const Address& contract_address);
+
+ absl::StatusOr<eevm::AccountState> GetContract(const Address& address);
+
+ absl::StatusOr<std::string> ExecContract(const Address& caller_address,
+ const Address& contract_address,
+ const Params& func_param);
+
+ std::vector<std::unique_ptr<ExecuteResp>> ExecContract(
+ std::vector<ContractExecuteInfo>& execute_info);
+
+ void AsyncExecContract(std::vector<ContractExecuteInfo>& execute_info);
+
+ void SetExecuteCallBack(
+ std::function<void(std::unique_ptr<ExecuteResp> resp)> func);
+
+ bool VerifyContract(std::vector<ContractExecuteInfo>& ordered_info,
+ std::vector<ConcurrencyController ::ModifyMap> rws_list);
+
+ private:
+ std::string GetFuncAddress(const Address& contract_address,
+ const std::string& func_name);
+ void SetFuncAddress(const Address& contract_address, const FuncInfo& func);
+
+ private:
+ std::unique_ptr<DataStorage> storage_;
+ std::unique_ptr<GlobalState> gs_;
+ std::unique_ptr<ContractCommitter> committer_;
+ std::unique_ptr<ContractDeployer> deployer_;
+ std::unique_ptr<ContractVerifier> verifier_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager_test.cpp
new file mode 100644
index 000000000..8373ceef4
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_manager_test.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/contract_manager.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "service/contract/executor/manager/address_manager.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Test;
+
+const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
+ std::string(getenv("TEST_WORKSPACE")) +
+ "/service/contract/executor/manager/";
+
+Address get_random_address() { return AddressManager().CreateRandomAddress(); }
+
+std::string U256ToString(uint256_t v) { return eevm::to_hex_string(v); }
+uint256_t HexToInt(const std::string& v) { return eevm::to_uint256(v); }
+
+class ContractManagerTest : public Test {
+ public:
+ ContractManagerTest() : owner_address_(get_random_address()) {
+ LOG(ERROR) << "owner:" << owner_address_;
+ std::string contract_path = test_dir + "test_data/contract.json";
+
+ std::ifstream contract_fstream(contract_path);
+ if (!contract_fstream) {
+ throw std::runtime_error(fmt::format(
+ "Unable to open contract definition file {}", contract_path));
+ }
+
+ const auto contracts_definition = nlohmann::json::parse(contract_fstream);
+ const auto all_contracts = contracts_definition["contracts"];
+ const auto contract_code = all_contracts["ERC20.sol:ERC20Token"];
+ contract_json_ = contract_code;
+ }
+
+ protected:
+ Address owner_address_;
+ nlohmann::json contract_json_;
+};
+
+TEST_F(ContractManagerTest, NoContract) {
+ ContractManager manager(std::make_unique<DataStorage>());
+ auto account = manager.GetContract(1234);
+ EXPECT_FALSE(account.ok());
+}
+
+TEST_F(ContractManagerTest, DeployContract) {
+ ContractManager manager(std::make_unique<DataStorage>());
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+}
+
+TEST_F(ContractManagerTest, InitContract) {
+ ContractManager manager(std::make_unique<DataStorage>());
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+
+ LOG(ERROR) << " deploy done:" << owner_address_;
+ Params func_params;
+ func_params.set_func_name("totalSupply()");
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1000);
+}
+
+TEST_F(ContractManagerTest, ExecContract) {
+ ContractManager manager(std::make_unique<DataStorage>());
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+
+ Address transfer_receiver = get_random_address();
+ Address transfer_receiver2 = get_random_address();
+
+ // owner 1000
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(owner_address_));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1000);
+ }
+
+ // receiver 0
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(transfer_receiver));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 0);
+ }
+
+ // transfer 400 to receiver
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(400));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1);
+ }
+
+ // receiver 400
+ {
+ Address caller = get_random_address();
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(transfer_receiver));
+
+ auto result = manager.ExecContract(caller, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 400);
+ }
+ // owner 600
+ {
+ Address caller = get_random_address();
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(owner_address_));
+
+ auto result = manager.ExecContract(caller, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 600);
+ }
+
+ // transfer 200 to receiver2 from receiver
+ {
+ Params func_params;
+ func_params.set_func_name("approve(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(200));
+
+ auto result =
+ manager.ExecContract(transfer_receiver, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1);
+ }
+ {
+ Params func_params;
+ func_params.set_func_name("transferFrom(address,address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(transfer_receiver2));
+ func_params.add_param(U256ToString(200));
+
+ auto result =
+ manager.ExecContract(transfer_receiver, contract_address, func_params);
+ EXPECT_EQ(HexToInt(*result), 1);
+ }
+}
+
+TEST_F(ContractManagerTest, NoFunc) {
+ ContractManager manager(std::make_unique<DataStorage>());
+
+ DeployInfo deploy_info;
+ deploy_info.set_contract_bin(contract_json_["bin"]);
+ for (auto& func : contract_json_["hashes"].items()) {
+ FuncInfo* new_func = deploy_info.add_func_info();
+ new_func->set_func_name(func.key());
+ new_func->set_hash(func.value());
+ }
+
+ deploy_info.add_init_param(U256ToString(1000));
+
+ Address contract_address =
+ manager.DeployContract(owner_address_, deploy_info);
+ EXPECT_GT(contract_address, 0);
+ auto account = manager.GetContract(contract_address);
+ EXPECT_TRUE(account.ok());
+
+ // owner 1000
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf()");
+ func_params.add_param(U256ToString(owner_address_));
+
+ auto result =
+ manager.ExecContract(owner_address_, contract_address, func_params);
+ EXPECT_FALSE(result.ok());
+ }
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_verifier.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/contract_verifier.cpp
new file mode 100644
index 000000000..451c0c3f4
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_verifier.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/contract_verifier.h"
+
+namespace resdb {
+namespace contract {
+
+ContractVerifier::ContractVerifier() {
+ executor_ = std::make_unique<ContractExecutor>();
+}
+
+ContractVerifier::~ContractVerifier() {}
+
+std::vector<std::unique_ptr<ExecuteResp>> ContractVerifier::ExecContract(
+ std::vector<ContractExecuteInfo>& request) {
+ return std::vector<std::unique_ptr<ExecuteResp>>();
+}
+
+absl::StatusOr<std::string> ContractVerifier::ExecContract(
+ const Address& caller_address, const Address& contract_address,
+ const std::string& func_addr, const Params& func_param, EVMState* state) {
+ return executor_->ExecContract(caller_address, contract_address, func_addr,
+ func_param, state);
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/contract_verifier.h b/platform/consensus/ordering/thunderbolt/executor/manager/contract_verifier.h
new file mode 100644
index 000000000..04b88e950
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/contract_verifier.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "absl/status/statusor.h"
+#include "service/contract/executor/manager/committer_context.h"
+#include "service/contract/executor/manager/contract_committer.h"
+#include "service/contract/executor/manager/contract_executor.h"
+
+namespace resdb {
+namespace contract {
+
+class ContractVerifier : public ContractCommitter {
+ public:
+ ContractVerifier();
+ virtual ~ContractVerifier();
+
+ virtual bool VerifyContract(
+ const std::vector<ContractExecuteInfo>& request_list,
+ const std::vector<ConcurrencyController ::ModifyMap>& rws_list) = 0;
+
+ std::vector<std::unique_ptr<ExecuteResp>> ExecContract(
+ std::vector<ContractExecuteInfo>& request) override;
+
+ absl::StatusOr<std::string> ExecContract(const Address& caller_address,
+ const Address& contract_address,
+ const std::string& func_addr,
+ const Params& func_param,
+ EVMState* state) override;
+
+ protected:
+ std::unique_ptr<ContractExecutor> executor_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/d_storage.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/d_storage.cpp
new file mode 100644
index 000000000..eade73c28
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/d_storage.cpp
@@ -0,0 +1,162 @@
+#include "service/contract/executor/manager/d_storage.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+namespace {
+
+int GetHashKey(const uint256_t& address) {
+ // Get big-endian form
+ const uint8_t* bytes = intx::as_bytes(address);
+ // uint8_t arr[32] = {};
+ // memset(arr,0,sizeof(arr));
+ // intx::be::store(arr, address);
+ // const uint8_t* bytes = arr;
+ size_t sz = sizeof(address);
+ int v = 0;
+ for (int i = 0; i < sz; ++i) {
+ v += bytes[i];
+ }
+ return v % 1024;
+}
+
+void InternalReset(const uint256_t& key, const uint256_t& value,
+ int64_t version,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ (*db)[key] = std::make_pair(value, version);
+}
+
+int64_t InternalStore(const uint256_t& key, const uint256_t& value,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ int64_t v = (*db)[key].second;
+ (*db)[key] = std::make_pair(value, v + 1);
+ // LOG(ERROR)<<"store key:"<<key<<" v:"<<v+1;
+ return v + 1;
+}
+
+std::pair<uint256_t, int64_t> InternalLoad(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ auto e = db->find(key);
+ if (e == db->end()) return std::make_pair(0, 0);
+ return e->second;
+}
+
+bool InternalRemove(const uint256_t& key,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ auto e = db->find(key);
+ if (e == db->end()) return false;
+ db->erase(e);
+ return true;
+}
+
+bool InternalExist(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ return db->find(key) != db->end();
+}
+
+int64_t InternalGetVersion(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ auto it = db->find(key);
+ if (it == db->end()) {
+ // LOG(ERROR)<<"get version key:"<<key<<" v:"<<0;
+ return 0;
+ }
+ // LOG(ERROR)<<"get version key:"<<key<<" v:"<<it->second.second;
+ return it->second.second;
+}
+
+} // namespace
+
+int64_t D_Storage::Store(const uint256_t& key, const uint256_t& value,
+ bool is_to_local_view) {
+ // LOG(ERROR)<<"store key:"<<key<<" value:"<<value<<"
+ // local:"<<is_to_local_view;
+ int idx = GetHashKey(key);
+ if (is_to_local_view) {
+ return InternalStore(key, value, &c_s_[idx], &mutex_[idx]);
+ } else {
+ return InternalStore(key, value, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+std::pair<uint256_t, int64_t> D_Storage::Load(const uint256_t& key,
+ bool is_local_view) const {
+ // LOG(ERROR)<<"load key:"<<key<<" local:"<<is_local_view;
+ int idx = GetHashKey(key);
+ if (is_local_view) {
+ auto ret = InternalLoad(key, &c_s_[idx], &mutex_[idx]);
+ if (ret.second == 0) {
+ // LOG(ERROR)<<"get from global:";
+ return InternalLoad(key, &g_s_[idx], &mutex_[idx]);
+ }
+ return ret;
+ } else {
+ return InternalLoad(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+bool D_Storage::Remove(const uint256_t& key, bool is_local) {
+ int idx = GetHashKey(key);
+ if (is_local) {
+ return InternalRemove(key, &c_s_[idx], &mutex_[idx]);
+ } else {
+ return InternalRemove(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+bool D_Storage::Exist(const uint256_t& key, bool is_local) const {
+ int idx = GetHashKey(key);
+ if (is_local) {
+ return InternalExist(key, &c_s_[idx], &mutex_[idx]);
+ } else {
+ return InternalExist(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+int64_t D_Storage::GetVersion(const uint256_t& key, bool is_local) const {
+ // LOG(ERROR)<<"get version key:"<<key<<" islocal:"<<is_local;
+ int idx = GetHashKey(key);
+ if (is_local) {
+ int ret = InternalGetVersion(key, &c_s_[idx], &mutex_[idx]);
+ if (ret == 0) {
+ ret = InternalGetVersion(key, &g_s_[idx], &g_mutex_[idx]);
+ // LOG(ERROR)<<"get from global:"<<ret;
+ }
+ // LOG(ERROR)<<"get version key:"<<key<<" islocal:"<<is_local<<" v:"<<ret;
+ return ret;
+ } else {
+ return InternalGetVersion(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+void D_Storage::Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local) {
+ // LOG(ERROR)<<"set key:"<<key<<" value:"<<value<<" local:"<<is_local<<"
+ // version:"<<version;
+ int idx = GetHashKey(key);
+ if (is_local) {
+ InternalReset(key, value, version, &c_s_[idx], &mutex_[idx]);
+ } else {
+ InternalReset(key, value, version, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/d_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/d_storage.h
new file mode 100644
index 000000000..1ae1d775c
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/d_storage.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "eEVM/util.h"
+#include "service/contract/executor/manager/data_storage.h"
+
+namespace resdb {
+namespace contract {
+
+class D_Storage : public DataStorage {
+ public:
+ virtual int64_t Store(const uint256_t& key, const uint256_t& value,
+ bool is_local);
+ virtual std::pair<uint256_t, int64_t> Load(const uint256_t& key,
+ bool is_from_local_view) const;
+ virtual bool Remove(const uint256_t& key, bool is_local);
+ virtual bool Exist(const uint256_t& key, bool is_local) const;
+
+ virtual int64_t GetVersion(const uint256_t& key, bool is_local) const;
+
+ virtual void Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local);
+
+ protected:
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > c_s_[1024];
+ mutable std::shared_mutex mutex_[1024];
+
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > g_s_[1024];
+ mutable std::shared_mutex g_mutex_[1024];
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/data_storage.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/data_storage.cpp
new file mode 100644
index 000000000..f1719209e
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/data_storage.cpp
@@ -0,0 +1,72 @@
+#include "service/contract/executor/manager/data_storage.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+namespace {
+
+int GetHashKey(const uint256_t& address) {
+ // Get big-endian form
+ const uint8_t* bytes = intx::as_bytes(address);
+ // uint8_t arr[32] = {};
+ // memset(arr,0,sizeof(arr));
+ // intx::be::store(arr, address);
+ // const uint8_t* bytes = arr;
+ size_t sz = sizeof(address);
+ int v = 0;
+ for (int i = 0; i < sz; ++i) {
+ v += bytes[i];
+ }
+ return 0;
+ return v % 2048;
+}
+} // namespace
+
+int64_t DataStorage::Store(const uint256_t& key, const uint256_t& value, bool) {
+ int idx = GetHashKey(key);
+ std::unique_lock lock(mutex_[idx]);
+ // LOG(ERROR)<<"store key:"<<key<<" value:"<<value;
+ int64_t v = s[key].second;
+ s[key] = std::make_pair(value, v + 1);
+ return v + 1;
+}
+
+std::pair<uint256_t, int64_t> DataStorage::Load(const uint256_t& key,
+ bool) const {
+ int idx = GetHashKey(key);
+ std::shared_lock lock(mutex_[idx]);
+ // LOG(ERROR)<<"load key:"<<key;
+ auto e = s.find(key);
+ if (e == s.end()) return std::make_pair(0, 0);
+ return e->second;
+}
+
+bool DataStorage::Remove(const uint256_t& key, bool) {
+ int idx = GetHashKey(key);
+ std::unique_lock lock(mutex_[idx]);
+ auto e = s.find(key);
+ if (e == s.end()) return false;
+ s.erase(e);
+ return true;
+}
+
+bool DataStorage::Exist(const uint256_t& key, bool) const {
+ int idx = GetHashKey(key);
+ std::shared_lock lock(mutex_[idx]);
+ return s.find(key) != s.end();
+}
+
+int64_t DataStorage::GetVersion(const uint256_t& key, bool) const {
+ int idx = GetHashKey(key);
+ std::shared_lock lock(mutex_[idx]);
+ auto it = s.find(key);
+ if (it == s.end()) {
+ return 0;
+ }
+ return it->second.second;
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/data_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/data_storage.h
new file mode 100644
index 000000000..f3c72de0a
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/data_storage.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "eEVM/util.h"
+
+namespace resdb {
+namespace contract {
+
+class DataStorage {
+ public:
+ DataStorage() = default;
+ virtual ~DataStorage() = default;
+
+ virtual int64_t Store(const uint256_t& key, const uint256_t& value,
+ bool is_local = false);
+ virtual std::pair<uint256_t, int64_t> Load(const uint256_t& key,
+ bool is_local_view = false) const;
+ virtual bool Remove(const uint256_t& key, bool is_local = false);
+ virtual bool Exist(const uint256_t& key, bool is_local = false) const;
+
+ virtual int64_t GetVersion(const uint256_t& key, bool is_local = false) const;
+
+ virtual void Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local = false) {}
+ virtual void Flush(){};
+
+ protected:
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > s;
+ // std::map<uint256_t, std::pair<uint256_t,int64_t> > s[4096];
+ mutable std::shared_mutex mutex_[4096];
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/evm_state.h b/platform/consensus/ordering/thunderbolt/executor/manager/evm_state.h
new file mode 100644
index 000000000..b1897765b
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/evm_state.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "eEVM/globalstate.h"
+
+namespace resdb {
+namespace contract {
+
+class EVMState : public eevm::GlobalState {
+ public:
+ EVMState() = default;
+ virtual ~EVMState() = default;
+
+ protected:
+ const eevm::Block& get_current_block() override { return block_; }
+ uint256_t get_block_hash(uint8_t offset) override { return 0; }
+
+ private:
+ // Unused.
+ eevm::Block block_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/global_state.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/global_state.cpp
new file mode 100644
index 000000000..423980006
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/global_state.cpp
@@ -0,0 +1,46 @@
+#include "service/contract/executor/manager/global_state.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+using eevm::AccountState;
+using eevm::Address;
+using eevm::Code;
+using eevm::SimpleAccount;
+
+GlobalState::GlobalState(DataStorage* storage) : storage_(storage) {}
+
+bool GlobalState::Exists(const eevm::Address& addr) {
+ return accounts.find(addr) != accounts.cend();
+}
+
+void GlobalState::remove(const Address& addr) { accounts.erase(addr); }
+
+AccountState GlobalState::get(const Address& addr) {
+ const auto acc = accounts.find(addr);
+ if (acc != accounts.cend()) return acc->second;
+
+ return create(addr, 0, {});
+}
+
+AccountState GlobalState::create(const Address& addr, const uint256_t& balance,
+ const Code& code) {
+ Insert({SimpleAccount(addr, balance, code), GlobalView(storage_)});
+
+ return get(addr);
+}
+
+const eevm::SimpleAccount& GlobalState::GetAccount(const eevm::Address& addr) {
+ const auto acc = accounts.find(addr);
+ return acc->second.first;
+}
+
+void GlobalState::Insert(const StateEntry& p) {
+ const auto ib = accounts.insert(std::make_pair(p.first.get_address(), p));
+
+ assert(ib.second);
+}
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/global_state.h b/platform/consensus/ordering/thunderbolt/executor/manager/global_state.h
new file mode 100644
index 000000000..c3c9ca7f7
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/global_state.h
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "eEVM/simple/simpleaccount.h"
+#include "service/contract/executor/manager/evm_state.h"
+#include "service/contract/executor/manager/global_view.h"
+
+namespace resdb {
+namespace contract {
+
+class GlobalState : public EVMState {
+ public:
+ using StateEntry = std::pair<eevm::SimpleAccount, GlobalView>;
+
+ public:
+ GlobalState(DataStorage* storage);
+ virtual ~GlobalState() = default;
+
+ virtual void remove(const eevm::Address& addr) override;
+
+ // Get contract by contract address.
+ eevm::AccountState get(const eevm::Address& addr) override;
+
+ bool Exists(const eevm::Address& addr);
+
+ // Create an account for the contract, which the balance is 0.
+ eevm::AccountState create(const eevm::Address& addr, const uint256_t& balance,
+ const eevm::Code& code) override;
+
+ const eevm::SimpleAccount& GetAccount(const eevm::Address& addr);
+
+ protected:
+ void Insert(const StateEntry& p);
+
+ private:
+ std::map<eevm::Address, StateEntry> accounts;
+ DataStorage* storage_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/global_view.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/global_view.cpp
new file mode 100644
index 000000000..5bd892496
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/global_view.cpp
@@ -0,0 +1,23 @@
+#include "service/contract/executor/manager/global_view.h"
+
+#include <glog/logging.h>
+
+#include "eEVM/util.h"
+
+namespace resdb {
+namespace contract {
+
+GlobalView::GlobalView(DataStorage* storage) : storage_(storage) {}
+
+void GlobalView::store(const uint256_t& key, const uint256_t& value) {
+ storage_->Store(key, value);
+}
+
+uint256_t GlobalView::load(const uint256_t& key) {
+ return storage_->Load(key).first;
+}
+
+bool GlobalView::remove(const uint256_t& key) { return storage_->Remove(key); }
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/global_view.h b/platform/consensus/ordering/thunderbolt/executor/manager/global_view.h
new file mode 100644
index 000000000..c54e27408
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/global_view.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <map>
+
+#include "eEVM/storage.h"
+#include "service/contract/executor/manager/data_storage.h"
+
+namespace resdb {
+namespace contract {
+
+class GlobalView : public eevm::Storage {
+ public:
+ GlobalView(DataStorage* storage);
+ virtual ~GlobalView() = default;
+
+ void store(const uint256_t& key, const uint256_t& value) override;
+ uint256_t load(const uint256_t& key) override;
+ bool remove(const uint256_t& key) override;
+
+ private:
+ DataStorage* storage_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/level_d_storage.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/level_d_storage.cpp
new file mode 100644
index 000000000..caabb0eed
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/level_d_storage.cpp
@@ -0,0 +1,207 @@
+#include "service/contract/executor/manager/level_d_storage.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+namespace {
+
+void InternalReset(const uint256_t& key, const uint256_t& value,
+ int64_t version,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ (*db)[key] = std::make_pair(value, version);
+}
+
+int64_t InternalStore(const uint256_t& key, const uint256_t& value,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ int64_t v = (*db)[key].second;
+ (*db)[key] = std::make_pair(value, v + 1);
+ // LOG(ERROR)<<"store key:"<<key<<" v:"<<v+1;
+ return v + 1;
+}
+
+std::pair<uint256_t, int64_t> InternalLoad(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ auto e = db->find(key);
+ if (e == db->end()) return std::make_pair(0, 0);
+ return e->second;
+}
+
+bool InternalRemove(const uint256_t& key,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ auto e = db->find(key);
+ if (e == db->end()) return false;
+ db->erase(e);
+ return true;
+}
+
+bool InternalExist(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ return db->find(key) != db->end();
+}
+
+int64_t InternalGetVersion(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ auto it = db->find(key);
+ if (it == db->end()) {
+ // LOG(ERROR)<<"get version key:"<<key<<" v:"<<0;
+ return 0;
+ }
+ // LOG(ERROR)<<"get version key:"<<key<<" v:"<<it->second.second;
+ return it->second.second;
+}
+
+std::string GetString(const uint256_t& key) { return ""; }
+
+uint256_t GetInt256(const std::string& value) { return 0; }
+
+std::string GetData(const uint256_t& value, int64_t version) {
+ std::string v_str = GetString(value);
+ std::string v((const char*)&version, sizeof(value));
+ v.append(v_str, v_str.size());
+ return v;
+}
+
+int64_t GetVersion(const std::string& value) {
+ int64_t v;
+ memcpy(&v, value.c_str(), sizeof(v));
+ return v;
+}
+
+uint256_t GetValue(const std::string& value) {
+ return GetInt256(std::string(value.c_str() + sizeof(int64_t),
+ value.size() - sizeof(int64_t)));
+}
+
+int64_t InternalStore(const uint256_t& key, const uint256_t& value,
+ ResLevelDB* db, std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ std::string old_value = db->GetValue(GetString(key));
+ int64_t v = GetVersion(old_value);
+ db->SetValue(GetString(key), GetData(value, v + 1));
+ // LOG(ERROR)<<"store key:"<<key<<" v:"<<v+1;
+ return v + 1;
+}
+
+std::pair<uint256_t, int64_t> InternalLoad(const uint256_t& key, ResLevelDB* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ std::string value = db->GetValue(GetString(key));
+ return std::make_pair(GetValue(value), GetVersion(value));
+}
+
+bool InternalRemove(const uint256_t& key, ResLevelDB* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ db->SetValue(GetString(key), "");
+ return true;
+}
+
+bool InternalExist(const uint256_t& key, ResLevelDB* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ std::string value = db->GetValue(GetString(key));
+ return value.empty();
+}
+
+void InternalReset(const uint256_t& key, const uint256_t& value,
+ int64_t version, ResLevelDB* db, std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ db->SetValue(GetString(key), GetData(value, version));
+}
+
+int64_t InternalGetVersion(const uint256_t& key, ResLevelDB* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ std::string value = db->GetValue(GetString(key));
+ return GetVersion(value);
+}
+
+} // namespace
+
+int64_t D_Storage::Store(const uint256_t& key, const uint256_t& value,
+ bool is_to_local_view) {
+ // LOG(ERROR)<<"store key:"<<key<<" value:"<<value<<"
+ // local:"<<is_to_local_view;
+ if (is_to_local_view) {
+ return InternalStore(key, value, &c_s_, &mutex_);
+ } else {
+ return InternalStore(key, value, g_s_.get(), &g_mutex_);
+ }
+}
+
+std::pair<uint256_t, int64_t> D_Storage::Load(const uint256_t& key,
+ bool is_local_view) const {
+ // LOG(ERROR)<<"load key:"<<key<<" local:"<<is_local_view;
+ if (is_local_view) {
+ auto ret = InternalLoad(key, &c_s_, &mutex_);
+ if (ret.second == 0) {
+ // LOG(ERROR)<<"get from global:";
+ return InternalLoad(key, g_s_.get(), &mutex_);
+ }
+ return ret;
+ } else {
+ return InternalLoad(key, g_s_.get(), &g_mutex_);
+ }
+}
+
+bool D_Storage::Remove(const uint256_t& key, bool is_local) {
+ if (is_local) {
+ return InternalRemove(key, &c_s_, &mutex_);
+ } else {
+ return InternalRemove(key, g_s_.get(), &g_mutex_);
+ }
+}
+
+bool D_Storage::Exist(const uint256_t& key, bool is_local) const {
+ if (is_local) {
+ return InternalExist(key, &c_s_, &mutex_);
+ } else {
+ return InternalExist(key, g_s_.get(), &g_mutex_);
+ }
+}
+
+int64_t D_Storage::GetVersion(const uint256_t& key, bool is_local) const {
+ // LOG(ERROR)<<"get version key:"<<key<<" islocal:"<<is_local;
+ if (is_local) {
+ int ret = InternalGetVersion(key, &c_s_, &mutex_);
+ if (ret == 0) {
+ ret = InternalGetVersion(key, g_s_.get(), &g_mutex_);
+ // LOG(ERROR)<<"get from global:"<<ret;
+ }
+ // LOG(ERROR)<<"get version key:"<<key<<" islocal:"<<is_local<<" v:"<<ret;
+ return ret;
+ } else {
+ return InternalGetVersion(key, g_s_.get(), &g_mutex_);
+ }
+}
+
+void D_Storage::Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local) {
+ // LOG(ERROR)<<"set key:"<<key<<" value:"<<value<<" local:"<<is_local<<"
+ // version:"<<version;
+ if (is_local) {
+ InternalReset(key, value, version, &c_s_, &mutex_);
+ } else {
+ InternalReset(key, value, version, g_s_.get(), &g_mutex_);
+ }
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/level_d_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/level_d_storage.h
new file mode 100644
index 000000000..89aba9b64
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/level_d_storage.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "eEVM/util.h"
+#include "service/contract/executor/manager/data_storage.h"
+#include "storage/res_leveldb.h"
+
+namespace resdb {
+namespace contract {
+
+class D_Storage : public DataStorage {
+ public:
+ virtual int64_t Store(const uint256_t& key, const uint256_t& value,
+ bool is_local);
+ virtual std::pair<uint256_t, int64_t> Load(const uint256_t& key,
+ bool is_from_local_view) const;
+ virtual bool Remove(const uint256_t& key, bool is_local);
+ virtual bool Exist(const uint256_t& key, bool is_local) const;
+
+ virtual int64_t GetVersion(const uint256_t& key, bool is_local) const;
+
+ virtual void Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local);
+
+ protected:
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > c_s_;
+ mutable std::shared_mutex mutex_;
+
+ std::unique_ptr<ResLevelDB> g_s_;
+ mutable std::shared_mutex g_mutex_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/leveldb.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb.cpp
new file mode 100644
index 000000000..354f63cb9
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb.cpp
@@ -0,0 +1,30 @@
+#include "service/contract/executor/manager/leveldb.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+LevelDB::LevelDB() {
+ db_ = std::make_unique<ResLevelDB>("./");
+ db_->SetBatchSize(10000);
+}
+
+void LevelDB::Flush() {
+ // LOG(ERROR)<<"flush";
+ for (const auto& it : s) {
+ std::string addr = eevm::to_hex_string(it.first);
+ std::string value = eevm::to_hex_string(it.second.first);
+ // LOG(ERROR)<<"addr:"<<addr<<" value:"<<value;
+ char* buf = new char[value.size() + sizeof(it.second.second)];
+ memcpy(buf, &it.second.second, sizeof(it.second.second));
+ memcpy(buf + sizeof(it.second.second), value.c_str(), value.size());
+
+ db_->SetValue(addr,
+ std::string(buf, value.size() + sizeof(it.second.second)));
+ delete buf;
+ }
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/leveldb.h b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb.h
new file mode 100644
index 000000000..3442cf50e
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "eEVM/util.h"
+#include "service/contract/executor/manager/data_storage.h"
+#include "storage/res_leveldb.h"
+
+namespace resdb {
+namespace contract {
+
+class LevelDB : public DataStorage {
+ public:
+ LevelDB();
+ virtual ~LevelDB() = default;
+
+ virtual void Flush();
+
+ private:
+ std::unique_ptr<ResLevelDB> db_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_d_storage.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_d_storage.cpp
new file mode 100644
index 000000000..2e827e775
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_d_storage.cpp
@@ -0,0 +1,203 @@
+
+#include "service/contract/executor/manager/leveldb_d_storage.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+namespace {
+
+int GetHashKey(const uint256_t& address) {
+ // Get big-endian form
+ const uint8_t* bytes = intx::as_bytes(address);
+ // uint8_t arr[32] = {};
+ // memset(arr,0,sizeof(arr));
+ // intx::be::store(arr, address);
+ // const uint8_t* bytes = arr;
+ size_t sz = sizeof(address);
+ int v = 0;
+ for (int i = 0; i < sz; ++i) {
+ v += bytes[i];
+ }
+ return v % 1024;
+}
+
+void Write(const uint256_t& key, const uint256_t& value, int version,
+ ResLevelDB* db) {
+ std::string addr = eevm::to_hex_string(key);
+
+ const uint8_t* bytes = intx::as_bytes(value);
+ size_t sz = sizeof(value);
+ db->SetValue(addr, std::string((const char*)bytes, sz));
+ return;
+}
+
+uint256_t Read(const uint256_t& key, ResLevelDB* db) {
+ std::string addr = eevm::to_hex_string(key);
+
+ std::string v = db->GetValue(addr);
+ if (v.empty()) {
+ return 0;
+ }
+
+ uint8_t tmp[32] = {};
+ memcpy(tmp, v.c_str(), 32);
+ return intx::le::load<uint256_t>(tmp);
+}
+
+void InternalReset(const uint256_t& key, const uint256_t& value,
+ int64_t version,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex, ResLevelDB* storage) {
+ std::unique_lock lock(*mutex);
+ (*db)[key] = std::make_pair(value, version);
+ if (storage) {
+ Write(key, value, version, storage);
+ }
+}
+
+int64_t InternalStore(const uint256_t& key, const uint256_t& value,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex, ResLevelDB* storage) {
+ std::unique_lock lock(*mutex);
+ int64_t v = (*db)[key].second;
+ (*db)[key] = std::make_pair(value, v + 1);
+ if (storage) {
+ Write(key, value, v + 1, storage);
+ }
+ // LOG(ERROR)<<"store key:"<<key<<" v:"<<v+1;
+ return v + 1;
+}
+
+std::pair<uint256_t, int64_t> InternalLoad(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex, ResLevelDB* storage) {
+ std::shared_lock lock(*mutex);
+ auto e = db->find(key);
+ if (e == db->end()) {
+ if (storage) {
+ // LOG(ERROR)<<"load from db:";
+ return std::make_pair(Read(key, storage), 0);
+ }
+ return std::make_pair(0, 0);
+ }
+ return e->second;
+}
+
+bool InternalRemove(const uint256_t& key,
+ std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::unique_lock lock(*mutex);
+ auto e = db->find(key);
+ if (e == db->end()) return false;
+ db->erase(e);
+ return true;
+}
+
+bool InternalExist(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ return db->find(key) != db->end();
+}
+
+int64_t InternalGetVersion(
+ const uint256_t& key,
+ const std::map<uint256_t, std::pair<uint256_t, int64_t> >* db,
+ std::shared_mutex* mutex) {
+ std::shared_lock lock(*mutex);
+ auto it = db->find(key);
+ if (it == db->end()) {
+ // LOG(ERROR)<<"get version key:"<<key<<" v:"<<0;
+ return 0;
+ }
+ // LOG(ERROR)<<"get version key:"<<key<<" v:"<<it->second.second;
+ return it->second.second;
+}
+
+} // namespace
+
+LevelDB_D_Storage ::LevelDB_D_Storage() {
+ db_ = std::make_unique<ResLevelDB>("./");
+}
+
+int64_t LevelDB_D_Storage::Store(const uint256_t& key, const uint256_t& value,
+ bool is_to_local_view) {
+ // LOG(ERROR)<<"store key:"<<key<<" value:"<<value<<"
+ // local:"<<is_to_local_view;
+ int idx = GetHashKey(key);
+ if (is_to_local_view) {
+ return InternalStore(key, value, &c_s_[idx], &mutex_[idx], nullptr);
+ } else {
+ return InternalStore(key, value, &g_s_[idx], &g_mutex_[idx], db_.get());
+ }
+}
+
+std::pair<uint256_t, int64_t> LevelDB_D_Storage::Load(
+ const uint256_t& key, bool is_local_view) const {
+ // LOG(ERROR)<<"load key:"<<key<<" local:"<<is_local_view;
+ int idx = GetHashKey(key);
+ if (is_local_view) {
+ auto ret = InternalLoad(key, &c_s_[idx], &mutex_[idx], nullptr);
+ if (ret.second == 0) {
+ // LOG(ERROR)<<"get from global:";
+ return InternalLoad(key, &g_s_[idx], &mutex_[idx], db_.get());
+ }
+ return ret;
+ } else {
+ return InternalLoad(key, &g_s_[idx], &g_mutex_[idx], db_.get());
+ }
+}
+
+bool LevelDB_D_Storage::Remove(const uint256_t& key, bool is_local) {
+ int idx = GetHashKey(key);
+ if (is_local) {
+ return InternalRemove(key, &c_s_[idx], &mutex_[idx]);
+ } else {
+ return InternalRemove(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+bool LevelDB_D_Storage::Exist(const uint256_t& key, bool is_local) const {
+ int idx = GetHashKey(key);
+ if (is_local) {
+ return InternalExist(key, &c_s_[idx], &mutex_[idx]);
+ } else {
+ return InternalExist(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+int64_t LevelDB_D_Storage::GetVersion(const uint256_t& key,
+ bool is_local) const {
+ // LOG(ERROR)<<"get version key:"<<key<<" islocal:"<<is_local;
+ int idx = GetHashKey(key);
+ if (is_local) {
+ int ret = InternalGetVersion(key, &c_s_[idx], &mutex_[idx]);
+ if (ret == 0) {
+ ret = InternalGetVersion(key, &g_s_[idx], &g_mutex_[idx]);
+ // LOG(ERROR)<<"get from global:"<<ret;
+ }
+ // LOG(ERROR)<<"get version key:"<<key<<" islocal:"<<is_local<<" v:"<<ret;
+ return ret;
+ } else {
+ return InternalGetVersion(key, &g_s_[idx], &g_mutex_[idx]);
+ }
+}
+
+void LevelDB_D_Storage::Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local) {
+ // LOG(ERROR)<<"set key:"<<key<<" value:"<<value<<" local:"<<is_local<<"
+ // version:"<<version;
+ int idx = GetHashKey(key);
+ if (is_local) {
+ InternalReset(key, value, version, &c_s_[idx], &mutex_[idx], nullptr);
+ } else {
+ InternalReset(key, value, version, &g_s_[idx], &g_mutex_[idx], db_.get());
+ }
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_d_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_d_storage.h
new file mode 100644
index 000000000..4d69165c1
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_d_storage.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "service/contract/executor/manager/data_storage.h"
+#include "storage/res_leveldb.h"
+
+namespace resdb {
+namespace contract {
+
+class LevelDB_D_Storage : public DataStorage {
+ public:
+ LevelDB_D_Storage();
+
+ public:
+ virtual int64_t Store(const uint256_t& key, const uint256_t& value,
+ bool is_local);
+ virtual std::pair<uint256_t, int64_t> Load(const uint256_t& key,
+ bool is_from_local_view) const;
+ virtual bool Remove(const uint256_t& key, bool is_local);
+ virtual bool Exist(const uint256_t& key, bool is_local) const;
+
+ virtual int64_t GetVersion(const uint256_t& key, bool is_local) const;
+
+ virtual void Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local);
+
+ protected:
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > c_s_[1024];
+ mutable std::shared_mutex mutex_[1024];
+
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > g_s_[1024];
+ mutable std::shared_mutex g_mutex_[1024];
+
+ std::unique_ptr<ResLevelDB> db_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_storage.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_storage.cpp
new file mode 100644
index 000000000..d650b1e9d
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_storage.cpp
@@ -0,0 +1,111 @@
+#include "service/contract/executor/manager/leveldb_storage.h"
+
+#include "glog/logging.h"
+
+namespace resdb {
+namespace contract {
+
+namespace {
+
+int GetHashKey(const uint256_t& address) {
+ // Get big-endian form
+ const uint8_t* bytes = intx::as_bytes(address);
+ // uint8_t arr[32] = {};
+ // memset(arr,0,sizeof(arr));
+ // intx::be::store(arr, address);
+ // const uint8_t* bytes = arr;
+ size_t sz = sizeof(address);
+ int v = 0;
+ for (int i = 0; i < sz; ++i) {
+ v += bytes[i];
+ }
+ return 0;
+ return v % 2048;
+}
+} // namespace
+
+LevelDBStorage ::LevelDBStorage() { db_ = std::make_unique<ResLevelDB>("./"); }
+
+void LevelDBStorage::Write(const uint256_t& key, const uint256_t& value,
+ int version) {
+ std::string addr = eevm::to_hex_string(key);
+
+ const uint8_t* bytes = intx::as_bytes(value);
+ size_t sz = sizeof(value);
+ db_->SetValue(addr, std::string((const char*)bytes, sz));
+ return;
+
+ // LOG(ERROR)<<"addr:"<<addr<<" value:"<<value;
+ char* buf = new char[sz + sizeof(version)];
+ memcpy(buf, &version, sizeof(version));
+ memcpy(buf + sizeof(value), bytes, sz);
+
+ db_->SetValue(addr, std::string(buf, sz + sizeof(version)));
+ LOG(ERROR) << "write db";
+ delete buf;
+}
+
+uint256_t LevelDBStorage::Read(const uint256_t& key) const {
+ std::string addr = eevm::to_hex_string(key);
+
+ std::string v = db_->GetValue(addr);
+ if (v.empty()) {
+ return 0;
+ }
+
+ uint8_t tmp[32] = {};
+ memcpy(tmp, v.c_str(), 32);
+ return intx::le::load<uint256_t>(tmp);
+}
+
+int64_t LevelDBStorage::Store(const uint256_t& key, const uint256_t& value,
+ bool) {
+ int idx = GetHashKey(key);
+ std::unique_lock lock(mutex_[idx]);
+ // LOG(ERROR)<<"store key:"<<key<<" value:"<<value;
+ int64_t v = s[idx][key].second;
+ s[idx][key] = std::make_pair(value, v + 1);
+ Write(key, value, v + 1);
+ return v + 1;
+}
+
+std::pair<uint256_t, int64_t> LevelDBStorage::Load(const uint256_t& key,
+ bool) const {
+ int idx = GetHashKey(key);
+ std::shared_lock lock(mutex_[idx]);
+ // LOG(ERROR)<<"load key:"<<key;
+ auto e = s[idx].find(key);
+ if (e == s[idx].end()) {
+ uint256_t v = Read(key);
+ return std::make_pair(v, 0);
+ }
+ return e->second;
+}
+
+bool LevelDBStorage::Remove(const uint256_t& key, bool) {
+ int idx = GetHashKey(key);
+ std::unique_lock lock(mutex_[idx]);
+ auto e = s[idx].find(key);
+ if (e == s[idx].end()) return false;
+ s[idx].erase(e);
+ return true;
+}
+
+bool LevelDBStorage::Exist(const uint256_t& key, bool) const {
+ int idx = GetHashKey(key);
+ std::shared_lock lock(mutex_[idx]);
+ return s[idx].find(key) != s[idx].end();
+}
+
+int64_t LevelDBStorage::GetVersion(const uint256_t& key, bool) const {
+ int idx = GetHashKey(key);
+ std::shared_lock lock(mutex_[idx]);
+ auto it = s[idx].find(key);
+ if (it == s[idx].end()) {
+ return 0;
+ }
+ return it->second.second;
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_storage.h
new file mode 100644
index 000000000..822294c84
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/leveldb_storage.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <map>
+#include <shared_mutex>
+
+#include "service/contract/executor/manager/data_storage.h"
+#include "storage/res_leveldb.h"
+
+namespace resdb {
+namespace contract {
+
+class LevelDBStorage : public DataStorage {
+ public:
+ LevelDBStorage();
+ virtual ~LevelDBStorage() = default;
+
+ virtual int64_t Store(const uint256_t& key, const uint256_t& value,
+ bool is_local = false);
+ virtual std::pair<uint256_t, int64_t> Load(const uint256_t& key,
+ bool is_local_view = false) const;
+ virtual bool Remove(const uint256_t& key, bool is_local = false);
+ virtual bool Exist(const uint256_t& key, bool is_local = false) const;
+
+ virtual int64_t GetVersion(const uint256_t& key, bool is_local = false) const;
+
+ virtual void Reset(const uint256_t& key, const uint256_t& value,
+ int64_t version, bool is_local = false) {}
+ virtual void Flush(){};
+
+ private:
+ void Write(const uint256_t& key, const uint256_t& value, int version);
+ uint256_t Read(const uint256_t& key) const;
+
+ protected:
+ std::map<uint256_t, std::pair<uint256_t, int64_t> > s[4096];
+ mutable std::shared_mutex mutex_[4096];
+ std::unique_ptr<ResLevelDB> db_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/local_state.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/local_state.cpp
new file mode 100644
index 000000000..2b3cd382c
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/local_state.cpp
@@ -0,0 +1,70 @@
+#include "service/contract/executor/manager/local_state.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+using eevm::AccountState;
+using eevm::Address;
+using eevm::Code;
+using eevm::SimpleAccount;
+
+LocalState::LocalState(ConcurrencyController* controller)
+ : controller_(controller) {}
+
+bool LocalState::Exists(const eevm::Address& addr) {
+ return accounts.find(addr) != accounts.cend();
+}
+
+void LocalState::remove(const Address& addr) { accounts.erase(addr); }
+
+AccountState LocalState::get(const Address& addr) {
+ const auto acc = accounts.find(addr);
+ if (acc != accounts.cend()) return acc->second;
+
+ return create(addr, 0, {});
+}
+
+AccountState LocalState::create(const Address& addr, const uint256_t& balance,
+ const Code& code) {
+ Insert({SimpleAccount(addr, balance, code), LocalView(controller_, 0)});
+ return get(addr);
+}
+
+const eevm::SimpleAccount& LocalState::GetAccount(const eevm::Address& addr) {
+ const auto acc = accounts.find(addr);
+ return acc->second.first;
+}
+
+void LocalState::Set(const eevm::SimpleAccount& acc, int64_t commit_id) {
+ Insert({acc, LocalView(controller_, commit_id)});
+}
+
+void LocalState::Insert(const StateEntry& p) {
+ const auto ib = accounts.insert(std::make_pair(p.first.get_address(), p));
+
+ assert(ib.second);
+}
+
+bool LocalState::Flesh(const Address& addr, int commit_id) {
+ const auto acc = accounts.find(addr);
+ if (acc != accounts.cend()) {
+ acc->second.second.Flesh(commit_id);
+ return true;
+ }
+ return false;
+}
+
+/*
+ bool LocalState::Commit(const eevm::Address& addr) {
+ const auto acc = accounts.find(addr);
+ if (acc != accounts.cend()){
+ return acc->second.second.Commit();
+ }
+ return false;
+ }
+ */
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/local_state.h b/platform/consensus/ordering/thunderbolt/executor/manager/local_state.h
new file mode 100644
index 000000000..f98c34c07
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/local_state.h
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "eEVM/simple/simpleaccount.h"
+#include "service/contract/executor/manager/concurrency_controller.h"
+#include "service/contract/executor/manager/evm_state.h"
+#include "service/contract/executor/manager/local_view.h"
+
+namespace resdb {
+namespace contract {
+
+class LocalState : public EVMState {
+ public:
+ using StateEntry = std::pair<eevm::SimpleAccount, LocalView>;
+
+ public:
+ LocalState(ConcurrencyController* controller);
+ virtual ~LocalState() = default;
+
+ virtual void remove(const eevm::Address& addr) override;
+
+ // Get contract by contract address.
+ eevm::AccountState get(const eevm::Address& addr) override;
+
+ bool Exists(const eevm::Address& addr);
+
+ // Flesh the local view to the controller with a commit id.
+ // Once all the contracts have fleshed their changes, they should call commit.
+ // Return false if contract not exists.
+ bool Flesh(const eevm::Address& addr, int commit_id);
+ // Commit the changes using the commit id from the flesh.
+ // bool Commit(const eevm::Address& addr);
+
+ // Create an account for the contract, which the balance is 0.
+ eevm::AccountState create(const eevm::Address& addr, const uint256_t& balance,
+ const eevm::Code& code) override;
+
+ const eevm::SimpleAccount& GetAccount(const eevm::Address& addr);
+ void Set(const eevm::SimpleAccount& acc, int64_t commit_id);
+
+ protected:
+ void Insert(const StateEntry& p);
+
+ private:
+ std::map<eevm::Address, StateEntry> accounts;
+ ConcurrencyController* controller_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/local_view.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/local_view.cpp
new file mode 100644
index 000000000..601b55ff2
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/local_view.cpp
@@ -0,0 +1,77 @@
+#include "service/contract/executor/manager/local_view.h"
+
+#include <glog/logging.h>
+
+#include "eEVM/util.h"
+
+namespace resdb {
+namespace contract {
+
+LocalView::LocalView(ConcurrencyController* controller, int64_t commit_id)
+ : controller_(controller), commit_id_(commit_id) {}
+
+void LocalView::store(const uint256_t& key, const uint256_t& value) {
+ // LOG(ERROR)<<"========= store key:"<<key<<" value:"<<value;
+ auto it = local_changes_.find(key);
+ if (it == local_changes_.end()) {
+ // std::pair<uint256_t,int64_t> load_value =
+ // controller_->GetStorage()->Load(key, /*is_from_local=*/true);
+ local_changes_[key].push_back(Data(STORE, value, 0, 0));
+ } else {
+ const Data& data = local_changes_[key].back();
+ if (data.state == LOAD) {
+ local_changes_[key].push_back(Data(STORE, value, data.version + 1));
+ } else {
+ int64_t v = data.version;
+ local_changes_[key].pop_back();
+ local_changes_[key].push_back(Data(STORE, value, v));
+ }
+ }
+}
+
+uint256_t LocalView::load(const uint256_t& key) {
+ // LOG(ERROR)<<"load key:"<<key;
+ auto it = local_changes_.find(key);
+ if (it == local_changes_.end()) {
+ std::pair<uint256_t, int64_t> value =
+ controller_->GetStorage()->Load(key, /*is_from_local=*/true);
+ local_changes_[key].push_back(Data(LOAD, value.first, value.second));
+ return value.first;
+ }
+ return it->second.back().data;
+}
+
+bool LocalView::remove(const uint256_t& key) {
+ store(key, 0);
+ return true;
+
+ // local_changes_[key].push_back(Data(REMOVE));
+ auto it = local_changes_.find(key);
+ if (it == local_changes_.end()) {
+ std::pair<uint256_t, int64_t> load_value =
+ controller_->GetStorage()->Load(key, /*is_from_local=*/true);
+ local_changes_[key].push_back(
+ Data(REMOVE, 0, load_value.second, load_value.first));
+ } else {
+ const Data& data = local_changes_[key].back();
+ if (data.state == LOAD) {
+ local_changes_[key].push_back(Data(REMOVE, 0, data.version + 1));
+ } else {
+ int64_t v = data.version;
+ local_changes_[key].pop_back();
+ local_changes_[key].push_back(Data(REMOVE, 0, v));
+ }
+ }
+
+ return true;
+}
+
+void LocalView::Flesh(int64_t commit_id) {
+ commit_id_ = commit_id;
+ // LOG(ERROR)<<"commit push:"<<commit_id;
+ controller_->PushCommit(commit_id, local_changes_);
+ local_changes_.clear();
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/local_view.h b/platform/consensus/ordering/thunderbolt/executor/manager/local_view.h
new file mode 100644
index 000000000..047d487d3
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/local_view.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <map>
+
+#include "eEVM/storage.h"
+#include "service/contract/executor/manager/concurrency_controller.h"
+
+namespace resdb {
+namespace contract {
+
+class LocalView : public eevm::Storage {
+ public:
+ LocalView(ConcurrencyController* controller, int64_t commit_id);
+ virtual ~LocalView() = default;
+
+ void store(const uint256_t& key, const uint256_t& value) override;
+ uint256_t load(const uint256_t& key) override;
+ bool remove(const uint256_t& key) override;
+
+ // for 2PL, once it is done, all the commit will be pushed to
+ // the controller to judge if it can be committed.
+ // During the flesh, all the changes will be removed.
+ void Flesh(int64_t commit_id);
+ // Commit the changes. If there is a conflict, return false.
+ // Make sure all other committers have pushed their changes before calling
+ // Commit.
+ // bool Commit();
+ // Remove all the changes.
+ // void Abort();
+
+ private:
+ ConcurrencyController* controller_;
+ int64_t commit_id_;
+ std::map<uint256_t, std::vector<Data>> local_changes_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/local_view_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/local_view_test.cpp
new file mode 100644
index 000000000..017f2b6de
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/local_view_test.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/local_view.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include "service/contract/executor/manager/two_phase_controller.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Test;
+
+uint256_t HexToInt(const std::string& v) { return eevm::to_uint256(v); }
+
+TEST(LocalViewTest, ViewChange) {
+ DataStorage storage;
+ uint256_t address1 = HexToInt("0x123");
+
+ storage.Store(address1, 2000);
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+
+ TwoPhaseController controller(&storage);
+
+ LocalView view(&controller, 0);
+
+ EXPECT_EQ(view.load(address1), 2000);
+ view.store(address1, 3000);
+ EXPECT_EQ(view.load(address1), 3000);
+
+ // storage still contains 2000
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+}
+
+TEST(LocalViewTest, CommitChange) {
+ DataStorage storage;
+ uint256_t address1 = HexToInt("0x123");
+
+ storage.Store(address1, 2000);
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+
+ TwoPhaseController controller(&storage);
+
+ LocalView view(&controller, 0);
+
+ EXPECT_EQ(view.load(address1), 2000);
+ view.store(address1, 3000);
+ EXPECT_EQ(view.load(address1), 3000);
+
+ // storage still contains 2000
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+
+ view.Flesh(0);
+ EXPECT_TRUE(controller.Commit(0));
+ // Save to real storage.
+ EXPECT_EQ(storage.Load(address1).first, 3000);
+}
+
+TEST(LocalViewTest, CommitConflict) {
+ DataStorage storage;
+ uint256_t address1 = HexToInt("0x123");
+
+ storage.Store(address1, 2000);
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+
+ TwoPhaseController controller(&storage);
+
+ LocalView view1(&controller, 0);
+ LocalView view2(&controller, 1);
+
+ EXPECT_EQ(view1.load(address1), 2000);
+ view1.store(address1, 3000);
+ EXPECT_EQ(view1.load(address1), 3000);
+
+ // storage still contains 2000
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+
+ EXPECT_EQ(view2.load(address1), 2000);
+ view2.store(address1, 4000);
+ EXPECT_EQ(view2.load(address1), 4000);
+
+ // storage still contains 2000
+ EXPECT_EQ(storage.Load(address1).first, 2000);
+
+ view1.Flesh(0);
+ view2.Flesh(1);
+
+ EXPECT_FALSE(controller.Commit(1));
+ EXPECT_TRUE(controller.Commit(0));
+
+ // Save to real storage.
+ EXPECT_EQ(storage.Load(address1).first, 3000);
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/mock_d_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/mock_d_storage.h
new file mode 100644
index 000000000..aa38fa511
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/mock_d_storage.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "gmock/gmock.h"
+#include "service/contract/executor/manager/d_storage.h"
+
+namespace resdb {
+namespace contract {
+
+class MockDStorage : public D_Storage {
+ public:
+ typedef std::pair<uint256_t, int64_t> LoadType;
+
+ MOCK_METHOD(int64_t, Store,
+ (const uint256_t& key, const uint256_t& value, bool), (override));
+ MOCK_METHOD(bool, Remove, (const uint256_t&, bool), (override));
+ MOCK_METHOD(bool, Exist, (const uint256_t&, bool), (const, override));
+ MOCK_METHOD(int64_t, GetVersion, (const uint256_t&, bool), (const, override));
+ MOCK_METHOD(LoadType, Load, (const uint256_t&, bool), (const, override));
+ MOCK_METHOD(void, Reset, (const uint256_t&, const uint256_t&, int64_t, bool),
+ (override));
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/mock_data_storage.h b/platform/consensus/ordering/thunderbolt/executor/manager/mock_data_storage.h
new file mode 100644
index 000000000..1876f7142
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/mock_data_storage.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "gmock/gmock.h"
+#include "service/contract/executor/manager/data_storage.h"
+
+namespace resdb {
+namespace contract {
+
+class MockStorage : public DataStorage {
+ public:
+ typedef std::pair<uint256_t, int64_t> LoadType;
+
+ MOCK_METHOD(int64_t, Store,
+ (const uint256_t& key, const uint256_t& value, bool), (override));
+ MOCK_METHOD(bool, Remove, (const uint256_t&, bool), (override));
+ MOCK_METHOD(bool, Exist, (const uint256_t&, bool), (const, override));
+ MOCK_METHOD(int64_t, GetVersion, (const uint256_t&, bool), (const, override));
+ MOCK_METHOD(LoadType, Load, (const uint256_t&, bool), (const, override));
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/ooo_committer.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_committer.cpp
new file mode 100644
index 000000000..a60c66e27
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_committer.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/ooo_committer.h"
+
+#include "eEVM/processor.h"
+#include "glog/logging.h"
+#include "service/contract/executor/manager/local_state.h"
+
+namespace resdb {
+namespace contract {
+
+OOOCommitter::OOOCommitter(DataStorage* storage, GlobalState* global_state,
+ int worker_num)
+ : gs_(global_state), worker_num_(worker_num) {
+ controller_ = std::make_unique<OOOController>(storage);
+ executor_ = std::make_unique<ContractExecutor>();
+ is_stop_ = false;
+
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_.push_back(std::thread([&]() {
+ while (!is_stop_) {
+ auto request = request_queue_.Pop();
+ if (request == nullptr) {
+ continue;
+ }
+ LocalState local_state(controller_.get());
+ local_state.Set(gs_->GetAccount(request->contract_address),
+ request->commit_id);
+
+ std::unique_ptr<ExecuteResp> resp = std::make_unique<ExecuteResp>();
+ auto ret = ExecContract(request->caller_address,
+ request->contract_address, request->func_addr,
+ request->func_params, &local_state);
+ resp->state = ret.status();
+ resp->contract_address = request->contract_address;
+ resp->commit_id = request->commit_id;
+ resp->user_id = request->user_id;
+ if (ret.ok()) {
+ resp->ret = 0;
+ resp->result = *ret;
+ } else {
+ resp->ret = -1;
+ }
+ resp_queue_.Push(std::move(resp));
+ }
+ }));
+ }
+}
+
+OOOCommitter::~OOOCommitter() {
+ is_stop_ = true;
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_[i].join();
+ }
+}
+
+std::vector<std::unique_ptr<ExecuteResp>> OOOCommitter::ExecContract(
+ std::vector<ContractExecuteInfo>& requests) {
+ int process_num = requests.size();
+ std::vector<std::unique_ptr<ExecuteResp>> resp_list;
+
+ std::set<int64_t> commits;
+ resp_list.resize(process_num);
+
+ for (auto& request : requests) {
+ request_queue_.Push(std::make_unique<ContractExecuteInfo>(request));
+ }
+
+ while (process_num) {
+ auto resp = resp_queue_.Pop();
+ if (resp == nullptr) {
+ continue;
+ }
+ int64_t resp_commit_id = resp->commit_id;
+ resp_list[resp->commit_id - 1] = std::move(resp);
+ process_num--;
+ }
+
+ return resp_list;
+}
+
+absl::StatusOr<std::string> OOOCommitter::ExecContract(
+ const Address& caller_address, const Address& contract_address,
+ const std::string& func_addr, const Params& func_param, EVMState* state) {
+ return executor_->ExecContract(caller_address, contract_address, func_addr,
+ func_param, state);
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/ooo_committer.h b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_committer.h
new file mode 100644
index 000000000..ddf15fdce
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_committer.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <future>
+#include <shared_mutex>
+
+#include "absl/status/statusor.h"
+#include "eEVM/opcode.h"
+#include "platform/common/queue/lock_free_queue.h"
+#include "service/contract/executor/common/utils.h"
+#include "service/contract/executor/manager/contract_committer.h"
+#include "service/contract/executor/manager/contract_executor.h"
+#include "service/contract/executor/manager/global_state.h"
+#include "service/contract/executor/manager/ooo_controller.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+class OOOCommitter : public ContractCommitter {
+ public:
+ OOOCommitter(DataStorage* storage, GlobalState* global_state,
+ int worker_num = 2);
+
+ ~OOOCommitter();
+
+ std::vector<std::unique_ptr<ExecuteResp>> ExecContract(
+ std::vector<ContractExecuteInfo>& request) override;
+
+ absl::StatusOr<std::string> ExecContract(const Address& caller_address,
+ const Address& contract_address,
+ const std::string& func_addr,
+ const Params& func_param,
+ EVMState* state);
+
+ private:
+ std::unique_ptr<OOOController> controller_;
+ std::unique_ptr<ContractExecutor> executor_;
+ GlobalState* gs_;
+ std::vector<std::thread> workers_;
+ std::atomic<bool> is_stop_;
+
+ LockFreeQueue<ContractExecuteInfo> request_queue_;
+ LockFreeQueue<ExecuteResp> resp_queue_;
+
+ const int worker_num_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/ooo_controller.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_controller.cpp
new file mode 100644
index 000000000..b9be8e61e
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_controller.cpp
@@ -0,0 +1,36 @@
+#include "service/contract/executor/manager/ooo_controller.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+OOOController::OOOController(DataStorage* storage)
+ : ConcurrencyController(storage) {}
+
+OOOController::~OOOController() {}
+
+void OOOController::PushCommit(int64_t commit_id,
+ const ModifyMap& local_changes) {
+ for (const auto& it : local_changes) {
+ bool done = false;
+ for (int i = it.second.size() - 1; i >= 0 && !done; --i) {
+ const auto& op = it.second[i];
+ switch (op.state) {
+ case LOAD:
+ break;
+ case STORE:
+ storage_->Store(it.first, op.data);
+ done = true;
+ break;
+ case REMOVE:
+ storage_->Remove(it.first);
+ done = true;
+ break;
+ }
+ }
+ }
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/ooo_controller.h b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_controller.h
new file mode 100644
index 000000000..449fbc4c2
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/ooo_controller.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "service/contract/executor/manager/concurrency_controller.h"
+
+namespace resdb {
+namespace contract {
+
+class OOOController : public ConcurrencyController {
+ public:
+ OOOController(DataStorage* storage);
+ ~OOOController();
+
+ virtual void PushCommit(int64_t commit_id, const ModifyMap& local_changes);
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller.cpp
new file mode 100644
index 000000000..708880238
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller.cpp
@@ -0,0 +1,267 @@
+#include "service/contract/executor/manager/sequential_cc_controller.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+SequentialCCController::SequentialCCController(DataStorage* storage)
+ : ConcurrencyController(storage) {
+ for (int i = 0; i < window_size_; ++i) {
+ is_redo_.push_back(false);
+ }
+
+ Clear();
+ last_commit_id_ = 0;
+}
+
+SequentialCCController::~SequentialCCController() {}
+
+void SequentialCCController::Clear() {
+ last_commit_id_ = 0;
+
+ changes_list_.resize(window_size_);
+ for (int i = 0; i < window_size_; ++i) {
+ changes_list_[i].clear();
+ is_redo_[i] = false;
+ }
+ for (int i = 0; i < 1024; ++i) {
+ commit_list_[i].clear();
+ }
+ m_list_.clear();
+}
+
+std::vector<int64_t>& SequentialCCController::GetRedo() { return redo_; }
+
+int SequentialCCController::GetHashKey(const uint256_t& address) {
+ // Get big-endian form
+ uint8_t arr[32] = {};
+ memset(arr, 0, sizeof(arr));
+ intx::be::store(arr, address);
+ uint32_t v = 0;
+ for (int i = 0; i < 32; ++i) {
+ v += arr[i];
+ }
+ return v % 128;
+}
+
+void SequentialCCController::SetCallback(CallBack call_back) {
+ call_back_ = call_back;
+}
+
+void SequentialCCController::RedoCommit(int64_t commit_id, int flag) {
+ if (is_redo_[commit_id]) {
+ return;
+ }
+ is_redo_[commit_id] = true;
+ redo_.push_back(commit_id);
+}
+
+void SequentialCCController::PushCommit(int64_t commit_id,
+ const ModifyMap& local_changes) {
+ if (commit_id <= last_commit_id_) {
+ // assert(!changes_list_[commit_id].empty());
+ changes_list_[commit_id] = local_changes;
+ // assert(Commit(commit_id));
+ return;
+ }
+
+ {
+ changes_list_[commit_id] = local_changes;
+ /*
+ for(const auto& it : local_changes){
+ int hash_idx = GetHashKey(it.first);
+ //LOG(ERROR)<<"address:"<<it.first<<" idx:"<<hash_idx;
+ std::unique_lock lock(mutexs_[hash_idx]);
+ //LOG(ERROR)<<"load idx:"<<hash_idx;
+ auto& commit_set = commit_list_[hash_idx][it.first];
+ commit_set.insert(commit_id);
+ }
+ */
+ }
+}
+
+bool SequentialCCController::Commit(int64_t commit_id) {
+ if (commit_id > last_commit_id_) {
+ const auto& local_changes = changes_list_[commit_id];
+ for (const auto& it : local_changes) {
+ int hash_idx = GetHashKey(it.first);
+ // LOG(ERROR)<<"address:"<<it.first<<" idx:"<<hash_idx;
+ // std::unique_lock lock(mutexs_[hash_idx]);
+ // LOG(ERROR)<<"load idx:"<<hash_idx;
+ auto& commit_set = commit_list_[hash_idx][it.first];
+ commit_set.push_back(commit_id);
+ // commit_set.insert(commit_id);
+ }
+ }
+
+ redo_.clear();
+ bool ret = CommitInternal(commit_id);
+ if (commit_id == last_commit_id_ + 1) {
+ last_commit_id_++;
+ }
+ return ret;
+}
+
+bool SequentialCCController::CommitInternal(int64_t commit_id) {
+ if (!CheckCommit(commit_id)) {
+ return false;
+ }
+ const auto& change_set = changes_list_[commit_id];
+ if (change_set.empty()) {
+ LOG(ERROR) << " no commit id record found:" << commit_id;
+ return false;
+ }
+ std::set<int64_t> new_commit_ids;
+ for (const auto& it : change_set) {
+ bool done = false;
+ const uint256_t& address = it.first;
+ int64_t new_v = 0;
+ for (int i = it.second.size() - 1; i >= 0 && !done; --i) {
+ const auto& op = it.second[i];
+ switch (op.state) {
+ case LOAD:
+ break;
+ case STORE:
+ // LOG(ERROR)<<"commit:"<<it.first<<" data:"<<op.data<<" commit
+ // id:"<<commit_id;
+ new_v = storage_->Store(it.first, op.data);
+ done = true;
+ break;
+ case REMOVE:
+ // LOG(ERROR)<<"remove:"<<it.first<<" data:";
+ storage_->Remove(it.first);
+ done = true;
+ break;
+ }
+ }
+ int64_t next_commit_id = Remove(address, commit_id, new_v);
+ // if(next_commit_id> 0){
+ if (next_commit_id > 0 && next_commit_id <= last_commit_id_) {
+ new_commit_ids.insert(next_commit_id);
+ }
+ if (done && next_commit_id > last_commit_id_) {
+ if (IsRead(address, next_commit_id)) {
+ new_commit_ids.insert(next_commit_id);
+ }
+ }
+ }
+ Remove(commit_id);
+ for (int64_t redo_commit : new_commit_ids) {
+ RedoCommit(redo_commit, 1);
+ }
+ return true;
+}
+
+bool SequentialCCController::CheckFirstCommit(const uint256_t& address,
+ int64_t commit_id) {
+ int idx = GetHashKey(address);
+ // std::shared_lock lock(mutexs_[idx]);
+ // LOG(ERROR)<<"load idx:"<<idx;
+ // std::shared_lock lock(mutex_);
+ if (commit_list_[idx].find(address) == commit_list_[idx].end()) {
+ LOG(ERROR) << "no address:" << commit_id << " add:" << address;
+ return false;
+ }
+ const auto& commit_set = commit_list_[idx][address];
+ // assert(*commit_set.begin()>0);
+
+ if (commit_set.front() < commit_id) {
+ // if(*commit_set.begin() < commit_id){
+ // not the first candidate
+ // LOG(ERROR)<<"still have dep. commit id:"<<commit_id<<"
+ // dep:"<<*commit_list_[address].begin();
+ return false;
+ }
+ // assert(*commit_set.begin() == commit_id);
+ return true;
+}
+
+bool SequentialCCController::IsRead(const uint256_t& address,
+ int64_t commit_id) {
+ const auto& change_set = changes_list_[commit_id];
+ if (change_set.empty()) {
+ LOG(ERROR) << " no commit id record found:" << commit_id;
+ // assert(!change_set.empty());
+ return false;
+ }
+
+ for (const auto& it : change_set) {
+ if (it.first != address) {
+ continue;
+ }
+ for (auto& op : it.second) {
+ if (op.state == LOAD) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool SequentialCCController::CheckCommit(int64_t commit_id) {
+ const auto& change_set = changes_list_[commit_id];
+ if (change_set.empty()) {
+ LOG(ERROR) << " no commit id record found:" << commit_id;
+ // assert(!change_set.empty());
+ return false;
+ }
+
+ for (const auto& it : change_set) {
+ const uint256_t& address = it.first;
+ if (!CheckFirstCommit(it.first, commit_id)) {
+ return false;
+ }
+
+ for (auto& op : it.second) {
+ if (op.state == LOAD) {
+ uint64_t v = storage_->GetVersion(address);
+ if (op.version != v) {
+ // LOG(ERROR)<<"check load:"<<address<<" version:"<<v<<" data
+ // v:"<<op.version<<" commit id:"<<commit_id<<"
+ // mlist:"<<m_list_[it.first];
+ RedoCommit(commit_id, 0);
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+const ConcurrencyController::ModifyMap* SequentialCCController::GetChangeList(
+ int64_t commit_id) {
+ // read lock
+ return &changes_list_[commit_id];
+}
+
+void SequentialCCController::Remove(int64_t commit_id) {
+ changes_list_[commit_id].clear();
+}
+
+int64_t SequentialCCController::Remove(const uint256_t& address,
+ int64_t commit_id, uint64_t v) {
+ int idx = GetHashKey(address);
+ // std::unique_lock lock(mutex_);
+ // std::unique_lock lock(mutexs_[idx]);
+ // LOG(ERROR)<<"load idx:"<<idx;
+ if (commit_list_[idx].find(address) == commit_list_[idx].end()) {
+ LOG(ERROR) << " remove address:" << address << " commit id:" << commit_id
+ << " not exist";
+ }
+ // assert(commit_list_.find(address) != commit_list_.end());
+
+ auto& it = commit_list_[idx][address];
+ // assert(*it.begin() == commit_id);
+ it.pop_front();
+ // it.erase(it.begin());
+ // LOG(ERROR)<<"update address:"<<address<<" mlist:"<<m_list_[address];
+ if (it.empty()) {
+ commit_list_[idx].erase(commit_list_[idx].find(address));
+ return -1;
+ }
+ return it.front();
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller.h b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller.h
new file mode 100644
index 000000000..9d0ee1ec5
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <deque>
+#include <set>
+#include <shared_mutex>
+#include <thread>
+
+#include "platform/common/queue/lock_free_queue.h"
+#include "service/contract/executor/manager/concurrency_controller.h"
+
+namespace resdb {
+namespace contract {
+
+class SequentialCCController : public ConcurrencyController {
+ public:
+ struct CallBack {
+ std::function<void(int64_t, int)> redo_callback = nullptr;
+ std::function<void(int64_t)> committed_callback = nullptr;
+ };
+
+ SequentialCCController(DataStorage* storage);
+ ~SequentialCCController();
+
+ void SetCallback(CallBack call_back);
+
+ virtual void PushCommit(int64_t commit_id, const ModifyMap& local_changes_);
+ bool Commit(int64_t commit_id);
+ std::vector<int64_t>& GetRedo();
+
+ void Clear();
+
+ private:
+ bool CommitInternal(int64_t commit_id);
+ bool CheckCommit(int64_t commit_id);
+ bool CheckFirstCommit(const uint256_t& address, int64_t commit_id);
+
+ const ModifyMap* GetChangeList(int64_t commit_id);
+ int64_t Remove(const uint256_t& address, int64_t commit_id, uint64_t v);
+ void Remove(int64_t commit_id);
+
+ std::function<void(int64_t)> GetCommitCallBack(int64_t commit_id);
+ std::function<void(int64_t, int)> GetRedoCallBack(int64_t commit_id);
+
+ void CommitDone(int64_t commit_id);
+ void RedoCommit(int64_t commit_id, int flag);
+
+ int GetHashKey(const uint256_t& address);
+
+ bool IsRead(const uint256_t& address, int64_t commit_id);
+
+ private:
+ const int window_size_ = 1000;
+ mutable std::shared_mutex mutex_, mutexs_[1024];
+
+ std::map<uint256_t, int64_t> first_commit_;
+ std::atomic<int64_t> last_commit_id_;
+
+ std::vector<ModifyMap> changes_list_;
+ std::map<uint256_t, std::deque<int64_t> > commit_list_[1024];
+ // std::map<uint256_t, std::set<int64_t> > commit_list_[1024];
+ std::map<uint256_t, uint64_t> m_list_;
+
+ std::vector<bool> is_redo_;
+ CallBack call_back_;
+
+ std::vector<int64_t> redo_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller_test.cpp
new file mode 100644
index 000000000..9224873ac
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_cc_controller_test.cpp
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/sequential_cc_controller.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <future>
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Test;
+
+uint256_t HexToInt(const std::string& v) { return eevm::to_uint256(v); }
+
+void GetData(const std::string& addr, const DataStorage& storage,
+ ConcurrencyController::ModifyMap& changes) {
+ changes[HexToInt(addr)].push_back(Data(LOAD,
+ storage.Load(HexToInt(addr)).first,
+ storage.Load(HexToInt(addr)).second));
+}
+
+void SetData(const std::string& addr, int value,
+ ConcurrencyController::ModifyMap& changes) {
+ changes[HexToInt(addr)].push_back(Data(STORE, value));
+}
+
+TEST(ContractDagManagerTest, PushOneCommit) {
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t) {
+ LOG(ERROR) << "committed";
+ done.set_value(true);
+ };
+
+ int64_t commit_id = 1;
+
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+ controller.SetCallback(call_back);
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x123", storage, changes);
+ SetData("0x124", 1000, changes);
+
+ controller.PushCommit(commit_id, changes);
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 0);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 1000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommit) {
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t) {
+ LOG(ERROR) << "committed";
+ committed_num++;
+ if (committed_num == 2) {
+ done.set_value(true);
+ }
+ };
+
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+ controller.SetCallback(call_back);
+
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+
+ SetData("0x123", 3000, changes);
+ SetData("0x124", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 1000, changes);
+ SetData("0x124", 2000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 3000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 4000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitRAWBlock) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ if (committed1_done == 1 && redo_num == 1) {
+ done.set_value(true);
+ }
+ LOG(ERROR) << "redo:" << commit_id;
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x123", storage, changes);
+ SetData("0x124", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 1000, changes);
+ SetData("0x124", 2000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 2000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitRAWRedo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ if (commit_id == 2) {
+ committed2_done = 1;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num == 1) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+ SequentialCCController::ModifyMap changes;
+
+ GetData("0x123", storage, changes);
+ SetData("0x124", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x123", storage, changes);
+ SetData("0x124", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 1000, changes);
+ SetData("0x124", 2000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 4000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitRAWRedo2) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ if (commit_id == 2) {
+ committed2_done = 1;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num == 1) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ GetData("0x123", storage, changes);
+ SetData("0x124", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ GetData("0x123", storage, changes);
+ SetData("0x124", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 1000, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 2000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 5000);
+}
+
+TEST(ContractDagManagerTest, ThreeOOOCommitRAWRedo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+ std::set<int64_t> done_list;
+ int redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ done_list.insert(commit_id);
+ if (done_list.size() == 3 && redo_num == 1) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 3);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+
+ SequentialCCController::ModifyMap changes;
+
+ GetData("0x121", storage, changes);
+ GetData("0x122", storage, changes);
+ GetData("0x123", storage, changes);
+ SetData("0x125", 8000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ };
+
+ controller.SetCallback(call_back);
+
+ {
+ int64_t commit_id = 3;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x121", storage, changes);
+ GetData("0x122", storage, changes);
+ GetData("0x123", storage, changes);
+ SetData("0x125", 8000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 5000, changes);
+ SetData("0x124", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x122", 5000, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x125")).first, 8000);
+}
+
+TEST(ContractDagManagerTest, ThreeOOOCommitRAW2Redo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+ std::set<int64_t> done_list;
+ int redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ LOG(ERROR) << "commit:" << commit_id;
+ done_list.insert(commit_id);
+ if (done_list.size() == 3 && redo_num == 2) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ redo_num++;
+ LOG(ERROR) << "redo:" << commit_id;
+
+ SequentialCCController::ModifyMap changes;
+
+ if (commit_id == 3) {
+ GetData("0x120", storage, changes);
+ GetData("0x122", storage, changes);
+ SetData("0x125", 8000, changes);
+ } else if (commit_id == 2) {
+ GetData("0x121", storage, changes);
+ SetData("0x123", 5000, changes);
+ SetData("0x120", 5000, changes);
+ }
+ controller.PushCommit(commit_id, changes);
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 3;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x120", storage, changes);
+ GetData("0x122", storage, changes);
+ SetData("0x125", 8000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x121", storage, changes);
+ SetData("0x123", 5000, changes);
+ SetData("0x120", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x121", 5000, changes);
+ SetData("0x122", 5000, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 6000);
+ EXPECT_EQ(storage.Load(HexToInt("0x125")).first, 8000);
+}
+
+TEST(ContractDagManagerTest, ThreeRAW2Redo3list) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+ storage.Store(HexToInt("0x125"), 5000);
+ storage.Store(HexToInt("0x126"), 6000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+ std::set<int64_t> done_list;
+ int redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ done_list.insert(commit_id);
+ if (done_list.size() == 3 && redo_num == 2) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ redo_num++;
+ LOG(ERROR) << "redo:" << commit_id;
+
+ SequentialCCController::ModifyMap changes;
+
+ if (commit_id == 3) {
+ GetData("0x120", storage, changes);
+ GetData("0x122", storage, changes);
+ SetData("0x125", 8000, changes);
+ } else if (commit_id == 2) {
+ GetData("0x121", storage, changes);
+ SetData("0x123", 5000, changes);
+ SetData("0x120", 5000, changes);
+ }
+ controller.PushCommit(commit_id, changes);
+ };
+ controller.SetCallback(call_back);
+
+ {
+ int64_t commit_id = 3;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x126", storage, changes);
+ GetData("0x121", storage, changes);
+ SetData("0x125", 8000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x121", storage, changes);
+ SetData("0x123", 5000, changes);
+ SetData("0x120", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x121", 5000, changes);
+ SetData("0x122", 5000, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 6000);
+ EXPECT_EQ(storage.Load(HexToInt("0x125")).first, 8000);
+ EXPECT_EQ(storage.Load(HexToInt("0x126")).first, 6000);
+}
+
+TEST(ContractDagManagerTest, TwoOOORAWRedoAfterNew) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int redo_num = 0;
+ std::set<int64_t> done_list;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ done_list.insert(commit_id);
+ if (done_list.size() == 3 && redo_num == 1) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+
+ if (commit_id == 2) {
+ {
+ int64_t new_commit_id = 3;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x120", storage, changes);
+ SetData("0x121", 4000, changes);
+
+ controller.PushCommit(new_commit_id, changes);
+ }
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ SetData("0x124", 2000, changes);
+ controller.PushCommit(commit_id, changes);
+ }
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ SetData("0x124", 2000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x122", 1000, changes);
+ SetData("0x124", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 0000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 4000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 3000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 2000);
+}
+
+TEST(ContractDagManagerTest, TwoOOORAWRedoAfterNewConflict) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int redo_num = 0;
+ std::set<int64_t> done_list;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ done_list.insert(commit_id);
+ if (done_list.size() == 3 && redo_num == 2) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ redo_num++;
+ LOG(ERROR) << "redo:" << commit_id;
+
+ if (commit_id == 2) {
+ {
+ int64_t new_commit_id = 3;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x124", storage, changes);
+ SetData("0x121", 4000, changes);
+
+ controller.PushCommit(new_commit_id, changes);
+ }
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ SetData("0x124", 2000, changes);
+ controller.PushCommit(commit_id, changes);
+ } else if (commit_id == 3) {
+ SequentialCCController::ModifyMap changes;
+ GetData("0x124", storage, changes);
+ SetData("0x121", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ SetData("0x124", 2000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x122", 1000, changes);
+ SetData("0x124", 5000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 0000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 4000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 3000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 2000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitRAWNoRedo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x122"), 2000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ if (commit_id == 2) {
+ committed2_done = 1;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num == 0) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x122", storage, changes);
+ SetData("0x124", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 1000, changes);
+ SetData("0x124", 4000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 2000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 4000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitWAWNoRedo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ if (commit_id == 2) {
+ committed2_done = 1;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num == 0) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x122", 3000, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 2000, changes);
+ SetData("0x124", 1000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 0000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 3000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 2000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 6000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitWARNoRedo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ if (commit_id == 2) {
+ committed2_done = 1;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num == 0) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ SetData("0x123", 5000, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x123", storage, changes);
+ SetData("0x124", 1000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 0000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 2000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 5000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 6000);
+}
+
+TEST(ContractDagManagerTest, PushTwoOOOCommitRARNoRedo) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ if (commit_id == 1) {
+ committed1_done = 1;
+ }
+ if (commit_id == 2) {
+ committed2_done = 1;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num == 0) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x123", storage, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x123", storage, changes);
+ SetData("0x124", 1000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x120")).first, 0000);
+ EXPECT_EQ(storage.Load(HexToInt("0x121")).first, 1000);
+ EXPECT_EQ(storage.Load(HexToInt("0x122")).first, 2000);
+ EXPECT_EQ(storage.Load(HexToInt("0x123")).first, 3000);
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 6000);
+}
+
+TEST(ContractDagManagerTest, ReadAndWriteSameAddress) {
+ DataStorage storage;
+ SequentialCCController controller(&storage);
+
+ storage.Store(HexToInt("0x120"), 0000);
+ storage.Store(HexToInt("0x121"), 1000);
+ storage.Store(HexToInt("0x122"), 2000);
+ storage.Store(HexToInt("0x123"), 3000);
+ storage.Store(HexToInt("0x124"), 4000);
+
+ std::promise<bool> done;
+ std::future<bool> done_future = done.get_future();
+
+ int committed1_done = 0, committed2_done = 0, redo_num = 0;
+ SequentialCCController::CallBack call_back;
+ call_back.committed_callback = [&](int64_t commit_id) {
+ LOG(ERROR) << "commit id ====:" << commit_id;
+ if (commit_id == 1) {
+ committed1_done++;
+ }
+ if (commit_id == 2) {
+ committed2_done++;
+ }
+ if (committed1_done == 1 && committed2_done == 1 && redo_num >= 1) {
+ done.set_value(true);
+ }
+ };
+
+ call_back.redo_callback = [&](int64_t commit_id) {
+ EXPECT_EQ(commit_id, 2);
+ redo_num = 1;
+ LOG(ERROR) << "redo:" << commit_id;
+ SequentialCCController::ModifyMap changes;
+ GetData("0x124", storage, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ };
+
+ controller.SetCallback(call_back);
+ {
+ int64_t commit_id = 2;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x124", storage, changes);
+ SetData("0x124", 6000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ {
+ int64_t commit_id = 1;
+
+ SequentialCCController::ModifyMap changes;
+ GetData("0x124", storage, changes);
+ SetData("0x124", 1000, changes);
+
+ controller.PushCommit(commit_id, changes);
+ }
+
+ done_future.get();
+ EXPECT_EQ(storage.Load(HexToInt("0x124")).first, 6000);
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer.cpp
new file mode 100644
index 000000000..282dd0f9c
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/sequential_concurrency_committer.h"
+
+#include <queue>
+
+#include "common/utils/utils.h"
+#include "eEVM/processor.h"
+#include "glog/logging.h"
+#include "service/contract/executor/manager/local_state.h"
+
+namespace resdb {
+namespace contract {
+
+/*
+ExecutionContext::ExecutionContext(const ContractExecuteInfo & info ) {
+ info_ = std::make_unique<ContractExecuteInfo>(info);
+}
+
+const ContractExecuteInfo * ExecutionContext::GetContractExecuteInfo() const {
+ return info_.get();
+}
+
+void ExecutionContext::SetResult(std::unique_ptr<ExecuteResp> result) {
+ result_ = std::move(result);
+}
+
+bool ExecutionContext::IsRedo() {
+ return is_redo_;
+}
+
+void ExecutionContext::SetRedo(){
+ is_redo_ = true;
+}
+
+std::unique_ptr<ExecuteResp> ExecutionContext::FetchResult() {
+ return std::move(result_);
+}
+*/
+
+ExecutionState* SequentialConcurrencyCommitter::GetExecutionState() {
+ return &execution_state_;
+}
+
+SequentialConcurrencyCommitter::SequentialConcurrencyCommitter(
+ DataStorage* storage, GlobalState* global_state, int worker_num)
+ : storage_(storage), gs_(global_state), worker_num_(worker_num) {
+ controller_ = std::make_unique<SequentialCCController>(storage);
+ executor_ = std::make_unique<ContractExecutor>();
+ is_stop_ = false;
+
+ SequentialCCController::CallBack callback;
+ callback.redo_callback =
+ std::bind(&SequentialConcurrencyCommitter::RedoCallBack, this,
+ std::placeholders::_1, std::placeholders::_2);
+ callback.committed_callback =
+ std::bind(&SequentialConcurrencyCommitter::CommitCallBack, this,
+ std::placeholders::_1);
+
+ controller_->SetCallback(callback);
+
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_.push_back(std::thread([&]() {
+ while (!is_stop_) {
+ auto request_ptr = request_queue_.Pop();
+ if (request_ptr == nullptr) {
+ continue;
+ }
+ ExecutionContext* request = *request_ptr;
+
+ LocalState local_state(controller_.get());
+ local_state.Set(
+ gs_->GetAccount(
+ request->GetContractExecuteInfo()->contract_address),
+ request->GetContractExecuteInfo()->commit_id);
+
+ std::unique_ptr<ExecuteResp> resp = std::make_unique<ExecuteResp>();
+ auto ret = ExecContract(
+ request->GetContractExecuteInfo()->caller_address,
+ request->GetContractExecuteInfo()->contract_address,
+ request->GetContractExecuteInfo()->func_addr,
+ request->GetContractExecuteInfo()->func_params, &local_state);
+ resp->state = ret.status();
+ resp->contract_address =
+ request->GetContractExecuteInfo()->contract_address;
+ resp->commit_id = request->GetContractExecuteInfo()->commit_id;
+ resp->user_id = request->GetContractExecuteInfo()->user_id;
+ if (ret.ok()) {
+ resp->ret = 0;
+ resp->result = *ret;
+ if (request->IsRedo()) {
+ resp->retry_time = 1;
+ // request->SetResult(std::move(resp));
+ }
+ local_state.Flesh(request->GetContractExecuteInfo()->contract_address,
+ request->GetContractExecuteInfo()->commit_id);
+ } else {
+ resp->ret = -1;
+ }
+ // if(!request->IsRedo()){
+ resp_queue_.Push(std::move(resp));
+ //}
+ }
+ }));
+ }
+}
+
+SequentialConcurrencyCommitter::~SequentialConcurrencyCommitter() {
+ is_stop_ = true;
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_[i].join();
+ }
+}
+
+void SequentialConcurrencyCommitter::AddTask(
+ int64_t commit_id, std::unique_ptr<ExecutionContext> context) {
+ context_list_[commit_id] = std::move(context);
+}
+
+void SequentialConcurrencyCommitter::RemoveTask(int64_t commit_id) {
+ context_list_.erase(context_list_.find(commit_id));
+}
+
+ExecutionContext* SequentialConcurrencyCommitter::GetTaskContext(
+ int64_t commit_id) {
+ return context_list_[commit_id].get();
+}
+
+void SequentialConcurrencyCommitter::CommitCallBack(int64_t commit_id) {}
+
+void SequentialConcurrencyCommitter::RedoCallBack(int64_t commit_id, int flag) {
+}
+
+std::vector<std::unique_ptr<ExecuteResp>>
+SequentialConcurrencyCommitter::ExecContract(
+ std::vector<ContractExecuteInfo>& requests) {
+ execution_state_.commit_time = 0;
+ execution_state_.redo_time = 0;
+
+ int process_num = requests.size();
+ std::vector<std::unique_ptr<ExecuteResp>> resp_list;
+
+ std::set<int64_t> commits;
+ int id = 1;
+ resp_list.resize(process_num);
+ for (auto& request : requests) {
+ resp_list[id - 1] = nullptr;
+ request.commit_id = id++;
+ auto context = std::make_unique<ExecutionContext>(request);
+ AddTask(request.commit_id, std::move(context));
+ commits.insert(request.commit_id);
+ }
+
+ controller_->Clear();
+ for (auto& request : requests) {
+ auto context_ptr = GetTaskContext(request.commit_id);
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+
+ auto cur_it = commits.begin();
+ std::queue<int64_t> redo_list;
+ while (process_num) {
+ auto resp = resp_queue_.Pop();
+ if (resp == nullptr) {
+ continue;
+ }
+ int64_t resp_commit_id = resp->commit_id;
+ // LOG(ERROR)<<"recv :"<<resp_commit_id<<" process num:"<<process_num;
+ resp_list[resp->commit_id - 1] = std::move(resp);
+ if (cur_it == commits.end() || resp_commit_id < *cur_it) {
+ bool ret = controller_->Commit(resp_commit_id);
+ std::vector<int64_t> list = controller_->GetRedo();
+ for (int64_t next_id : list) {
+ bool ret = controller_->Commit(next_id);
+ if (!ret) {
+ // redo_list.push(next_id);
+ auto context_ptr = GetTaskContext(next_id);
+ context_ptr->SetRedo();
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+ }
+ assert(ret);
+ process_num--;
+ }
+ while (cur_it != commits.end() && resp_list[*cur_it - 1] != nullptr) {
+ int64_t commit_id = *cur_it;
+ bool ret = controller_->Commit(commit_id);
+ cur_it++;
+ if (!ret) {
+ resp_list[commit_id - 1] = nullptr;
+ if (controller_->GetRedo().size()) {
+ // redo_list.push(commit_id);
+
+ auto context_ptr = GetTaskContext(commit_id);
+ context_ptr->SetRedo();
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+ } else {
+ process_num--;
+ std::vector<int64_t> list = controller_->GetRedo();
+ for (int64_t next_id : list) {
+ resp_list[next_id - 1] = nullptr;
+ // redo_list.push(next_id);
+ auto context_ptr = GetTaskContext(next_id);
+ context_ptr->SetRedo();
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+ }
+ }
+ }
+
+ for (auto& request : requests) {
+ RemoveTask(request.commit_id);
+ }
+
+ storage_->Flush();
+
+ return resp_list;
+}
+
+absl::StatusOr<std::string> SequentialConcurrencyCommitter::ExecContract(
+ const Address& caller_address, const Address& contract_address,
+ const std::string& func_addr, const Params& func_param, EVMState* state) {
+ return executor_->ExecContract(caller_address, contract_address, func_addr,
+ func_param, state);
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer.h b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer.h
new file mode 100644
index 000000000..fc2d1e57e
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include <future>
+#include <shared_mutex>
+
+#include "absl/status/statusor.h"
+#include "eEVM/opcode.h"
+#include "platform/common/queue/lock_free_queue.h"
+#include "service/contract/executor/common/utils.h"
+#include "service/contract/executor/manager/committer_context.h"
+#include "service/contract/executor/manager/contract_committer.h"
+#include "service/contract/executor/manager/contract_executor.h"
+#include "service/contract/executor/manager/global_state.h"
+#include "service/contract/executor/manager/sequential_cc_controller.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+
+/*
+class ExecutionContext {
+public:
+ ExecutionContext(const ContractExecuteInfo & info ) ;
+ const ContractExecuteInfo * GetContractExecuteInfo() const;
+
+ void SetRedo();
+ bool IsRedo();
+
+ void SetResult(std::unique_ptr<ExecuteResp> result);
+ std::unique_ptr<ExecuteResp> FetchResult();
+
+ private:
+ bool is_redo_ = false;
+ std::unique_ptr<ExecuteResp> result_;
+ std::unique_ptr<ContractExecuteInfo> info_;
+};
+*/
+
+struct ExecutionState {
+ std::atomic<int> commit_time;
+ int redo_time = 0;
+};
+
+class SequentialConcurrencyCommitter : public ContractCommitter {
+ public:
+ SequentialConcurrencyCommitter(DataStorage* storage,
+ GlobalState* global_state, int worker_num = 2);
+
+ ~SequentialConcurrencyCommitter();
+
+ std::vector<std::unique_ptr<ExecuteResp>> ExecContract(
+ std::vector<ContractExecuteInfo>& request) override;
+
+ absl::StatusOr<std::string> ExecContract(const Address& caller_address,
+ const Address& contract_address,
+ const std::string& func_addr,
+ const Params& func_param,
+ EVMState* state);
+
+ ExecutionState* GetExecutionState();
+
+ private:
+ void AddTask(int64_t commit_id, std::unique_ptr<ExecutionContext> comtext);
+ void RemoveTask(int64_t commit_id);
+ ExecutionContext* GetTaskContext(int64_t commit_id);
+
+ void CommitCallBack(int64_t commit_id);
+ void RedoCallBack(int64_t commit_id, int flag);
+
+ private:
+ std::unique_ptr<SequentialCCController> controller_;
+ std::unique_ptr<ContractExecutor> executor_;
+ DataStorage* storage_;
+ GlobalState* gs_;
+ std::vector<std::thread> workers_;
+ std::atomic<bool> is_stop_;
+
+ LockFreeQueue<ExecutionContext*> request_queue_;
+ LockFreeQueue<ExecuteResp> resp_queue_;
+
+ std::map<int64_t, std::unique_ptr<ExecutionContext>> context_list_;
+
+ const int worker_num_;
+ ExecutionState execution_state_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer_test.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer_test.cpp
new file mode 100644
index 000000000..4f7e57f38
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/sequential_concurrency_committer_test.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/sequential_concurrency_committer.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "service/contract/executor/manager/address_manager.h"
+#include "service/contract/executor/manager/contract_deployer.h"
+#include "service/contract/executor/manager/global_state.h"
+#include "service/contract/executor/manager/mock_data_storage.h"
+#include "service/contract/proto/func_params.pb.h"
+
+namespace resdb {
+namespace contract {
+namespace {
+
+using ::testing::Invoke;
+using ::testing::Test;
+
+const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
+ std::string(getenv("TEST_WORKSPACE")) +
+ "/service/contract/executor/manager/";
+
+Address get_random_address() { return AddressManager().CreateRandomAddress(); }
+
+std::string U256ToString(uint256_t v) { return eevm::to_hex_string(v); }
+uint256_t HexToInt(const std::string& v) { return eevm::to_uint256(v); }
+
+class SequentialConcurrencyCommitterTest : public Test {
+ public:
+ SequentialConcurrencyCommitterTest() : owner_address_(get_random_address()) {
+ std::string contract_path = test_dir + "test_data/contract.json";
+
+ std::ifstream contract_fstream(contract_path);
+ if (!contract_fstream) {
+ throw std::runtime_error(fmt::format(
+ "Unable to open contract definition file {}", contract_path));
+ }
+
+ const auto contracts_definition = nlohmann::json::parse(contract_fstream);
+ const auto all_contracts = contracts_definition["contracts"];
+ const auto contract_code = all_contracts["ERC20.sol:ERC20Token"];
+ storage_ = std::make_unique<MockStorage>();
+ contract_json_ = contract_code;
+
+ EXPECT_CALL(*storage_, Load)
+ .WillRepeatedly(
+ Invoke([&](const uint256_t& address) { return data_[address]; }));
+
+ EXPECT_CALL(*storage_, Store)
+ .WillRepeatedly(
+ Invoke([&](const uint256_t& key, const uint256_t& value) {
+ int v = data_[key].second;
+ data_[key] = std::make_pair(value, v + 1);
+ }));
+
+ EXPECT_CALL(*storage_, GetVersion)
+ .WillRepeatedly(
+ Invoke([&](const uint256_t& key) { return data_[key].second; }));
+
+ Init();
+ }
+
+ void Init() {
+ gs_ = std::make_unique<GlobalState>(storage_.get());
+
+ committer_ = std::make_unique<SequentialConcurrencyCommitter>(
+ storage_.get(), gs_.get());
+
+ contract_address_ = AddressManager::CreateContractAddress(owner_address_);
+ deployer_ = std::make_unique<ContractDeployer>(committer_.get(), gs_.get());
+ contract_address_ =
+ deployer_->DeployContract(owner_address_, contract_json_, {1000});
+ }
+
+ std::vector<std::unique_ptr<ExecuteResp>> ExecContract(
+ std::vector<ContractExecuteInfo>& execute_info) {
+ for (int i = 0; i < execute_info.size(); ++i) {
+ std::string func_addr =
+ deployer_->GetFuncAddress(execute_info[i].contract_address,
+ execute_info[i].func_params.func_name());
+ if (func_addr.empty()) {
+ LOG(ERROR) << "no fouction:" << execute_info[i].func_params.func_name();
+ execute_info[i].contract_address = 0;
+ continue;
+ }
+ execute_info[i].func_addr = func_addr;
+ execute_info[i].commit_id = i + 1;
+ }
+ return committer_->ExecContract(execute_info);
+ }
+
+ protected:
+ Address owner_address_;
+ Address contract_address_;
+ nlohmann::json contract_json_;
+ std::unique_ptr<MockStorage> storage_;
+ std::unique_ptr<GlobalState> gs_;
+ std::unique_ptr<SequentialConcurrencyCommitter> committer_;
+ std::map<uint256_t, std::pair<uint256_t, int>> data_;
+ std::unique_ptr<ContractDeployer> deployer_;
+};
+
+TEST_F(SequentialConcurrencyCommitterTest, ExecContract) {
+ // owner 1000
+ std::vector<ContractExecuteInfo> info;
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(owner_address_));
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address_, "",
+ func_params, 0));
+ }
+
+ {
+ std::vector<std::unique_ptr<ExecuteResp>> resp = ExecContract(info);
+ EXPECT_EQ(resp.size(), 1);
+ EXPECT_EQ(resp[0]->ret, 0);
+ }
+}
+
+// get a
+// a->b
+TEST_F(SequentialConcurrencyCommitterTest, TwoTxnNoConflict) {
+ Address transfer_receiver = get_random_address();
+
+ // owner 1000
+ std::vector<ContractExecuteInfo> info;
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param(U256ToString(owner_address_));
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address_, "",
+ func_params, 0));
+ }
+
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(100));
+
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address_, "",
+ func_params, 0));
+ }
+
+ {
+ std::vector<std::unique_ptr<ExecuteResp>> resp = ExecContract(info);
+ EXPECT_EQ(resp.size(), 2);
+ EXPECT_EQ(resp[0]->ret, 0);
+ EXPECT_EQ(HexToInt(resp[0]->result), 1000);
+ EXPECT_EQ(resp[1]->ret, 0);
+ EXPECT_EQ(HexToInt(resp[1]->result), 1);
+ }
+ // LOG(ERROR)<<"commit time:"<<committer_->GetExecutionState()->commit_time<<"
+ // redo time:"<<committer_->GetExecutionState()->redo_time;
+ EXPECT_EQ(committer_->GetExecutionState()->commit_time, 2);
+ EXPECT_EQ(committer_->GetExecutionState()->redo_time, 0);
+}
+
+// a->b
+// a->b
+TEST_F(SequentialConcurrencyCommitterTest, TwoTxnConflict) {
+ Address transfer_receiver = get_random_address();
+ Address transfer_receiver2 = get_random_address();
+
+ bool start = false;
+ std::map<uint256_t, int> load_time;
+ EXPECT_CALL(*storage_, Load)
+ .WillRepeatedly(Invoke([&](const uint256_t& address) {
+ if (start) {
+ load_time[address]++;
+ }
+ return data_[address];
+ }));
+
+ EXPECT_CALL(*storage_, Store)
+ .WillRepeatedly(Invoke([&](const uint256_t& key, const uint256_t& value) {
+ if (start) {
+ bool done = false;
+ while (!done) {
+ for (auto it : load_time) {
+ if (it.second > 1) {
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+ int v = data_[key].second;
+ data_[key] = std::make_pair(value, v + 1);
+ }));
+
+ Init();
+ start = true;
+
+ // owner 1000
+ std::vector<ContractExecuteInfo> info;
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver));
+ func_params.add_param(U256ToString(100));
+
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address_, "",
+ func_params, 0));
+ }
+ {
+ Params func_params;
+ func_params.set_func_name("transfer(address,uint256)");
+ func_params.add_param(U256ToString(transfer_receiver2));
+ func_params.add_param(U256ToString(100));
+
+ info.push_back(ContractExecuteInfo(owner_address_, contract_address_, "",
+ func_params, 0));
+ }
+
+ {
+ std::vector<std::unique_ptr<ExecuteResp>> resp = ExecContract(info);
+ EXPECT_EQ(resp.size(), 2);
+ EXPECT_EQ(resp[0]->ret, 0);
+ EXPECT_EQ(HexToInt(resp[0]->result), 1);
+ EXPECT_EQ(resp[1]->ret, 0);
+ EXPECT_EQ(HexToInt(resp[1]->result), 1);
+ }
+ EXPECT_EQ(committer_->GetExecutionState()->commit_time, 2);
+ EXPECT_EQ(committer_->GetExecutionState()->redo_time, 1);
+}
+
+} // namespace
+} // namespace contract
+} // namespace resdb
diff --git a/platform/consensus/ordering/thunderbolt/executor/manager/streaming_committer.cpp b/platform/consensus/ordering/thunderbolt/executor/manager/streaming_committer.cpp
new file mode 100644
index 000000000..fb6c8232d
--- /dev/null
+++ b/platform/consensus/ordering/thunderbolt/executor/manager/streaming_committer.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2019-2022 ExpoLab, UC Davis
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "service/contract/executor/manager/streaming_committer.h"
+
+#include <future>
+#include <queue>
+
+#include "common/utils/utils.h"
+#include "eEVM/processor.h"
+#include "glog/logging.h"
+#include "service/contract/executor/manager/local_state.h"
+
+namespace resdb {
+namespace contract {
+namespace streaming {
+
+ExecutionContext::ExecutionContext(const ContractExecuteInfo& info) {
+ info_ = std::make_unique<ContractExecuteInfo>(info);
+}
+
+const ContractExecuteInfo* ExecutionContext::GetContractExecuteInfo() const {
+ return info_.get();
+}
+
+void ExecutionContext::SetResult(std::unique_ptr<ExecuteResp> result) {
+ result_ = std::move(result);
+}
+
+bool ExecutionContext::IsRedo() { return is_redo_; }
+
+void ExecutionContext::SetRedo() { is_redo_++; }
+
+int ExecutionContext::RedoTime() { return is_redo_; }
+
+std::unique_ptr<ExecuteResp> ExecutionContext::FetchResult() {
+ return std::move(result_);
+}
+
+ExecutionState* StreamingCommitter::GetExecutionState() {
+ return &execution_state_;
+}
+
+StreamingCommitter::StreamingCommitter(
+ DataStorage* storage, GlobalState* global_state, int window_size,
+ std::function<void(std::unique_ptr<ExecuteResp>)> call_back, int worker_num)
+ : storage_(storage),
+ gs_(global_state),
+ worker_num_(worker_num),
+ window_size_(window_size),
+ call_back_(call_back) {
+ controller_ = std::make_unique<StreamingController>(storage, window_size * 2);
+ executor_ = std::make_unique<ContractExecutor>();
+
+ resp_list_.resize(window_size_);
+ is_done_.resize(window_size_);
+ for (int i = 0; i < window_size_; ++i) {
+ is_done_[i] = false;
+ resp_list_[i] = nullptr;
+ }
+
+ first_id_ = 0;
+ last_id_ = 1;
+ is_stop_ = false;
+ id_ = 1;
+
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_.push_back(std::thread([&]() {
+ while (!is_stop_) {
+ auto request_ptr = request_queue_.Pop();
+ if (request_ptr == nullptr) {
+ continue;
+ }
+ ExecutionContext* request = *request_ptr;
+
+ LocalState local_state(controller_.get());
+ local_state.Set(
+ gs_->GetAccount(
+ request->GetContractExecuteInfo()->contract_address),
+ request->GetContractExecuteInfo()->commit_id);
+
+ std::unique_ptr<ExecuteResp> resp = std::make_unique<ExecuteResp>();
+ auto ret = ExecContract(
+ request->GetContractExecuteInfo()->caller_address,
+ request->GetContractExecuteInfo()->contract_address,
+ request->GetContractExecuteInfo()->func_addr,
+ request->GetContractExecuteInfo()->func_params, &local_state);
+ resp->state = ret.status();
+ resp->contract_address =
+ request->GetContractExecuteInfo()->contract_address;
+ resp->commit_id = request->GetContractExecuteInfo()->commit_id;
+ resp->user_id = request->GetContractExecuteInfo()->user_id;
+ // LOG(ERROR)<<"========= get resp commit
+ // id:"<<request->GetContractExecuteInfo()->commit_id<<" param:"<<
+ // request->GetContractExecuteInfo()->func_params.DebugString();
+ if (ret.ok()) {
+ resp->ret = 0;
+ resp->result = *ret;
+ if (request->IsRedo()) {
+ resp->retry_time = request->RedoTime();
+ // request->SetResult(std::move(resp));
+ }
+ local_state.Flesh(request->GetContractExecuteInfo()->contract_address,
+ request->GetContractExecuteInfo()->commit_id);
+ } else {
+ LOG(ERROR) << "commit :" << resp->commit_id << " fail";
+ resp->ret = -1;
+ assert(resp->ret >= 0);
+ }
+ resp_queue_.Push(std::move(resp));
+ }
+ }));
+ }
+
+ response_ = std::thread([&]() {
+ while (!is_stop_) {
+ ResponseProcess();
+ }
+ });
+}
+
+void StreamingCommitter::SetExecuteCallBack(
+ std::function<void(std::unique_ptr<ExecuteResp>)> func) {
+ call_back_ = std::move(func);
+}
+
+StreamingCommitter::~StreamingCommitter() {
+ is_stop_ = true;
+ for (int i = 0; i < worker_num_; ++i) {
+ workers_[i].join();
+ }
+ if (response_.joinable()) {
+ response_.join();
+ }
+}
+
+void StreamingCommitter::AddTask(int64_t commit_id,
+ std::unique_ptr<ExecutionContext> context) {
+ context_list_[commit_id % window_size_] = std::move(context);
+}
+
+void StreamingCommitter::RemoveTask(int64_t commit_id) {
+ context_list_.erase(context_list_.find(commit_id));
+}
+
+ExecutionContext* StreamingCommitter::GetTaskContext(int64_t commit_id) {
+ return context_list_[commit_id % window_size_].get();
+}
+
+void StreamingCommitter::CallBack(uint64_t commit_id) {
+ int idx = commit_id % window_size_;
+ if (call_back_) {
+ call_back_(std::move(resp_list_[idx]));
+ } else {
+ resp_list_[idx] = nullptr;
+ }
+ is_done_[idx] = true;
+
+ // LOG(ERROR)<<"current commit done call back commit id:"<<commit_id<<"
+ // idx:"<<idx<<" first id:"<<first_id_;
+ bool need_notify = false;
+ while (first_id_ < last_id_ && is_done_[(first_id_ + 1) % window_size_]) {
+ is_done_[(first_id_ + 1) % window_size_] = false;
+ first_id_++;
+ // LOG(ERROR)<<"commit:"<<first_id_;
+ need_notify = true;
+ }
+
+ if (need_notify) {
+ std::lock_guard<std::mutex> lk(mutex_);
+ cv_.notify_all();
+ }
+ // LOG(ERROR)<<"call back done:"<<first_id_<<" last id:"<<last_id_;
+}
+
+bool StreamingCommitter::WaitNext() {
+ while (!is_stop_) {
+ int timeout_ms = 10000;
+ std::unique_lock<std::mutex> lk(mutex_);
+ cv_.wait_for(lk, std::chrono::microseconds(timeout_ms),
+ [&] { return id_ - first_id_ < window_size_; });
+ if (id_ - first_id_ < window_size_) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool StreamingCommitter::WaitAll() {
+ while (!is_stop_) {
+ int timeout_ms = 10000;
+ std::unique_lock<std::mutex> lk(mutex_);
+ cv_.wait_for(lk, std::chrono::microseconds(timeout_ms), [&] {
+ return first_id_ > 0 && first_id_ % 500 == 0;
+ // return id_ - first_id_<window_size_;
+ });
+ if (id_ - first_id_ < window_size_) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void StreamingCommitter::ResponseProcess() {
+ auto resp = resp_queue_.Pop();
+ if (resp == nullptr) {
+ return;
+ }
+ int64_t resp_commit_id = resp->commit_id;
+ int idx = resp->commit_id % window_size_;
+ // LOG(ERROR)<<"recv :"<<resp_commit_id<<" idx:"<<idx;
+ resp_list_[idx] = std::move(resp);
+
+ if (resp_commit_id < last_id_) {
+ std::queue<int64_t> q;
+ q.push(resp_commit_id);
+ while (!q.empty()) {
+ int64_t next_id = q.front();
+ q.pop();
+
+ // LOG(ERROR)<<"!!!!!! commit retry:"<<next_id;
+ bool ret = controller_->Commit(next_id);
+ if (!ret) {
+ // LOG(ERROR)<<"retry:"<<next_id;
+ auto context_ptr = GetTaskContext(next_id);
+ // LOG(ERROR)<<"redo:"<<next_id;
+ context_ptr->SetRedo();
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ } else {
+ CallBack(next_id);
+ }
+ std::vector<int64_t> next_commit = controller_->GetRedo();
+ for (int64_t new_next : next_commit) {
+ if (next_id == new_next) {
+ continue;
+ }
+ q.push(new_next);
+ // LOG(ERROR)<<"get retry next:"<<new_next;
+ }
+ }
+ }
+ while (resp_list_[last_id_ % window_size_] != nullptr) {
+ int idx = last_id_ % window_size_;
+ int64_t current_commit_id = resp_list_[idx]->commit_id;
+ // LOG(ERROR)<<" !!!!! commit new resp:"<<current_commit_id;
+ bool ret = controller_->Commit(current_commit_id);
+ if (!ret) {
+ // LOG(ERROR)<<"redo size:"<<controller_->GetRedo().size();
+ if (controller_->GetRedo().size()) {
+ assert(controller_->GetRedo()[0] == current_commit_id);
+ // redo_list.push(commit_id);
+ // LOG(ERROR)<<"commit redo:"<<current_commit_id;
+ auto context_ptr = GetTaskContext(current_commit_id);
+ context_ptr->SetRedo();
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+ } else {
+ std::vector<int64_t> list = controller_->GetRedo();
+ assert(list.empty());
+ // LOG(ERROR)<<"commit done:"<<ret<<" last_id_:"<<last_id_<<" commit
+ // id:"<<current_commit_id<<" redo list:"<<list.size();
+ for (int64_t next_id : list) {
+ resp_list_[next_id % window_size_] = nullptr;
+ // redo_list.push(next_id);
+ // LOG(ERROR)<<"redo:"<<next_id;
+ auto context_ptr = GetTaskContext(next_id);
+ context_ptr->SetRedo();
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+ CallBack(current_commit_id);
+ }
+ last_id_++;
+ }
+}
+
+void StreamingCommitter::AsyncExecContract(
+ std::vector<ContractExecuteInfo>& requests) {
+ for (auto& request : requests) {
+ if (!WaitNext()) {
+ return;
+ }
+
+ int cur_idx = id_ % window_size_;
+ assert(id_ >= last_id_);
+
+ request.commit_id = id_++;
+ auto context = std::make_unique<ExecutionContext>(request);
+ auto context_ptr = context.get();
+
+ // LOG(ERROR)<<"execute:"<<request.commit_id<<" id:"<<id_<<" first
+ // id:"<<first_id_<<" last id:"<<last_id_<<" window:"<<window_size_<<"
+ // cur_idx:"<<cur_idx;
+ assert(resp_list_[cur_idx] == nullptr);
+
+ AddTask(cur_idx, std::move(context));
+ request_queue_.Push(std::make_unique<ExecutionContext*>(context_ptr));
+ }
+
+ return;
+}
+
+absl::StatusOr<std::string> StreamingCommitter::ExecContract(
... 41748 lines suppressed ...