This is an automated email from the ASF dual-hosted git repository.
junchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git
The following commit(s) were added to refs/heads/master by this push:
new aa54deb7 Support SmartContract with Key-Value (#171)
aa54deb7 is described below
commit aa54deb779e568a5adc84e3dad6e00a87fd6480f
Author: cjcchen <[email protected]>
AuthorDate: Fri Feb 14 15:45:09 2025 +0800
Support SmartContract with Key-Value (#171)
* add poe
* add
* update workflo
* add log
* change github name
* change img files
* fix workflow
* fix communicator
* rm log
* add base fairdag
* add fairdag
* add hs
* add hs
* add ooohs
* add tusk
* add rcc
* add rcc
* add config
* add cassandra
* add cassandra
* add prepare
* add prepare
* add cass 256
* add ooowq
* rcc done
* done
* rcc done
* add
* add fair
* add cass
* add poe
* fix execution response
* remove smallbank
* fix performance script
* add fairdag rl
* add graph
* add fair
* add
* done
* done
* done
* fix build
* add perf
* linear poe
* add
* update
* fix
* update
* update
* update
* update
* add log
* revert
* revert
* rm
* fix
* add storage
* add sm in kv
* add kv cmd for sm
* update
* add contact kv
* format
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* merge master
* add license
* fix build
* add boost
* add deps
---------
Co-authored-by: Ubuntu <[email protected]>
Co-authored-by: Ubuntu <[email protected]>
Co-authored-by: Ubuntu <[email protected]>
Co-authored-by: Ubuntu <[email protected]>
Co-authored-by: junchao <junchao@localhost>
---
WORKSPACE | 2 +-
executor/common/transaction_manager.cpp | 44 +++
executor/common/transaction_manager.h | 10 +
executor/contract/executor/BUILD | 1 +
executor/contract/executor/contract_executor.cpp | 55 +++-
executor/contract/executor/contract_executor.h | 6 +-
.../contract/executor/contract_executor_test.cpp | 266 +++++++++++++++++-
executor/contract/executor/test_data/contract.json | 18 +-
executor/contract/executor/test_data/token.json | 13 +
executor/contract/manager/BUILD | 36 +++
executor/contract/manager/contract_manager.cpp | 14 +-
executor/contract/manager/contract_manager.h | 9 +-
.../contract/manager/contract_manager_test.cpp | 13 +-
.../contract/manager/evm_state.h | 57 ++--
executor/contract/manager/global_state.cpp | 87 ++++++
executor/contract/manager/global_state.h | 63 +++++
.../contract/manager/global_view.cpp | 49 ++--
.../contract/manager/global_view.h | 58 ++--
executor/kv/BUILD | 1 +
executor/kv/kv_executor.cpp | 67 ++++-
executor/kv/kv_executor.h | 6 +
interface/contract/contract_client.cpp | 13 -
interface/contract/contract_client.h | 1 -
interface/kv/BUILD | 14 +
interface/{contract => kv}/contract_client.cpp | 71 +++--
interface/{contract => kv}/contract_client.h | 8 +-
platform/config/resdb_config.cpp | 5 +-
platform/config/resdb_config.h | 15 +-
.../consensus/execution/transaction_executor.cpp | 309 +++++++++++++++++++--
.../consensus/execution/transaction_executor.h | 49 +++-
platform/networkstrate/replica_communicator.cpp | 91 +++++-
platform/networkstrate/replica_communicator.h | 15 +-
platform/proto/resdb.proto | 1 +
proto/contract/rpc.proto | 19 +-
proto/kv/kv.proto | 2 +
service/contract/BUILD | 1 +
service/contract/contract_service.cpp | 4 +-
.../tools/contract/api_tools/contract_tools.cpp | 115 ++++----
.../tools/contract/api_tools/create.js | 35 +--
.../tools/contract/api_tools/deploy.js | 38 +--
.../contract/api_tools/example_contract/token.json | 16 +-
.../contract/api_tools/example_contract/token.sol | 14 +
.../tools/contract/api_tools/execute.js | 39 +--
.../service_tools/start_contract_service.sh | 3 +
service/tools/kv/api_tools/BUILD | 12 +
.../api_tools/contract_service_tools.cpp} | 129 +++++----
.../tools/kv/api_tools/create.js | 34 +--
.../tools/kv/api_tools/deploy.js | 38 +--
.../tools/kv/api_tools/example_contract/compile.sh | 21 ++
.../tools/kv/api_tools/example_contract/token.json | 13 +
.../api_tools/example_contract/token.sol | 14 +
.../tools/kv/api_tools/execute.js | 39 +--
.../tools/kv/api_tools/get_balance.js | 35 +--
.../tools/kv/api_tools/set_balance.js | 36 +--
54 files changed, 1529 insertions(+), 595 deletions(-)
diff --git a/WORKSPACE b/WORKSPACE
index 93a66164..0b898a36 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -177,7 +177,7 @@ http_archive(
http_archive(
name = "pybind11_bazel",
strip_prefix = "pybind11_bazel-2.11.1.bzl.1",
- urls =
["https://github.com/pybind/pybind11_bazel/archive/refs/tags/v2.11.1.bzl.1.zip"],
+ urls =
["https://github.com/pybind/pybind11_bazel/archive/refs/tags/v2.11.1.bzl.1.zip"]
)
http_archive(
diff --git a/executor/common/transaction_manager.cpp
b/executor/common/transaction_manager.cpp
index 036f9619..74df05c9 100644
--- a/executor/common/transaction_manager.cpp
+++ b/executor/common/transaction_manager.cpp
@@ -35,6 +35,50 @@ std::unique_ptr<std::string> TransactionManager::ExecuteData(
return std::make_unique<std::string>();
}
+std::unique_ptr<google::protobuf::Message> TransactionManager::ParseData(
+ const std::string& data) {
+ return nullptr;
+}
+
+std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>
+TransactionManager::Prepare(const BatchUserRequest& request) {
+ std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>
+ batch_response = std::make_unique<
+ std::vector<std::unique_ptr<google::protobuf::Message>>>();
+ {
+ for (auto& sub_request : request.user_requests()) {
+ std::unique_ptr<google::protobuf::Message> response =
+ ParseData(sub_request.request().data());
+ batch_response->push_back(std::move(response));
+ }
+ // LOG(ERROR)<<"prepare data size:"<<batch_response.size();
+ }
+
+ return batch_response;
+}
+
+std::unique_ptr<std::string> TransactionManager::ExecuteRequest(
+ const google::protobuf::Message& request) {
+ return nullptr;
+}
+
+std::vector<std::unique_ptr<std::string>> TransactionManager::ExecuteBatchData(
+ const std::vector<std::unique_ptr<google::protobuf::Message>>& requests) {
+ // LOG(ERROR)<<"execute data:"<<requests.size();
+ std::vector<std::unique_ptr<std::string>> ret;
+ {
+ for (auto& sub_request : requests) {
+ std::unique_ptr<std::string> response = ExecuteRequest(*sub_request);
+ if (response == nullptr) {
+ response = std::make_unique<std::string>();
+ }
+ ret.push_back(std::move(response));
+ }
+ }
+ return ret;
+}
+
+
std::unique_ptr<BatchUserResponse> TransactionManager::ExecuteBatch(
const BatchUserRequest& request) {
std::unique_ptr<BatchUserResponse> batch_response =
diff --git a/executor/common/transaction_manager.h
b/executor/common/transaction_manager.h
index 16e1a58d..b1d564ac 100644
--- a/executor/common/transaction_manager.h
+++ b/executor/common/transaction_manager.h
@@ -40,6 +40,11 @@ class TransactionManager {
virtual std::unique_ptr<BatchUserResponse> ExecuteBatch(
const BatchUserRequest& request);
+ std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>
+ Prepare(const BatchUserRequest& request);
+
+ std::vector<std::unique_ptr<std::string>> ExecuteBatchData(
+ const std::vector<std::unique_ptr<google::protobuf::Message>>& requests);
virtual std::unique_ptr<std::string> ExecuteData(const std::string& request);
bool IsOutOfOrder();
@@ -48,6 +53,11 @@ class TransactionManager {
virtual Storage* GetStorage() { return nullptr; };
+ protected:
+ virtual std::unique_ptr<google::protobuf::Message> ParseData(
+ const std::string& data);
+ virtual std::unique_ptr<std::string> ExecuteRequest(
+ const google::protobuf::Message& request);
private:
bool is_out_of_order_ = false;
bool need_response_ = true;
diff --git a/executor/contract/executor/BUILD b/executor/contract/executor/BUILD
index c6e40c65..dfffaf15 100644
--- a/executor/contract/executor/BUILD
+++ b/executor/contract/executor/BUILD
@@ -40,6 +40,7 @@ cc_test(
tags = ["manual"],
deps = [
":contract_executor",
+ "//chain/storage:memory_db",
"//common/test:test_main",
],
)
diff --git a/executor/contract/executor/contract_executor.cpp
b/executor/contract/executor/contract_executor.cpp
index ad1c6057..99f6f205 100644
--- a/executor/contract/executor/contract_executor.cpp
+++ b/executor/contract/executor/contract_executor.cpp
@@ -24,8 +24,8 @@
namespace resdb {
namespace contract {
-ContractTransactionManager::ContractTransactionManager(void)
- : contract_manager_(std::make_unique<ContractManager>()),
+ContractTransactionManager::ContractTransactionManager(Storage * storage)
+ : contract_manager_(std::make_unique<ContractManager>(storage)),
address_manager_(std::make_unique<AddressManager>()) {}
std::unique_ptr<std::string> ContractTransactionManager::ExecuteData(
@@ -37,32 +37,42 @@ std::unique_ptr<std::string>
ContractTransactionManager::ExecuteData(
LOG(ERROR) << "parse data fail";
return nullptr;
}
-
int ret = 0;
- if (request.cmd() == Request::CREATE_ACCOUNT) {
+ if (request.cmd() == contract::Request::CREATE_ACCOUNT) {
absl::StatusOr<Account> account_or = CreateAccount();
if (account_or.ok()) {
response.mutable_account()->Swap(&(*account_or));
+ LOG(ERROR)<<" create count:"<<response.account().DebugString();
} else {
ret = -1;
}
- } else if (request.cmd() == Request::DEPLOY) {
+ } else if (request.cmd() == contract::Request::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) {
+ } else if (request.cmd() == contract::Request::EXECUTE) {
auto res_or = Execute(request);
if (res_or.ok()) {
response.set_res(*res_or);
} else {
ret = -1;
}
- } else if (request.cmd() == Request::ADD_ADDRESS) { // New command handling
- absl::Status status = AddAddress(request);
- if (!status.ok()) {
+ } else if (request.cmd() == resdb::contract::Request::GETBALANCE) {
+ auto res_or = GetBalance(request);
+ if (res_or.ok()) {
+ response.set_res(*res_or);
+ } else {
+ ret = -1;
+ }
+
+ } else if (request.cmd() == resdb::contract::Request::SETBALANCE) {
+ auto res_or = SetBalance(request);
+ if (res_or.ok()) {
+ response.set_res("1");
+ } else {
ret = -1;
}
}
@@ -85,12 +95,6 @@ absl::StatusOr<Account>
ContractTransactionManager::CreateAccount() {
return account;
}
-absl::Status ContractTransactionManager::AddAddress(const Request& request) {
- Address address = AddressManager::HexToAddress(request.external_address());
- address_manager_->AddExternalAddress(address);
- return absl::OkStatus();
-}
-
absl::StatusOr<Contract> ContractTransactionManager::Deploy(
const Request& request) {
Address caller_address =
@@ -128,5 +132,26 @@ absl::StatusOr<std::string>
ContractTransactionManager::Execute(
request.func_params());
}
+absl::StatusOr<std::string> ContractTransactionManager::GetBalance(
+ const Request& request) {
+
+ Address account =
+ AddressManager::HexToAddress(request.account());
+ return contract_manager_->GetBalance(account);
+}
+
+absl::StatusOr<std::string> ContractTransactionManager::SetBalance(
+ const Request& request) {
+
+ Address account =
+ AddressManager::HexToAddress(request.account());
+ Address balance =
+ AddressManager::HexToAddress(request.balance());
+ int ret = contract_manager_->SetBalance(account, balance);
+ return std::to_string(ret);
+}
+
+
+
} // namespace contract
} // namespace resdb
diff --git a/executor/contract/executor/contract_executor.h
b/executor/contract/executor/contract_executor.h
index a5002598..489f822f 100644
--- a/executor/contract/executor/contract_executor.h
+++ b/executor/contract/executor/contract_executor.h
@@ -31,7 +31,7 @@ namespace contract {
class ContractTransactionManager : public TransactionManager {
public:
- ContractTransactionManager(void);
+ ContractTransactionManager(Storage * storage);
virtual ~ContractTransactionManager() = default;
std::unique_ptr<std::string> ExecuteData(const std::string& request)
override;
@@ -40,7 +40,9 @@ class ContractTransactionManager : public TransactionManager {
absl::StatusOr<Account> CreateAccount();
absl::StatusOr<Contract> Deploy(const Request& request);
absl::StatusOr<std::string> Execute(const Request& request);
- absl::Status AddAddress(const Request& request);
+
+ absl::StatusOr<std::string> GetBalance(const Request& request);
+ absl::StatusOr<std::string> SetBalance(const Request& request);
private:
std::unique_ptr<ContractManager> contract_manager_;
diff --git a/executor/contract/executor/contract_executor_test.cpp
b/executor/contract/executor/contract_executor_test.cpp
index b8b63aec..8f7d44de 100644
--- a/executor/contract/executor/contract_executor_test.cpp
+++ b/executor/contract/executor/contract_executor_test.cpp
@@ -19,6 +19,8 @@
#include "executor/contract/executor/contract_executor.h"
+#include "chain/storage/memory_db.h"
+
#include <glog/logging.h>
#include <gtest/gtest.h>
@@ -29,10 +31,11 @@ namespace contract {
namespace {
using ::testing::Test;
+using resdb::storage::MemoryDB;
const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
std::string(getenv("TEST_WORKSPACE")) +
- "/service/contract/executor/service/";
+ "/executor/contract/executor/";
std::string ToString(const Request& request) {
std::string ret;
@@ -42,8 +45,9 @@ std::string ToString(const Request& request) {
class ContractTransactionManagerTest : public Test {
public:
- ContractTransactionManagerTest() {
+ ContractTransactionManagerTest() : executor_(&db_) {
std::string contract_path = test_dir + "test_data/contract.json";
+ contract_name_ = "token.sol:Token";
std::ifstream contract_fstream(contract_path);
if (!contract_fstream) {
@@ -109,8 +113,49 @@ class ContractTransactionManagerTest : public Test {
}
}
+ absl::StatusOr<uint256_t> GetBalance(const std::string& account_address) {
+ Request request;
+ Response response;
+
+ request.set_account(account_address);
+ request.set_cmd(Request::GETBALANCE);
+
+ 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.");
+ }
+ }
+
+ absl::StatusOr<std::string> SetBalance(const std::string& account_address,
const std::string& balance) {
+ Request request;
+ Response response;
+
+ request.set_account(account_address);
+ request.set_balance(balance);
+ request.set_cmd(Request::SETBALANCE);
+
+ std::unique_ptr<std::string> ret =
executor_.ExecuteData(ToString(request));
+ EXPECT_TRUE(ret != nullptr);
+
+ response.ParseFromString(*ret);
+
+ if (response.ret() == 0) {
+ return response.res();
+ } else {
+ return absl::InternalError("DeployFail.");
+ }
+ }
+
protected:
+ std::string contract_name_;
nlohmann::json contracts_json_;
+ MemoryDB db_;
ContractTransactionManager executor_;
};
@@ -119,7 +164,7 @@ TEST_F(ContractTransactionManagerTest, ExecContract) {
Account account = CreateAccount();
EXPECT_FALSE(account.address().empty());
- std::string contract_name = "ERC20.sol:ERC20Token";
+ std::string contract_name = contract_name_;
std::string contract_code = contracts_json_[contract_name]["bin"];
nlohmann::json func_hashes = contracts_json_[contract_name]["hashes"];
@@ -203,7 +248,7 @@ TEST_F(ContractTransactionManagerTest, DeployFail) {
Account account = CreateAccount();
EXPECT_FALSE(account.address().empty());
- std::string contract_name = "ERC20.sol:ERC20Token";
+ std::string contract_name = contract_name_;
std::string contract_code = contracts_json_[contract_name]["bin"];
nlohmann::json func_hashes = contracts_json_[contract_name]["hashes"];
@@ -228,7 +273,7 @@ TEST_F(ContractTransactionManagerTest, NoFunc) {
Account account = CreateAccount();
EXPECT_FALSE(account.address().empty());
- std::string contract_name = "ERC20.sol:ERC20Token";
+ std::string contract_name = contract_name_;
std::string contract_code = contracts_json_[contract_name]["bin"];
nlohmann::json func_hashes = contracts_json_[contract_name]["hashes"];
@@ -259,6 +304,217 @@ TEST_F(ContractTransactionManagerTest, NoFunc) {
}
}
+TEST_F(ContractTransactionManagerTest, GetFromKV) {
+ // create an account.
+ Account account = CreateAccount();
+ EXPECT_FALSE(account.address().empty());
+
+ std::string contract_name = contract_name_;
+ 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);
+
+ {
+ auto result = GetBalance(account.address());
+ 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);
+
+ {
+ auto result = GetBalance(transfer_receiver.address());
+ EXPECT_EQ(*result, 400);
+ }
+ }
+
+ {
+
+ {
+ auto result = SetBalance(account.address(), "1000");
+ EXPECT_EQ(*result, "1");
+ }
+ 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, 1000);
+
+ {
+ auto result = GetBalance(account.address());
+ EXPECT_EQ(*result, 1000);
+ }
+ }
+}
+
+TEST_F(ContractTransactionManagerTest, GetFromKV2) {
+ // create an account.
+ Account account = CreateAccount();
+ EXPECT_FALSE(account.address().empty());
+
+ std::string contract_name = contract_name_;
+ 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("0x1be8e78d765a2e63339fc99a66320db73158a35a");
+
+ 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("0x1be8e78d765a2e63339fc99a66320db73158a35a");
+ 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);
+
+ {
+ auto result = GetBalance(account.address());
+ EXPECT_EQ(*result, 600);
+ }
+ }
+
+ // receiver 400
+ {
+ Params func_params;
+ func_params.set_func_name("balanceOf(address)");
+ func_params.add_param("0x1be8e78d765a2e63339fc99a66320db73158a35a");
+
+ auto result =
+ Execute(account.address(), contract.contract_address(), func_params);
+ EXPECT_EQ(*result, 400);
+
+ {
+ auto result = GetBalance("0x1be8e78d765a2e63339fc99a66320db73158a35a");
+ EXPECT_EQ(*result, 400);
+ }
+ }
+
+}
+
+
+
} // namespace
} // namespace contract
} // namespace resdb
diff --git a/executor/contract/executor/test_data/contract.json
b/executor/contract/executor/test_data/contract.json
index e9c0d972..eaeaa36f 100644
--- a/executor/contract/executor/test_data/contract.json
+++ b/executor/contract/executor/test_data/contract.json
@@ -1,19 +1,13 @@
{
- "contracts":
- {
- "ERC20.sol:ERC20Token":
- {
- "bin":
"608060405234801561001057600080fd5b506040516104423803806104428339818101604052602081101561003357600080fd5b50516000818155338152600160205260409020556103ec806100566000396000f3fe608060405234801561001057600080fd5b506004361061007e577c01000000000000000000000000000000000000000000000000000000006000350463095ea7b3811461008357806318160ddd146100c357806323b872dd146100dd57806370a0823114610113578063a9059cbb14610139578063dd62ed3e14610165575b600080fd5b6100af6004803603604081101561009957600080fd
[...]
- "hashes":
- {
- "allowance(address,address)": "dd62ed3e",
- "approve(address,uint256)": "095ea7b3",
+ "contracts": {
+ "token.sol:Token": {
+ "bin":
"6080604052348015600f57600080fd5b506040516103f83803806103f8833981016040819052602c916040565b336000908152602081905260409020556058565b600060208284031215605157600080fd5b5051919050565b610391806100676000396000f3fe608060405234801561001057600080fd5b506004361061005d577c0100000000000000000000000000000000000000000000000000000000600035046370a082318114610062578063a5f2a1521461009e578063a9059cbb146100c1575b600080fd5b61008b610070366004610284565b600160a060020a03166000908152602081905260409020
[...]
+ "hashes": {
"balanceOf(address)": "70a08231",
- "totalSupply()": "18160ddd",
"transfer(address,uint256)": "a9059cbb",
- "transferFrom(address,address,uint256)": "23b872dd"
+ "transferTo(address,address,uint256)": "a5f2a152"
}
}
},
- "version": "0.5.16+commit.9c3226ce.Linux.g++"
+ "version": "0.8.28+commit.7893614a.Linux.g++"
}
diff --git a/executor/contract/executor/test_data/token.json
b/executor/contract/executor/test_data/token.json
new file mode 100644
index 00000000..eaeaa36f
--- /dev/null
+++ b/executor/contract/executor/test_data/token.json
@@ -0,0 +1,13 @@
+{
+ "contracts": {
+ "token.sol:Token": {
+ "bin":
"6080604052348015600f57600080fd5b506040516103f83803806103f8833981016040819052602c916040565b336000908152602081905260409020556058565b600060208284031215605157600080fd5b5051919050565b610391806100676000396000f3fe608060405234801561001057600080fd5b506004361061005d577c0100000000000000000000000000000000000000000000000000000000600035046370a082318114610062578063a5f2a1521461009e578063a9059cbb146100c1575b600080fd5b61008b610070366004610284565b600160a060020a03166000908152602081905260409020
[...]
+ "hashes": {
+ "balanceOf(address)": "70a08231",
+ "transfer(address,uint256)": "a9059cbb",
+ "transferTo(address,address,uint256)": "a5f2a152"
+ }
+ }
+ },
+ "version": "0.8.28+commit.7893614a.Linux.g++"
+}
diff --git a/executor/contract/manager/BUILD b/executor/contract/manager/BUILD
index f1d26925..ee570c37 100644
--- a/executor/contract/manager/BUILD
+++ b/executor/contract/manager/BUILD
@@ -33,6 +33,7 @@ cc_library(
deps = [
":address_manager",
":utils",
+ ":global_state",
"//common:comm",
"//proto/contract:func_params_cc_proto",
],
@@ -47,6 +48,7 @@ cc_test(
tags = ["manual"],
deps = [
":contract_manager",
+ "//chain/storage:memory_db",
"//common/test:test_main",
],
)
@@ -69,3 +71,37 @@ cc_test(
"//common/test:test_main",
],
)
+
+cc_library(
+ name = "global_view",
+ srcs = ["global_view.cpp"],
+ hdrs = ["global_view.h"],
+ deps = [
+ ":utils",
+ "//chain/storage:storage",
+ "//common:comm",
+ ],
+)
+
+
+cc_library(
+ name = "evm_state",
+ hdrs = ["evm_state.h"],
+ deps = [
+ ":utils",
+ "//common:comm",
+ ],
+)
+
+
+cc_library(
+ name = "global_state",
+ srcs = ["global_state.cpp"],
+ hdrs = ["global_state.h"],
+ deps = [
+ ":evm_state",
+ ":global_view",
+ "//common:comm",
+ ],
+)
+
diff --git a/executor/contract/manager/contract_manager.cpp
b/executor/contract/manager/contract_manager.cpp
index 426a0b8a..862fc7e5 100644
--- a/executor/contract/manager/contract_manager.cpp
+++ b/executor/contract/manager/contract_manager.cpp
@@ -36,8 +36,8 @@ void AppendArgToInput(std::vector<uint8_t>& code, const
std::string& arg) {
AppendArgToInput(code, eevm::to_uint256(arg));
}
-ContractManager::ContractManager() {
- gs_ = std::make_unique<eevm::SimpleGlobalState>();
+ContractManager::ContractManager(Storage* storage) {
+ gs_ = std::make_unique<GlobalState>(storage);
}
std::string ContractManager::GetFuncAddress(const Address& contract_address,
@@ -84,7 +84,7 @@ Address ContractManager::DeployContract(const Address&
owner_address,
absl::StatusOr<eevm::AccountState> ContractManager::GetContract(
const Address& address) {
- if (!gs_->exists(address)) {
+ if (!gs_->Exists(address)) {
return absl::InvalidArgumentError("Contract not exist.");
}
@@ -144,5 +144,13 @@ absl::StatusOr<std::vector<uint8_t>>
ContractManager::Execute(
}
}
+std::string ContractManager::GetBalance(const Address& account) {
+ return gs_->GetBalance(account);
+}
+
+int ContractManager::SetBalance(const Address& account, const uint256_t&
balance) {
+ return gs_->SetBalance(account, balance);
+}
+
} // namespace contract
} // namespace resdb
diff --git a/executor/contract/manager/contract_manager.h
b/executor/contract/manager/contract_manager.h
index 7e250aa6..d5347fae 100644
--- a/executor/contract/manager/contract_manager.h
+++ b/executor/contract/manager/contract_manager.h
@@ -22,7 +22,9 @@
#include "absl/status/statusor.h"
#include "eEVM/opcode.h"
#include "eEVM/simple/simpleglobalstate.h"
+#include "chain/storage/storage.h"
#include "executor/contract/manager/utils.h"
+#include "executor/contract/manager/global_state.h"
#include "proto/contract/func_params.pb.h"
namespace resdb {
@@ -30,7 +32,7 @@ namespace contract {
class ContractManager {
public:
- ContractManager();
+ ContractManager(Storage* storage);
public:
Address DeployContract(const Address& owner_address,
@@ -42,6 +44,9 @@ class ContractManager {
const Address& contract_address,
const Params& func_param);
+ std::string GetBalance(const Address& account);
+ int SetBalance(const Address& account, const uint256_t& balance);
+
private:
std::string GetFuncAddress(const Address& contract_address,
const std::string& func_name);
@@ -52,7 +57,7 @@ class ContractManager {
const std::vector<uint8_t>& func_para);
private:
- std::unique_ptr<eevm::SimpleGlobalState> gs_;
+ std::unique_ptr<GlobalState> gs_;
std::map<Address, std::map<std::string, std::string>> func_address_;
};
diff --git a/executor/contract/manager/contract_manager_test.cpp
b/executor/contract/manager/contract_manager_test.cpp
index 32540bd4..db36d188 100644
--- a/executor/contract/manager/contract_manager_test.cpp
+++ b/executor/contract/manager/contract_manager_test.cpp
@@ -25,12 +25,14 @@
#include <fstream>
#include "executor/contract/manager/address_manager.h"
+#include "chain/storage/memory_db.h"
namespace resdb {
namespace contract {
namespace {
using ::testing::Test;
+using resdb::storage::MemoryDB;
const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" +
std::string(getenv("TEST_WORKSPACE")) +
@@ -61,16 +63,17 @@ class ContractManagerTest : public Test {
protected:
Address owner_address_;
nlohmann::json contract_json_;
+ MemoryDB db_;
};
TEST_F(ContractManagerTest, NoContract) {
- ContractManager manager;
+ ContractManager manager(&db_);
auto account = manager.GetContract(1234);
EXPECT_FALSE(account.ok());
}
TEST_F(ContractManagerTest, DeployContract) {
- ContractManager manager;
+ ContractManager manager(&db_);
DeployInfo deploy_info;
deploy_info.set_contract_bin(contract_json_["bin"]);
@@ -90,7 +93,7 @@ TEST_F(ContractManagerTest, DeployContract) {
}
TEST_F(ContractManagerTest, InitContract) {
- ContractManager manager;
+ ContractManager manager(&db_);
DeployInfo deploy_info;
deploy_info.set_contract_bin(contract_json_["bin"]);
@@ -116,7 +119,7 @@ TEST_F(ContractManagerTest, InitContract) {
}
TEST_F(ContractManagerTest, ExecContract) {
- ContractManager manager;
+ ContractManager manager(&db_);
DeployInfo deploy_info;
deploy_info.set_contract_bin(contract_json_["bin"]);
@@ -217,7 +220,7 @@ TEST_F(ContractManagerTest, ExecContract) {
}
TEST_F(ContractManagerTest, NoFunc) {
- ContractManager manager;
+ ContractManager manager(&db_);
DeployInfo deploy_info;
deploy_info.set_contract_bin(contract_json_["bin"]);
diff --git a/proto/contract/rpc.proto b/executor/contract/manager/evm_state.h
similarity index 53%
copy from proto/contract/rpc.proto
copy to executor/contract/manager/evm_state.h
index 8df1dd40..26fe199e 100644
--- a/proto/contract/rpc.proto
+++ b/executor/contract/manager/evm_state.h
@@ -17,36 +17,27 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
-}
+
+#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/executor/contract/manager/global_state.cpp
b/executor/contract/manager/global_state.cpp
new file mode 100644
index 00000000..77ff82d3
--- /dev/null
+++ b/executor/contract/manager/global_state.cpp
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#include "executor/contract/manager/global_state.h"
+
+#include <glog/logging.h>
+
+namespace resdb {
+namespace contract {
+
+using eevm::AccountState;
+using eevm::Address;
+using eevm::Code;
+using eevm::SimpleAccount;
+
+
+uint256_t AccountToAddress(const eevm::Address& account) {
+ std::vector<uint8_t> code;
+ code.resize(64);
+ std::fill(code.begin(), code.end(), 0);
+ eevm::to_big_endian(account, code.data());
+
+ uint8_t h[32];
+ eevm::keccak_256(code.data(), static_cast<unsigned int>(64), h);
+ return eevm::from_big_endian(h, sizeof(h));
+}
+
+GlobalState::GlobalState(resdb::Storage* 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);
+}
+
+std::string GlobalState::GetBalance(const eevm::Address& account) {
+ return storage_->GetValue(eevm::to_hex_string(AccountToAddress(account)));
+}
+
+int GlobalState::SetBalance(const eevm::Address& account, const uint256_t&
balance) {
+ return storage_->SetValue(eevm::to_hex_string(AccountToAddress(account)),
eevm::to_hex_string(balance));
+}
+
+} // namespace contract
+} // namespace resdb
diff --git a/executor/contract/manager/global_state.h
b/executor/contract/manager/global_state.h
new file mode 100644
index 00000000..0320e35e
--- /dev/null
+++ b/executor/contract/manager/global_state.h
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#pragma once
+
+#include "eEVM/simple/simpleaccount.h"
+#include "executor/contract/manager/evm_state.h"
+#include "executor/contract/manager/global_view.h"
+
+namespace resdb {
+namespace contract {
+
+class GlobalState : public EVMState {
+ public:
+ using StateEntry = std::pair<eevm::SimpleAccount, GlobalView>;
+
+ public:
+ GlobalState(resdb::Storage* 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);
+
+ std::string GetBalance(const eevm::Address& account);
+ int SetBalance(const eevm::Address& account, const uint256_t& balance);
+
+ protected:
+ void Insert(const StateEntry& p);
+
+ private:
+ std::map<eevm::Address, StateEntry> accounts;
+ resdb::Storage* storage_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/proto/contract/rpc.proto
b/executor/contract/manager/global_view.cpp
similarity index 53%
copy from proto/contract/rpc.proto
copy to executor/contract/manager/global_view.cpp
index 8df1dd40..0fbbbef2 100644
--- a/proto/contract/rpc.proto
+++ b/executor/contract/manager/global_view.cpp
@@ -17,36 +17,27 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
+#include "executor/contract/manager/global_view.h"
+
+#include <glog/logging.h>
+
+#include "eEVM/util.h"
+
+namespace resdb {
+namespace contract {
+GlobalView::GlobalView(resdb::Storage* storage) : storage_(storage) {}
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+void GlobalView::store(const uint256_t& key, const uint256_t& value) {
+ storage_->SetValue(eevm::to_hex_string(key), eevm::to_hex_string(value));
}
+
+uint256_t GlobalView::load(const uint256_t& key) {
+ return eevm::to_uint256(storage_->GetValue(eevm::to_hex_string(key)));
+}
+
+bool GlobalView::remove(const uint256_t& key) { return true; }
+
+} // namespace contract
+} // namespace resdb
diff --git a/proto/contract/rpc.proto b/executor/contract/manager/global_view.h
similarity index 52%
copy from proto/contract/rpc.proto
copy to executor/contract/manager/global_view.h
index 8df1dd40..6fdfc583 100644
--- a/proto/contract/rpc.proto
+++ b/executor/contract/manager/global_view.h
@@ -17,36 +17,28 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
-}
+#pragma once
+
+#include <map>
+
+#include "eEVM/storage.h"
+#include "chain/storage/storage.h"
+
+namespace resdb {
+namespace contract {
+
+class GlobalView : public eevm::Storage {
+ public:
+ GlobalView(resdb::Storage* 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:
+ resdb::Storage* storage_;
+};
+
+} // namespace contract
+} // namespace resdb
diff --git a/executor/kv/BUILD b/executor/kv/BUILD
index 09f75c24..d8a47bcf 100644
--- a/executor/kv/BUILD
+++ b/executor/kv/BUILD
@@ -30,6 +30,7 @@ cc_library(
"//executor/common:transaction_manager",
"//platform/config:resdb_config_utils",
"//proto/kv:kv_cc_proto",
+ "//executor/contract/executor:contract_executor",
],
)
diff --git a/executor/kv/kv_executor.cpp b/executor/kv/kv_executor.cpp
index 742253b0..cf294174 100644
--- a/executor/kv/kv_executor.cpp
+++ b/executor/kv/kv_executor.cpp
@@ -18,13 +18,72 @@
*/
#include "executor/kv/kv_executor.h"
+#include "executor/contract/executor/contract_executor.h"
#include <glog/logging.h>
namespace resdb {
KVExecutor::KVExecutor(std::unique_ptr<Storage> storage)
- : storage_(std::move(storage)) {}
+ : storage_(std::move(storage)) {
+ contract_manager_ =
std::make_unique<resdb::contract::ContractTransactionManager>(storage_.get());
+}
+
+std::unique_ptr<google::protobuf::Message> KVExecutor::ParseData(
+ const std::string& request) {
+ std::unique_ptr<KVRequest> kv_request = std::make_unique<KVRequest>();
+ if (!kv_request->ParseFromString(request)) {
+ LOG(ERROR) << "parse data fail";
+ return nullptr;
+ }
+ return kv_request;
+}
+
+std::unique_ptr<std::string> KVExecutor::ExecuteRequest(
+ const google::protobuf::Message& request) {
+ KVResponse kv_response;
+ const KVRequest& kv_request = dynamic_cast<const KVRequest&>(request);
+ // LOG(ERROR)<<"execute request:";
+
+ if (kv_request.cmd() == KVRequest::SET) {
+ Set(kv_request.key(), kv_request.value());
+ } else if (kv_request.cmd() == KVRequest::GET) {
+ kv_response.set_value(Get(kv_request.key()));
+ } else if (kv_request.cmd() == KVRequest::GETALLVALUES) {
+ kv_response.set_value(GetAllValues());
+ } else if (kv_request.cmd() == KVRequest::GETRANGE) {
+ kv_response.set_value(GetRange(kv_request.key(), kv_request.value()));
+ } else if (kv_request.cmd() == KVRequest::SET_WITH_VERSION) {
+ SetWithVersion(kv_request.key(), kv_request.value(), kv_request.version());
+ } else if (kv_request.cmd() == KVRequest::GET_WITH_VERSION) {
+ GetWithVersion(kv_request.key(), kv_request.version(),
+ kv_response.mutable_value_info());
+ } else if (kv_request.cmd() == KVRequest::GET_ALL_ITEMS) {
+ GetAllItems(kv_response.mutable_items());
+ } else if (kv_request.cmd() == KVRequest::GET_KEY_RANGE) {
+ GetKeyRange(kv_request.min_key(), kv_request.max_key(),
+ kv_response.mutable_items());
+ } else if (kv_request.cmd() == KVRequest::GET_HISTORY) {
+ GetHistory(kv_request.key(), kv_request.min_version(),
+ kv_request.max_version(), kv_response.mutable_items());
+ } else if (kv_request.cmd() == KVRequest::GET_TOP) {
+ GetTopHistory(kv_request.key(), kv_request.top_number(),
+ kv_response.mutable_items());
+ }
+ else if(!kv_request.smart_contract_request().empty()){
+ std::unique_ptr<std::string> resp =
contract_manager_->ExecuteData(kv_request.smart_contract_request());
+ if(resp != nullptr){
+ kv_response.set_smart_contract_response(*resp);
+ }
+ }
+
+ std::unique_ptr<std::string> resp_str = std::make_unique<std::string>();
+ if (!kv_response.SerializeToString(resp_str.get())) {
+ return nullptr;
+ }
+
+ return resp_str;
+}
std::unique_ptr<std::string> KVExecutor::ExecuteData(
const std::string& request) {
@@ -61,6 +120,12 @@ std::unique_ptr<std::string> KVExecutor::ExecuteData(
GetTopHistory(kv_request.key(), kv_request.top_number(),
kv_response.mutable_items());
}
+ else if(!kv_request.smart_contract_request().empty()){
+ std::unique_ptr<std::string> resp =
contract_manager_->ExecuteData(kv_request.smart_contract_request());
+ if(resp != nullptr){
+ kv_response.set_smart_contract_response(*resp);
+ }
+ }
std::unique_ptr<std::string> resp_str = std::make_unique<std::string>();
if (!kv_response.SerializeToString(resp_str.get())) {
diff --git a/executor/kv/kv_executor.h b/executor/kv/kv_executor.h
index 0fda88ae..fef12597 100644
--- a/executor/kv/kv_executor.h
+++ b/executor/kv/kv_executor.h
@@ -36,6 +36,10 @@ class KVExecutor : public TransactionManager {
std::unique_ptr<std::string> ExecuteData(const std::string& request)
override;
+ std::unique_ptr<google::protobuf::Message> ParseData(
+ const std::string& request) override;
+ std::unique_ptr<std::string> ExecuteRequest(
+ const google::protobuf::Message& kv_request) override;
protected:
virtual void Set(const std::string& key, const std::string& value);
std::string Get(const std::string& key);
@@ -54,6 +58,8 @@ class KVExecutor : public TransactionManager {
private:
std::unique_ptr<Storage> storage_;
+
+ std::unique_ptr<TransactionManager> contract_manager_;
};
} // namespace resdb
diff --git a/interface/contract/contract_client.cpp
b/interface/contract/contract_client.cpp
index 77dec83f..2d8b2e98 100644
--- a/interface/contract/contract_client.cpp
+++ b/interface/contract/contract_client.cpp
@@ -43,19 +43,6 @@ absl::StatusOr<Account> ContractClient::CreateAccount() {
return response.account();
}
-absl::Status ContractClient::AddExternalAddress(
- const std::string& external_address) {
- Request request;
- Response response;
- request.set_cmd(Request::ADD_ADDRESS);
- request.set_external_address(external_address);
- int ret = SendRequest(request, &response);
- if (ret != 0 || response.ret() != 0) {
- return absl::InternalError("Add address failed.");
- }
- return absl::OkStatus();
-}
-
absl::StatusOr<Contract> ContractClient::DeployContract(
const std::string& caller_address, const std::string& contract_name,
const std::string& contract_path,
diff --git a/interface/contract/contract_client.h
b/interface/contract/contract_client.h
index 944e71e6..7b0c5aed 100644
--- a/interface/contract/contract_client.h
+++ b/interface/contract/contract_client.h
@@ -32,7 +32,6 @@ class ContractClient : public TransactionConstructor {
ContractClient(const ResDBConfig& config);
absl::StatusOr<Account> CreateAccount();
- absl::Status AddExternalAddress(const std::string& external_address);
absl::StatusOr<Contract> DeployContract(
const std::string& caller_address, const std::string& contract_name,
const std::string& contract_path,
diff --git a/interface/kv/BUILD b/interface/kv/BUILD
index e90fb9ef..aad894e0 100644
--- a/interface/kv/BUILD
+++ b/interface/kv/BUILD
@@ -27,3 +27,17 @@ cc_library(
"//proto/kv:kv_cc_proto",
],
)
+
+cc_library(
+ name = "contract_client",
+ srcs = ["contract_client.cpp"],
+ hdrs = ["contract_client.h"],
+ deps = [
+ "//common:json",
+ "//interface/rdbc:transaction_constructor",
+ "//proto/contract:account_cc_proto",
+ "//proto/contract:contract_cc_proto",
+ "//proto/contract:rpc_cc_proto",
+ "//proto/kv:kv_cc_proto",
+ ],
+)
diff --git a/interface/contract/contract_client.cpp
b/interface/kv/contract_client.cpp
similarity index 73%
copy from interface/contract/contract_client.cpp
copy to interface/kv/contract_client.cpp
index 77dec83f..26259eb9 100644
--- a/interface/contract/contract_client.cpp
+++ b/interface/kv/contract_client.cpp
@@ -17,14 +17,14 @@
* under the License.
*/
-#include "interface/contract/contract_client.h"
+#include "interface/kv/contract_client.h"
#include <glog/logging.h>
#include <fstream>
#include <nlohmann/json.hpp>
-#include "proto/contract/rpc.pb.h"
+#include "proto/kv/kv.pb.h"
namespace resdb {
namespace contract {
@@ -36,26 +36,13 @@ absl::StatusOr<Account> ContractClient::CreateAccount() {
Request request;
Response response;
request.set_cmd(Request::CREATE_ACCOUNT);
- int ret = SendRequest(request, &response);
+ int ret = SendRequestInternal(request, &response);
if (ret != 0 || response.ret() != 0) {
return absl::InternalError("Account not exist.");
}
return response.account();
}
-absl::Status ContractClient::AddExternalAddress(
- const std::string& external_address) {
- Request request;
- Response response;
- request.set_cmd(Request::ADD_ADDRESS);
- request.set_external_address(external_address);
- int ret = SendRequest(request, &response);
- if (ret != 0 || response.ret() != 0) {
- return absl::InternalError("Add address failed.");
- }
- return absl::OkStatus();
-}
-
absl::StatusOr<Contract> ContractClient::DeployContract(
const std::string& caller_address, const std::string& contract_name,
const std::string& contract_path,
@@ -101,7 +88,7 @@ absl::StatusOr<Contract> ContractClient::DeployContract(
request.set_cmd(Request::DEPLOY);
LOG(ERROR) << "send request:" << request.DebugString();
- int ret = SendRequest(request, &response);
+ int ret = SendRequestInternal(request, &response);
if (ret != 0 || response.ret() != 0) {
return absl::InternalError("Deploy contract fail.");
}
@@ -122,13 +109,61 @@ absl::StatusOr<std::string>
ContractClient::ExecuteContract(
}
request.set_cmd(Request::EXECUTE);
+
LOG(ERROR) << "send request:" << request.DebugString();
- int ret = SendRequest(request, &response);
+ int ret = SendRequestInternal(request, &response);
+ if (ret != 0 || response.ret() != 0) {
+ return absl::InternalError("Deploy contract fail.");
+ }
+ return response.res();
+}
+
+
+absl::StatusOr<std::string> ContractClient::GetBalance(const std::string&
address) {
+ Request request;
+ Response response;
+ request.set_account(address);
+
+ request.set_cmd(Request::GETBALANCE);
+
+ int ret = SendRequestInternal(request, &response);
if (ret != 0 || response.ret() != 0) {
return absl::InternalError("Deploy contract fail.");
}
return response.res();
}
+absl::StatusOr<std::string> ContractClient::SetBalance(const std::string&
address, const std::string& balance) {
+ Request request;
+ Response response;
+ request.set_account(address);
+ request.set_balance(balance);
+
+ request.set_cmd(Request::SETBALANCE);
+
+ int ret = SendRequestInternal(request, &response);
+ if (ret != 0 || response.ret() != 0) {
+ return absl::InternalError("Deploy contract fail.");
+ }
+ return response.res();
+}
+
+int ContractClient::SendRequestInternal(const Request& request, Response *
response) {
+ KVRequest kv_request;
+ request.SerializeToString(kv_request.mutable_smart_contract_request());
+ KVResponse kv_response;
+
+ int ret = SendRequest(kv_request, &kv_response);
+ if (ret != 0) {
+ return ret;
+ }
+ printf("get response from sm\n");
+
+ response->ParseFromString(kv_response.smart_contract_response());
+ return 0;
+}
+
+
+
} // namespace contract
} // namespace resdb
diff --git a/interface/contract/contract_client.h
b/interface/kv/contract_client.h
similarity index 83%
copy from interface/contract/contract_client.h
copy to interface/kv/contract_client.h
index 944e71e6..7df166ef 100644
--- a/interface/contract/contract_client.h
+++ b/interface/kv/contract_client.h
@@ -22,6 +22,7 @@
#include "interface/rdbc/transaction_constructor.h"
#include "proto/contract/account.pb.h"
#include "proto/contract/contract.pb.h"
+#include "proto/contract/rpc.pb.h"
namespace resdb {
namespace contract {
@@ -32,7 +33,6 @@ class ContractClient : public TransactionConstructor {
ContractClient(const ResDBConfig& config);
absl::StatusOr<Account> CreateAccount();
- absl::Status AddExternalAddress(const std::string& external_address);
absl::StatusOr<Contract> DeployContract(
const std::string& caller_address, const std::string& contract_name,
const std::string& contract_path,
@@ -42,6 +42,12 @@ class ContractClient : public TransactionConstructor {
const std::string& caller_address, const std::string& contract_address,
const std::string& func_name,
const std::vector<std::string>& func_params);
+
+ absl::StatusOr<std::string> GetBalance(const std::string& address);
+ absl::StatusOr<std::string> SetBalance(const std::string& address, const
std::string& balance);
+
+ private:
+ int SendRequestInternal(const resdb::contract::Request& request,
resdb::contract::Response* response);
};
} // namespace contract
diff --git a/platform/config/resdb_config.cpp b/platform/config/resdb_config.cpp
index 4c3ff954..23129a25 100644
--- a/platform/config/resdb_config.cpp
+++ b/platform/config/resdb_config.cpp
@@ -76,6 +76,9 @@ ResDBConfig::ResDBConfig(const ResConfigData& config_data,
if (config_data_.tcp_batch_num() == 0) {
config_data_.set_tcp_batch_num(100);
}
+ if (config_data_.max_process_txn() == 0) {
+ config_data_.set_max_process_txn(64);
+ }
}
void ResDBConfig::SetConfigData(const ResConfigData& config_data) {
@@ -177,7 +180,7 @@ void ResDBConfig::SetSignatureVerifierEnabled(bool
enable_sv) {
}
// Performance setting
-bool ResDBConfig::IsPerformanceRunning() {
+bool ResDBConfig::IsPerformanceRunning() const {
return is_performance_running_ || GetConfigData().is_performance_running();
}
diff --git a/platform/config/resdb_config.h b/platform/config/resdb_config.h
index fb56a9dd..9867c6d5 100644
--- a/platform/config/resdb_config.h
+++ b/platform/config/resdb_config.h
@@ -94,7 +94,7 @@ class ResDBConfig {
void SetSignatureVerifierEnabled(bool enable_sv);
// Performance setting
- bool IsPerformanceRunning();
+ bool IsPerformanceRunning() const;
void RunningPerformance(bool);
bool IsTestMode() const;
@@ -135,15 +135,18 @@ class ResDBConfig {
bool signature_verifier_enabled_ = true;
bool is_performance_running_ = false;
bool is_test_mode_ = false;
- uint32_t max_process_txn_ = 2048;
uint32_t client_batch_wait_time_ms_ = 100; // milliseconds, 0.1s
- uint32_t client_batch_num_ = 100;
uint64_t viewchange_commit_timeout_ms_ =
60000; // default 60s to change viewchange
- uint32_t worker_num_ = 64;
- uint32_t input_worker_num_ = 1;
- uint32_t output_worker_num_ = 1;
+
+ // This is the default settings.
+ // change these parameters in the configuration.
+ uint32_t max_process_txn_ = 64;
+ uint32_t worker_num_ = 16;
+ uint32_t input_worker_num_ = 5;
+ uint32_t output_worker_num_ = 5;
+ uint32_t client_batch_num_ = 100;
};
} // namespace resdb
diff --git a/platform/consensus/execution/transaction_executor.cpp
b/platform/consensus/execution/transaction_executor.cpp
index fd24da3a..a62e55f5 100644
--- a/platform/consensus/execution/transaction_executor.cpp
+++ b/platform/consensus/execution/transaction_executor.cpp
@@ -20,6 +20,7 @@
#include "platform/consensus/execution/transaction_executor.h"
#include <glog/logging.h>
+#include "common/utils/utils.h"
namespace resdb {
@@ -35,9 +36,19 @@ TransactionExecutor::TransactionExecutor(
execute_queue_("execute"),
stop_(false),
duplicate_manager_(nullptr) {
+
+ memset(blucket_, 0, sizeof(blucket_));
global_stats_ = Stats::GetGlobalStats();
ordering_thread_ = std::thread(&TransactionExecutor::OrderMessage, this);
- execute_thread_ = std::thread(&TransactionExecutor::ExecuteMessage, this);
+ for (int i = 0; i < execute_thread_num_; ++i) {
+ execute_thread_.push_back(
+ std::thread(&TransactionExecutor::ExecuteMessage, this));
+ }
+
+ for (int i = 0; i < 1; ++i) {
+ prepare_thread_.push_back(
+ std::thread(&TransactionExecutor::PrepareMessage, this));
+ }
if (transaction_manager_ && transaction_manager_->IsOutOfOrder()) {
execute_OOO_thread_ =
@@ -48,13 +59,55 @@ TransactionExecutor::TransactionExecutor(
TransactionExecutor::~TransactionExecutor() { Stop(); }
+void TransactionExecutor::RegisterExecute(int64_t seq) {
+ if (execute_thread_num_ == 1) return;
+ int idx = seq % blucket_num_;
+ std::unique_lock<std::mutex> lk(mutex_);
+ // LOG(ERROR)<<"register seq:"<<seq<<" bluck:"<<blucket_[idx];
+ assert(!blucket_[idx] || !(blucket_[idx] ^ 3));
+ blucket_[idx] = 1;
+ // LOG(ERROR)<<"register seq:"<<seq;
+}
+
+void TransactionExecutor::WaitForExecute(int64_t seq) {
+ if (execute_thread_num_ == 1) return;
+ int pre_idx = (seq - 1 + blucket_num_) % blucket_num_;
+
+ while (!IsStop()) {
+ std::unique_lock<std::mutex> lk(mutex_);
+ cv_.wait_for(lk, std::chrono::milliseconds(10000), [&] {
+ return ((blucket_[pre_idx] & 2) || !blucket_[pre_idx]);
+ });
+ if ((blucket_[pre_idx] & 2) || !blucket_[pre_idx]) {
+ break;
+ }
+ }
+ // LOG(ERROR)<<"wait for :"<<seq<<" done";
+}
+
+void TransactionExecutor::FinishExecute(int64_t seq) {
+ if (execute_thread_num_ == 1) return;
+ int idx = seq % blucket_num_;
+ std::unique_lock<std::mutex> lk(mutex_);
+ // LOG(ERROR)<<"finish :"<<seq<<" done";
+ blucket_[idx] = 3;
+ cv_.notify_all();
+}
+
void TransactionExecutor::Stop() {
stop_ = true;
if (ordering_thread_.joinable()) {
ordering_thread_.join();
}
- if (execute_thread_.joinable()) {
- execute_thread_.join();
+ for (auto& th : execute_thread_) {
+ if (th.joinable()) {
+ th.join();
+ }
+ }
+ for (auto& th : prepare_thread_) {
+ if (th.joinable()) {
+ th.join();
+ }
}
if (execute_OOO_thread_.joinable()) {
execute_OOO_thread_.join();
@@ -144,6 +197,12 @@ void TransactionExecutor::OrderMessage() {
return;
}
+void TransactionExecutor::AddExecuteMessage(std::unique_ptr<Request> message) {
+ global_stats_->IncCommit();
+ message->set_commit_time(GetCurrentTime());
+ execute_queue_.Push(std::move(message));
+}
+
void TransactionExecutor::ExecuteMessage() {
while (!IsStop()) {
auto message = execute_queue_.Pop();
@@ -184,10 +243,8 @@ void
TransactionExecutor::OnlyExecute(std::unique_ptr<Request> request) {
// LOG(INFO) << " get request batch size:"
// << batch_request.user_requests_size()<<" proxy
// id:"<<request->proxy_id();
- // std::unique_ptr<BatchUserResponse> batch_response =
- // std::make_unique<BatchUserResponse>();
std::unique_ptr<BatchUserResponse> response;
- global_stats_->GetTransactionDetails(batch_request);
+ global_stats_->GetTransactionDetails(batch_request);
if (transaction_manager_) {
response = transaction_manager_->ExecuteBatch(batch_request);
}
@@ -198,45 +255,93 @@ void
TransactionExecutor::OnlyExecute(std::unique_ptr<Request> request) {
void TransactionExecutor::Execute(std::unique_ptr<Request> request,
bool need_execute) {
+ RegisterExecute(request->seq());
+ std::unique_ptr<BatchUserRequest> batch_request = nullptr;
+ std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>
data;
+ std::vector<std::unique_ptr<google::protobuf::Message>> * data_p = nullptr;
+ BatchUserRequest* batch_request_p = nullptr;
+
// Execute the request, then send the response back to the user.
- BatchUserRequest batch_request;
- if (!batch_request.ParseFromString(request->data())) {
- LOG(ERROR) << "parse data fail";
- }
- batch_request.set_seq(request->seq());
- batch_request.set_hash(request->hash());
- batch_request.set_proxy_id(request->proxy_id());
- if (request->has_committed_certs()) {
- *batch_request.mutable_committed_certs() = request->committed_certs();
+ if (batch_request_p == nullptr) {
+ batch_request = std::make_unique<BatchUserRequest>();
+ if (!batch_request->ParseFromString(request->data())) {
+ LOG(ERROR) << "parse data fail";
+ }
+ batch_request->set_hash(request->hash());
+ if (request->has_committed_certs()) {
+ *batch_request->mutable_committed_certs() = request->committed_certs();
+ }
+ batch_request->set_seq(request->seq());
+ batch_request->set_proxy_id(request->proxy_id());
+ batch_request_p = batch_request.get();
+ // LOG(ERROR)<<"get data from req:";
+ } else {
+ assert(batch_request_p);
+ batch_request_p->set_seq(request->seq());
+ batch_request_p->set_proxy_id(request->proxy_id());
+ // LOG(ERROR)<<" get from cache:"<<uid;
}
+ assert(batch_request_p);
// LOG(INFO) << " get request batch size:"
- // << batch_request.user_requests_size()<<" proxy
- // id:"<<request->proxy_id()<<" need execute:"<<need_execute;
- // std::unique_ptr<BatchUserResponse> batch_response =
- // std::make_unique<BatchUserResponse>();
+ // << batch_request.user_requests_size()<<" proxy id:"
+ // <<request->proxy_id()<<" need execute:"<<need_execute;
std::unique_ptr<BatchUserResponse> response;
- global_stats_->GetTransactionDetails(batch_request);
+ global_stats_->GetTransactionDetails(*batch_request_p);
if (transaction_manager_ && need_execute) {
- response = transaction_manager_->ExecuteBatch(batch_request);
+ if (execute_thread_num_ == 1) {
+ response = transaction_manager_->ExecuteBatch(*batch_request_p);
+ } else {
+ std::vector<std::unique_ptr<std::string>> response_v;
+
+ if(data_p == nullptr) {
+ int64_t start_time = GetCurrentTime();
+ data = std::move(transaction_manager_->Prepare(*batch_request_p));
+ int64_t end_time = GetCurrentTime();
+ if (end_time - start_time > 10) {
+ // LOG(ERROR)<<"exec data done:"<<uid<<" wait
+ // time:"<<(end_time-start_time);
+ }
+ data_p = data.get();
+ }
+
+ WaitForExecute(request->seq());
+ if(data_p->empty() || (*data_p)[0] == nullptr){
+ response =
transaction_manager_->ExecuteBatch(*batch_request_p);
+ }
+ else {
+ response_v =
transaction_manager_->ExecuteBatchData(*data_p);
+ }
+ FinishExecute(request->seq());
+
+ if(response == nullptr){
+ response = std::make_unique<BatchUserResponse>();
+ for (auto& s : response_v) {
+ response->add_response()->swap(*s);
+ }
+ }
+ }
}
+ // LOG(ERROR)<<" CF = :"<<(cf==1)<<" uid:"<<uid;
- if (duplicate_manager_) {
- duplicate_manager_->AddExecuted(batch_request.hash(), batch_request.seq());
+ if (duplicate_manager_ && batch_request_p) {
+ duplicate_manager_->AddExecuted(batch_request_p->hash(),
batch_request_p->seq());
}
- global_stats_->IncTotalRequest(batch_request.user_requests_size());
if (response == nullptr) {
response = std::make_unique<BatchUserResponse>();
}
+ global_stats_->IncTotalRequest(batch_request_p->user_requests_size());
+ response->set_proxy_id(batch_request_p->proxy_id());
+ response->set_createtime(batch_request_p->createtime() +
request->queuing_time());
+ response->set_local_id(batch_request_p->local_id());
- response->set_proxy_id(batch_request.proxy_id());
- response->set_createtime(batch_request.createtime());
- response->set_local_id(batch_request.local_id());
- response->set_hash(batch_request.hash());
+ response->set_seq(request->seq());
- post_exec_func_(std::move(request), std::move(response));
+ if (post_exec_func_) {
+ post_exec_func_(std::move(request), std::move(response));
+ }
global_stats_->IncExecuteDone();
}
@@ -245,4 +350,150 @@ void
TransactionExecutor::SetDuplicateManager(DuplicateManager* manager) {
duplicate_manager_ = manager;
}
+
+bool TransactionExecutor::SetFlag(uint64_t uid, int f) {
+ std::unique_lock<std::mutex> lk(f_mutex_[uid % mod]);
+ auto it = flag_[uid % mod].find(uid);
+ if (it == flag_[uid % mod].end()) {
+ flag_[uid % mod][uid] |= f;
+ // LOG(ERROR)<<"NO FUTURE uid:"<<uid;
+ return true;
+ }
+ assert(it != flag_[uid % mod].end());
+ if (f == Start_Prepare) {
+ if (flag_[uid % mod][uid] & Start_Execute) {
+ return false;
+ }
+ } else if(f == Start_Execute){
+ if (flag_[uid % mod][uid] & End_Prepare) {
+ //if (flag_[uid % mod][uid] & Start_Prepare) {
+ return false;
+ }
+ }
+ flag_[uid % mod][uid] |= f;
+ return true;
+}
+
+void TransactionExecutor::ClearPromise(uint64_t uid) {
+ std::unique_lock<std::mutex> lk(f_mutex_[uid % mod]);
+ auto it = pre_[uid % mod].find(uid);
+ if (it == pre_[uid % mod].end()) {
+ return;
+ }
+ // LOG(ERROR)<<"CLEAR UID:"<<uid;
+ assert(it != pre_[uid % mod].end());
+ assert(flag_[uid % mod].find(uid) != flag_[uid % mod].end());
+ //assert(data_[uid%mod].find(uid) != data_[uid%mod].end());
+ //assert(req_[uid%mod].find(uid) != req_[uid%mod].end());
+ //data_[uid%mod].erase(data_[uid%mod].find(uid));
+ //req_[uid%mod].erase(req_[uid%mod].find(uid));
+ pre_[uid % mod].erase(it);
+ flag_[uid % mod].erase(flag_[uid % mod].find(uid));
+}
+
+std::promise<int>* TransactionExecutor::GetPromise(uint64_t uid) {
+ std::unique_lock<std::mutex> lk(f_mutex_[uid % mod]);
+ auto it = pre_[uid % mod].find(uid);
+ if (it == pre_[uid % mod].end()) {
+ return nullptr;
+ }
+ return it->second.get();
+}
+
+std::unique_ptr<std::future<int>> TransactionExecutor::GetFuture(uint64_t uid)
{
+ std::unique_lock<std::mutex> lk(f_mutex_[uid % mod]);
+ auto it = pre_[uid % mod].find(uid);
+ if (it == pre_[uid % mod].end()) {
+ return nullptr;
+ }
+ //return std::move(it->second);
+ // LOG(ERROR)<<"add future:"<<uid;
+ return std::make_unique<std::future<int>>(it->second->get_future());
+}
+
+bool TransactionExecutor::AddFuture(uint64_t uid) {
+ std::unique_lock<std::mutex> lk(f_mutex_[uid % mod]);
+ auto it = pre_[uid % mod].find(uid);
+ if (it == pre_[uid % mod].end()) {
+ // LOG(ERROR)<<"add future:"<<uid;
+ std::unique_ptr<std::promise<int>> p =
+ std::make_unique<std::promise<int>>();
+ //auto f = std::make_unique<std::future<int>>(p->get_future());
+ pre_[uid % mod][uid] = std::move(p);
+ //pre_f_[uid % mod][uid] = std::move(f);
+ flag_[uid % mod][uid] = 0;
+ return true;
+ }
+ return false;
+}
+
+void TransactionExecutor::Prepare(std::unique_ptr<Request> request) {
+ if (AddFuture(request->uid())) {
+ prepare_queue_.Push(std::move(request));
+ }
+}
+
+void TransactionExecutor::PrepareMessage() {
+ while (!IsStop()) {
+ std::unique_ptr<Request> request = prepare_queue_.Pop();
+ if (request == nullptr) {
+ continue;
+ }
+
+ uint64_t uid = request->uid();
+ int current_f = SetFlag(uid, Start_Prepare);
+ if (current_f == 0) {
+ // commit has done
+ // LOG(ERROR)<<" want prepare, commit started:"<<uid;
+// ClearPromise(uid);
+ continue;
+ }
+
+ std::promise<int>* p = GetPromise(uid) ;
+ assert(p);
+ //LOG(ERROR)<<" prepare started:"<<uid;
+
+ // LOG(ERROR)<<" prepare uid:"<<uid;
+
+ // Execute the request, then send the response back to the user.
+ std::unique_ptr<BatchUserRequest> batch_request =
+ std::make_unique<BatchUserRequest>();
+ if (!batch_request->ParseFromString(request->data())) {
+ LOG(ERROR) << "parse data fail";
+ }
+ // batch_request = std::make_unique<BatchUserRequest>();
+ batch_request->set_seq(request->seq());
+ batch_request->set_hash(request->hash());
+ batch_request->set_proxy_id(request->proxy_id());
+ if (request->has_committed_certs()) {
+ *batch_request->mutable_committed_certs() = request->committed_certs();
+ }
+
+ // LOG(ERROR)<<"prepare seq:"<<batch_request->seq()<<" proxy
+ // id:"<<request->proxy_id()<<" local id:"<<batch_request->local_id();
+
+ std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>
+ request_v = transaction_manager_->Prepare(*batch_request);
+ {
+ std::unique_lock<std::mutex> lk(fd_mutex_[uid % mod]);
+ // assert(request_v);
+ // assert(data_[uid%mod].find(uid) == data_[uid%mod].end());
+ data_[uid%mod][uid] = std::move(request_v);
+ req_[uid % mod][uid] = std::move(batch_request);
+ }
+ //LOG(ERROR)<<"set promise:"<<uid;
+ p->set_value(1);
+ {
+ int set_ret = SetFlag(uid, End_Prepare);
+ if (set_ret == 0) {
+ // LOG(ERROR)<<"commit interrupt:"<<uid;
+ //ClearPromise(uid);
+ } else {
+ //LOG(ERROR)<<"prepare done:"<<uid;
+ }
+ }
+ }
+}
+
+
} // namespace resdb
diff --git a/platform/consensus/execution/transaction_executor.h
b/platform/consensus/execution/transaction_executor.h
index 2b111164..6fb8ef39 100644
--- a/platform/consensus/execution/transaction_executor.h
+++ b/platform/consensus/execution/transaction_executor.h
@@ -62,8 +62,16 @@ class TransactionExecutor {
void SetDuplicateManager(DuplicateManager* manager);
+ void AddExecuteMessage(std::unique_ptr<Request> message);
+
Storage* GetStorage();
+ void RegisterExecute(int64_t seq);
+ void WaitForExecute(int64_t seq);
+ void FinishExecute(int64_t seq);
+
+ void Prepare(std::unique_ptr<Request> request);
+
private:
void Execute(std::unique_ptr<Request> request, bool need_execute = true);
void OnlyExecute(std::unique_ptr<Request> request);
@@ -80,6 +88,14 @@ class TransactionExecutor {
void UpdateMaxExecutedSeq(uint64_t seq);
+ bool SetFlag(uint64_t uid, int f);
+ void ClearPromise(uint64_t uid);
+ void PrepareMessage();
+
+ bool AddFuture(uint64_t uid);
+ std::unique_ptr<std::future<int>> GetFuture(uint64_t uid);
+ std::promise<int>* GetPromise(uint64_t uid);
+
protected:
ResDBConfig config_;
@@ -91,11 +107,42 @@ class TransactionExecutor {
SystemInfo* system_info_ = nullptr;
std::unique_ptr<TransactionManager> transaction_manager_ = nullptr;
std::map<uint64_t, std::unique_ptr<Request>> candidates_;
- std::thread ordering_thread_, execute_thread_, execute_OOO_thread_;
+ std::thread ordering_thread_, execute_OOO_thread_;
+ std::vector<std::thread> execute_thread_;
LockFreeQueue<Request> commit_queue_, execute_queue_, execute_OOO_queue_;
std::atomic<bool> stop_;
Stats* global_stats_ = nullptr;
DuplicateManager* duplicate_manager_;
+ int execute_thread_num_ = 10;
+ static const int blucket_num_ = 1024;
+ int blucket_[blucket_num_];
+ std::condition_variable cv_;
+ std::mutex mutex_;
+
+ enum PrepareType {
+ Start_Prepare = 1,
+ Start_Execute = 2,
+ End_Prepare = 4,
+ };
+
+
+ std::vector<std::thread> prepare_thread_;
+ static const int mod = 2048;
+ std::mutex f_mutex_[mod], fd_mutex_[mod];
+ LockFreeQueue<Request> prepare_queue_;
+ LockFreeQueue<int64_t> gc_queue_;
+ typedef std::unique_ptr<std::promise<int>> PromiseType;
+ std::map<uint64_t, PromiseType> pre_[mod];
+
+ std::map<uint64_t, std::unique_ptr<std::future<int>>> pre_f_[mod];
+ std::map<uint64_t, int> flag_[mod];
+
+ std::map<uint64_t, std::unique_ptr<BatchUserRequest>> req_[mod];
+ std::unordered_map<
+ uint64_t,
+ std::unique_ptr<std::vector<std::unique_ptr<google::protobuf::Message>>>>
+ data_[mod];
+
};
} // namespace resdb
diff --git a/platform/networkstrate/replica_communicator.cpp
b/platform/networkstrate/replica_communicator.cpp
index de096125..f1521acb 100644
--- a/platform/networkstrate/replica_communicator.cpp
+++ b/platform/networkstrate/replica_communicator.cpp
@@ -34,7 +34,8 @@ ReplicaCommunicator::ReplicaCommunicator(
verifier_(verifier),
is_running_(false),
batch_queue_("bc_batch", tcp_batch),
- is_use_long_conn_(is_use_long_conn) {
+ is_use_long_conn_(is_use_long_conn),
+ tcp_batch_(tcp_batch) {
global_stats_ = Stats::GetGlobalStats();
if (is_use_long_conn_) {
worker_ = std::make_unique<boost::asio::io_service::work>(io_service_);
@@ -42,18 +43,10 @@ ReplicaCommunicator::ReplicaCommunicator(
worker_threads_.push_back(std::thread([&]() { io_service_.run(); }));
}
}
-
- /*
- for (const ReplicaInfo& info : replicas) {
- std::string ip = info.ip();
- int port = info.port();
- auto client = std::make_unique<AsyncReplicaClient>(
- &io_service_, ip, port + (is_use_long_conn_ ? 10000 : 0), true);
- client_pools_[std::make_pair(ip, port)] = std::move(client);
- }
- */
+ LOG(ERROR)<<" tcp batch:"<<tcp_batch;
StartBroadcastInBackGround();
+
}
ReplicaCommunicator::~ReplicaCommunicator() {
@@ -131,6 +124,74 @@ void ReplicaCommunicator::StartBroadcastInBackGround() {
});
}
+void ReplicaCommunicator::StartSingleInBackGround(const std::string& ip, int
port) {
+ single_bq_[std::make_pair(ip,port)] =
std::make_unique<BatchQueue<std::unique_ptr<QueueItem>>>("s_batch", tcp_batch_);
+
+ ReplicaInfo replica_info;
+ for (const auto& replica : replicas_) {
+ if (replica.ip() == ip && replica.port() == port) {
+ replica_info = replica;
+ break;
+ }
+ }
+
+ if (replica_info.ip().empty()) {
+ for (const auto& replica : GetClientReplicas()) {
+ if (replica.ip() == ip && replica.port() == port) {
+ replica_info = replica;
+ break;
+ }
+ }
+ }
+
+
+
single_thread_.push_back(std::thread([&](BatchQueue<std::unique_ptr<QueueItem>>
*bq, ReplicaInfo replica_info) {
+ while (IsRunning()) {
+ std::vector<std::unique_ptr<QueueItem>> batch_req =
+ bq->Pop(50000);
+ if (batch_req.empty()) {
+ continue;
+ }
+ BroadcastData broadcast_data;
+ for (auto& queue_item : batch_req) {
+ broadcast_data.add_data()->swap(queue_item->data);
+ }
+
+ global_stats_->SendBroadCastMsg(broadcast_data.data_size());
+ //LOG(ERROR)<<" send to ip:"<<replica_info.ip()<<"
port:"<<replica_info.port()<<" bq size:"<<batch_req.size();
+ int ret = SendMessageFromPool(broadcast_data, {replica_info});
+ if (ret < 0) {
+ LOG(ERROR) << "broadcast request fail:";
+ }
+ //LOG(ERROR)<<" send to ip:"<<replica_info.ip()<<"
port:"<<replica_info.port()<<" bq size:"<<batch_req.size()<<" done";
+ }
+ }, single_bq_[std::make_pair(ip,port)].get(), replica_info));
+}
+
+
+int ReplicaCommunicator::SendSingleMessage(const google::protobuf::Message&
message,
+const ReplicaInfo& replica_info) {
+
+ std::string ip = replica_info.ip();
+ int port = replica_info.port();
+
+ //LOG(ERROR)<<" send msg ip:"<<ip<<" port:"<<port;
+ global_stats_->BroadCastMsg();
+ if (is_use_long_conn_) {
+ auto item = std::make_unique<QueueItem>();
+ item->data = NetChannel::GetRawMessageString(message, verifier_);
+ std::lock_guard<std::mutex> lk(smutex_);
+ if(single_bq_.find(std::make_pair(ip, port)) == single_bq_.end()){
+ StartSingleInBackGround(ip, port);
+ }
+ assert(single_bq_[std::make_pair(ip, port)] != nullptr);
+ single_bq_[std::make_pair(ip, port)]->Push(std::move(item));
+ return 0;
+ } else {
+ return SendMessageInternal(message, replicas_);
+ }
+}
+
int ReplicaCommunicator::SendMessage(const google::protobuf::Message& message)
{
global_stats_->BroadCastMsg();
if (is_use_long_conn_) {
@@ -139,13 +200,14 @@ int ReplicaCommunicator::SendMessage(const
google::protobuf::Message& message) {
batch_queue_.Push(std::move(item));
return 0;
} else {
- LOG(ERROR) << "send internal";
return SendMessageInternal(message, replicas_);
}
}
int ReplicaCommunicator::SendMessage(const google::protobuf::Message& message,
const ReplicaInfo& replica_info) {
+ return SendSingleMessage(message, replica_info);
+
if (is_use_long_conn_) {
std::string data = NetChannel::GetRawMessageString(message, verifier_);
BroadcastData broadcast_data;
@@ -188,11 +250,13 @@ int ReplicaCommunicator::SendMessageFromPool(
if (client == nullptr) {
continue;
}
+ //LOG(ERROR) << "send to:" << replica.ip();
if (client->SendMessage(data) == 0) {
ret++;
} else {
LOG(ERROR) << "send to:" << replica.ip() << " fail";
}
+ //LOG(ERROR) << "send to:" << replica.ip()<<" done";
}
return ret;
}
@@ -222,6 +286,7 @@ AsyncReplicaClient* ReplicaCommunicator::GetClientFromPool(
auto client = std::make_unique<AsyncReplicaClient>(
&io_service_, ip, port + (is_use_long_conn_ ? 10000 : 0), true);
client_pools_[std::make_pair(ip, port)] = std::move(client);
+ //StartSingleInBackGround(ip, port);
}
return client_pools_[std::make_pair(ip, port)].get();
}
@@ -257,7 +322,7 @@ void ReplicaCommunicator::SendMessage(const
google::protobuf::Message& message,
}
if (target_replica.ip().empty()) {
- LOG(ERROR) << "no replica info node:" << node_id;
+ LOG(ERROR) << "no replica info";
return;
}
diff --git a/platform/networkstrate/replica_communicator.h
b/platform/networkstrate/replica_communicator.h
index 24ef8101..239e4d21 100644
--- a/platform/networkstrate/replica_communicator.h
+++ b/platform/networkstrate/replica_communicator.h
@@ -37,7 +37,7 @@ class ReplicaCommunicator {
ReplicaCommunicator(const std::vector<ReplicaInfo>& replicas,
SignatureVerifier* verifier = nullptr,
bool is_use_long_conn = false, int epoll_num = 1,
- int tcp_batch = 100);
+ int tcp_batch = 1);
virtual ~ReplicaCommunicator();
// HeartBeat message is used to broadcast public keys.
@@ -73,6 +73,11 @@ class ReplicaCommunicator {
bool IsRunning() const;
bool IsInPool(const ReplicaInfo& replica_info);
+ void StartSingleInBackGround(const std::string& ip, int port);
+
+ int SendSingleMessage(const google::protobuf::Message& message,
+ const ReplicaInfo& replica_info);
+
private:
std::vector<ReplicaInfo> replicas_;
SignatureVerifier* verifier_;
@@ -93,6 +98,14 @@ class ReplicaCommunicator {
std::vector<std::thread> worker_threads_;
std::vector<ReplicaInfo> clients_;
std::mutex mutex_;
+
+
+
+ std::map<std::pair<std::string, int>,
+ std::unique_ptr<BatchQueue<std::unique_ptr<QueueItem>>>> single_bq_;
+ std::vector<std::thread> single_thread_;
+ int tcp_batch_;
+ std::mutex smutex_;
};
} // namespace resdb
diff --git a/platform/proto/resdb.proto b/platform/proto/resdb.proto
index ac60498a..47edac38 100644
--- a/platform/proto/resdb.proto
+++ b/platform/proto/resdb.proto
@@ -88,6 +88,7 @@ message Request {
int64 uid = 23;
int64 create_time = 24;
int64 commit_time = 25;
+ bytes data_hash = 26;
}
// The response message containing response
diff --git a/proto/contract/rpc.proto b/proto/contract/rpc.proto
index 8df1dd40..91295a5f 100644
--- a/proto/contract/rpc.proto
+++ b/proto/contract/rpc.proto
@@ -31,22 +31,29 @@ message Request {
CREATE_ACCOUNT = 1; // deploy contract
DEPLOY = 2; // deploy contract
EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
+ GETBALANCE = 4; // get balance directly (key-value)
+ SETBALANCE = 5; // set balance directly (key-value)
};
CMD cmd = 1;
+
+ // for smart-contract
string caller_address = 2;
optional DeployInfo deploy_info = 3;
optional string contract_address = 4;
optional Params func_params = 5;
- optional string external_address = 6;
+
+ // for key-value
+ optional string account = 6;
+ // hex string
+ optional string balance = 7;
}
message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+ int32 ret = 1;
+ optional Account account = 2;
+ optional Contract contract = 3;
+ optional string res = 4;
}
diff --git a/proto/kv/kv.proto b/proto/kv/kv.proto
index a76c2f48..750058e7 100644
--- a/proto/kv/kv.proto
+++ b/proto/kv/kv.proto
@@ -47,6 +47,7 @@ message KVRequest {
int32 max_version = 8;
// For top history
int32 top_number = 9;
+ bytes smart_contract_request = 10;
}
message ValueInfo {
@@ -68,5 +69,6 @@ message KVResponse {
bytes value = 2;
ValueInfo value_info = 3;
Items items = 4;
+ bytes smart_contract_response = 10;
}
diff --git a/service/contract/BUILD b/service/contract/BUILD
index 11545b16..d97c304b 100644
--- a/service/contract/BUILD
+++ b/service/contract/BUILD
@@ -26,5 +26,6 @@ cc_binary(
"//platform/config:resdb_config_utils",
"//platform/consensus/ordering/pbft:consensus_manager_pbft",
"//service/utils:server_factory",
+ "//chain/storage:memory_db",
],
)
diff --git a/service/contract/contract_service.cpp
b/service/contract/contract_service.cpp
index 73826af9..5bcc8942 100644
--- a/service/contract/contract_service.cpp
+++ b/service/contract/contract_service.cpp
@@ -19,6 +19,7 @@
#include <glog/logging.h>
+#include "chain/storage/memory_db.h"
#include "executor/contract/executor/contract_executor.h"
#include "platform/config/resdb_config_utils.h"
#include "platform/consensus/ordering/pbft/consensus_manager_pbft.h"
@@ -62,9 +63,10 @@ int main(int argc, char** argv) {
GenerateResDBConfig(config_file, private_key_file, cert_file);
ResConfigData config_data = config->GetConfigData();
+ std::unique_ptr<resdb::Storage> memory_db = resdb::storage::NewMemoryDB();
auto server = CustomGenerateResDBServer<ConsensusManagerPBFT>(
config_file, private_key_file, cert_file,
- std::make_unique<ContractTransactionManager>(), logging_dir);
+ std::make_unique<ContractTransactionManager>(memory_db.get()),
logging_dir);
server->Run();
}
diff --git a/service/tools/contract/api_tools/contract_tools.cpp
b/service/tools/contract/api_tools/contract_tools.cpp
index 0271b312..72e7a73e 100644
--- a/service/tools/contract/api_tools/contract_tools.cpp
+++ b/service/tools/contract/api_tools/contract_tools.cpp
@@ -19,9 +19,11 @@
#include <glog/logging.h>
+#include <getopt.h>
+#include <nlohmann/json.hpp>
#include <boost/algorithm/string.hpp>
#include <vector>
-#include <unistd.h> // For getopt
+#include <fstream>
#include "interface/contract/contract_client.h"
#include "platform/config/resdb_config_utils.h"
@@ -30,21 +32,21 @@ using resdb::GenerateResDBConfig;
using resdb::ResDBConfig;
using resdb::contract::ContractClient;
+
+
void ShowUsage() {
printf(
- "<cmd> -c <config> -m <caller address> -n <contract name> -p <contract "
- "path> -a <params> -e <external address>\n");
+ "<cmd> -c <config> -m <caller address> -n <contract name> -p <contact "
+ "path> -a <params> \n");
exit(0);
}
-void AddAddress(ContractClient* client, const std::string& external_address) {
- absl::Status status = client->AddExternalAddress(external_address);
- if (!status.ok()) {
- printf("Add address failed\n");
- } else {
- printf("Address added successfully\n");
- }
-}
+static struct option long_options[] = {
+ { "cmd", required_argument, NULL, 'm'},
+ { "config_file", required_argument, NULL, 'f'},
+ { 0, 0, 0, 0 }
+};
+
void CreateAccount(ContractClient* client) {
auto account = client->CreateAccount();
@@ -81,70 +83,88 @@ void ExecuteContract(ContractClient* client, const
std::string& caller_address,
LOG(ERROR) << "execute result:\n" << *output;
}
+nlohmann::json ReadJSConfig(const std::string& config_path) {
+
+ std::ifstream contract_fstream(config_path);
+ if (!contract_fstream) {
+ throw std::runtime_error( "Unable to open config file "+config_path);
+ }
+
+ return nlohmann::json::parse(contract_fstream);
+}
+
+std::string GetValue(const nlohmann::json& js, std::string key){
+if(!js.contains(key)){
+ printf("need %s\n", key.c_str());
+ exit(0);
+ }
+ return js[key];
+}
+
+
int main(int argc, char** argv) {
- if (argc < 3) {
- ShowUsage();
+ if (argc < 2) {
+ printf("<cmd> -c [config]\n");
return 0;
}
- std::string cmd = argv[1];
+
+ std::string config_file;
+
+ std::string cmd;
std::string caller_address, contract_name, contract_path, params,
- contract_address, func_name, external_address; // Added external_address
+ contract_address, func_name;
int c;
+ int option_index;
std::string client_config_file;
- while ((c = getopt(argc, argv, "m:c:a:n:p:h:f:s:e:")) != -1) { // Added 'e:'
+ while ((c = getopt_long(argc, argv, "c:h", long_options, &option_index)) !=
-1) {
switch (c) {
- case 'm':
- caller_address = optarg;
- break;
- case 'c':
- client_config_file = optarg;
- break;
- case 'n':
- contract_name = optarg;
+ case -1:
break;
case 'f':
- func_name = optarg;
- break;
- case 'p':
- contract_path = optarg;
- break;
- case 'a':
- params = optarg;
+ config_file = optarg;
break;
- case 's':
- contract_address = optarg;
- break;
- case 'e':
- external_address = optarg; // Handle the 'e' option
+ case 'c':
+ client_config_file = optarg;
break;
case 'h':
ShowUsage();
break;
- default:
- ShowUsage();
- break;
}
}
- printf("cmd = %s config path = %s\n", cmd.c_str(),
- client_config_file.c_str());
+ nlohmann::json js = ReadJSConfig(config_file);
+ cmd = GetValue(js, "command");
+
+ printf("client config path = %s config path = %s cmd = %s\n",
client_config_file.c_str(), config_file.c_str(), cmd.c_str());
ResDBConfig config = GenerateResDBConfig(client_config_file);
config.SetClientTimeoutMs(100000);
ContractClient client(config);
- if (cmd == "create") {
+ if (cmd == "create_account") {
CreateAccount(&client);
- } else if (cmd == "add_address") {
- AddAddress(&client, external_address);
} else if (cmd == "deploy") {
+
+ contract_path = GetValue(js, "contract_path");
+ contract_name = GetValue(js, "contract_name");
+ contract_address = GetValue(js, "contract_address");
+ params = GetValue(js, "init_params");
+
+ printf("contract path %s cmd %s contract name %s caller_address %s init
params %s\n", contract_path.c_str(), cmd.c_str(), contract_name.c_str(),
contract_address.c_str(), params.c_str());
+
std::vector<std::string> init_params;
boost::split(init_params, params, boost::is_any_of(","));
- DeployContract(&client, caller_address, contract_name, contract_path,
+ DeployContract(&client, contract_address, contract_name, contract_path,
init_params);
} else if (cmd == "execute") {
+
+ caller_address = GetValue(js, "caller_address");
+ contract_address = GetValue(js, "contract_address");
+ func_name = GetValue(js, "func_name");
+ params = GetValue(js, "params");
+
printf(
"execute\n caller address:%s\n contract address: %s\n func: %s\n "
"params:%s\n",
@@ -155,7 +175,6 @@ int main(int argc, char** argv) {
ExecuteContract(&client, caller_address, contract_address, func_name,
func_params);
- } else {
- ShowUsage();
}
-}
\ No newline at end of file
+}
+
diff --git a/proto/contract/rpc.proto
b/service/tools/contract/api_tools/create.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/contract/api_tools/create.js
index 8df1dd40..26d34f6e 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/contract/api_tools/create.js
@@ -17,36 +17,7 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"create_account",
+
"contract_path":"/home/junechen/projects/asf-resilientdb/service/tools/contract/api_tools/example_contract/token.json"
}
diff --git a/proto/contract/rpc.proto
b/service/tools/contract/api_tools/deploy.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/contract/api_tools/deploy.js
index 8df1dd40..b013fa34 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/contract/api_tools/deploy.js
@@ -17,36 +17,10 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"deploy",
+ "contract_path":
"service/tools/contract/api_tools/example_contract/token.json",
+ "contract_name": "token.sol:Token",
+ "init_params": "1000",
+ "contract_address": "0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8"
}
diff --git a/service/tools/contract/api_tools/example_contract/token.json
b/service/tools/contract/api_tools/example_contract/token.json
index 1f91b6d5..eaeaa36f 100644
--- a/service/tools/contract/api_tools/example_contract/token.json
+++ b/service/tools/contract/api_tools/example_contract/token.json
@@ -1,15 +1,13 @@
{
- "contracts":
- {
- "token.sol:Token":
- {
- "bin":
"608060405234801561001057600080fd5b506040516101fe3803806101fe8339818101604052602081101561003357600080fd5b5051336000908152602081905260409020556101aa806100546000396000f3fe608060405234801561001057600080fd5b5060043610610052577c0100000000000000000000000000000000000000000000000000000000600035046370a082318114610057578063a9059cbb1461008f575b600080fd5b61007d6004803603602081101561006d57600080fd5b5035600160a060020a03166100cf565b60408051918252519081900360200190f35b6100bb6004803603604081
[...]
- "hashes":
- {
+ "contracts": {
+ "token.sol:Token": {
+ "bin":
"6080604052348015600f57600080fd5b506040516103f83803806103f8833981016040819052602c916040565b336000908152602081905260409020556058565b600060208284031215605157600080fd5b5051919050565b610391806100676000396000f3fe608060405234801561001057600080fd5b506004361061005d577c0100000000000000000000000000000000000000000000000000000000600035046370a082318114610062578063a5f2a1521461009e578063a9059cbb146100c1575b600080fd5b61008b610070366004610284565b600160a060020a03166000908152602081905260409020
[...]
+ "hashes": {
"balanceOf(address)": "70a08231",
- "transfer(address,uint256)": "a9059cbb"
+ "transfer(address,uint256)": "a9059cbb",
+ "transferTo(address,address,uint256)": "a5f2a152"
}
}
},
- "version": "0.5.16+commit.9c3226ce.Linux.g++"
+ "version": "0.8.28+commit.7893614a.Linux.g++"
}
diff --git a/service/tools/contract/api_tools/example_contract/token.sol
b/service/tools/contract/api_tools/example_contract/token.sol
index f5588212..498cacc1 100644
--- a/service/tools/contract/api_tools/example_contract/token.sol
+++ b/service/tools/contract/api_tools/example_contract/token.sol
@@ -28,4 +28,18 @@ contract Token {
return false;
}
}
+
+ function transferTo(address _from, address _to, uint256 _value) public
returns (bool) {
+ if (balances[_from] >= _value) {
+ balances[_from] -= _value;
+ balances[_to] += _value;
+ emit Transfer(_from, _to, _value);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
}
diff --git a/proto/contract/rpc.proto
b/service/tools/contract/api_tools/execute.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/contract/api_tools/execute.js
index 8df1dd40..df863de0 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/contract/api_tools/execute.js
@@ -17,36 +17,11 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"execute",
+ "init_params": "1000",
+ "contract_address": "0xfc08e5bfebdcf7bb4cf5aafc29be03c1d53898f1",
+ "caller_address": "0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8",
+ "func_name":"transfer(address,uint256)",
+ "params":"0x1be8e78d765a2e63339fc99a66320db73158a35a,100"
}
diff --git a/service/tools/contract/service_tools/start_contract_service.sh
b/service/tools/contract/service_tools/start_contract_service.sh
index 28438d75..fa290c6b 100755
--- a/service/tools/contract/service_tools/start_contract_service.sh
+++ b/service/tools/contract/service_tools/start_contract_service.sh
@@ -1,3 +1,5 @@
+<<<<<<< HEAD
+=======
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
@@ -16,6 +18,7 @@
# specific language governing permissions and limitations
# under the License.
#
+>>>>>>> master
killall -9 contract_service
SERVER_PATH=./bazel-bin/service/contract/contract_service
diff --git a/service/tools/kv/api_tools/BUILD b/service/tools/kv/api_tools/BUILD
index 61a7d366..a25b2f95 100644
--- a/service/tools/kv/api_tools/BUILD
+++ b/service/tools/kv/api_tools/BUILD
@@ -29,6 +29,18 @@ cc_binary(
],
)
+cc_binary(
+ name = "contract_service_tools",
+ srcs = ["contract_service_tools.cpp"],
+ deps = [
+ "//common/proto:signature_info_cc_proto",
+ "//interface/kv:contract_client",
+ "//platform/config:resdb_config_utils",
+ "//common:boost_comm",
+ ],
+)
+
+
cc_binary(
name = "kv_client_txn_tools",
srcs = ["kv_client_txn_tools.cpp"],
diff --git a/service/tools/contract/api_tools/contract_tools.cpp
b/service/tools/kv/api_tools/contract_service_tools.cpp
similarity index 60%
copy from service/tools/contract/api_tools/contract_tools.cpp
copy to service/tools/kv/api_tools/contract_service_tools.cpp
index 0271b312..0fcb05c5 100644
--- a/service/tools/contract/api_tools/contract_tools.cpp
+++ b/service/tools/kv/api_tools/contract_service_tools.cpp
@@ -19,11 +19,13 @@
#include <glog/logging.h>
+#include <getopt.h>
+#include <nlohmann/json.hpp>
#include <boost/algorithm/string.hpp>
#include <vector>
-#include <unistd.h> // For getopt
+#include <fstream>
-#include "interface/contract/contract_client.h"
+#include "interface/kv/contract_client.h"
#include "platform/config/resdb_config_utils.h"
using resdb::GenerateResDBConfig;
@@ -32,19 +34,17 @@ using resdb::contract::ContractClient;
void ShowUsage() {
printf(
- "<cmd> -c <config> -m <caller address> -n <contract name> -p <contract "
- "path> -a <params> -e <external address>\n");
+ "<cmd> -c <config> -m <caller address> -n <contract name> -p <contact "
+ "path> -a <params> \n");
exit(0);
}
-void AddAddress(ContractClient* client, const std::string& external_address) {
- absl::Status status = client->AddExternalAddress(external_address);
- if (!status.ok()) {
- printf("Add address failed\n");
- } else {
- printf("Address added successfully\n");
- }
-}
+static struct option long_options[] = {
+ { "cmd", required_argument, NULL, 'm'},
+ { "config_file", required_argument, NULL, 'f'},
+ { 0, 0, 0, 0 }
+};
+
void CreateAccount(ContractClient* client) {
auto account = client->CreateAccount();
@@ -81,70 +81,88 @@ void ExecuteContract(ContractClient* client, const
std::string& caller_address,
LOG(ERROR) << "execute result:\n" << *output;
}
+nlohmann::json ReadJSConfig(const std::string& config_path) {
+
+ std::ifstream contract_fstream(config_path);
+ if (!contract_fstream) {
+ throw std::runtime_error( "Unable to open config file "+config_path);
+ }
+
+ return nlohmann::json::parse(contract_fstream);
+}
+
+std::string GetValue(const nlohmann::json& js, std::string key){
+if(!js.contains(key)){
+ printf("need %s\n", key.c_str());
+ exit(0);
+ }
+ return js[key];
+}
+
+
int main(int argc, char** argv) {
- if (argc < 3) {
- ShowUsage();
+ if (argc < 2) {
+ printf("<cmd> -c [config]\n");
return 0;
}
- std::string cmd = argv[1];
+
+ std::string config_file;
+
+ std::string cmd;
std::string caller_address, contract_name, contract_path, params,
- contract_address, func_name, external_address; // Added external_address
+ contract_address, func_name;
int c;
+ int option_index;
std::string client_config_file;
- while ((c = getopt(argc, argv, "m:c:a:n:p:h:f:s:e:")) != -1) { // Added 'e:'
+ while ((c = getopt_long(argc, argv, "c:h", long_options, &option_index)) !=
-1) {
switch (c) {
- case 'm':
- caller_address = optarg;
- break;
- case 'c':
- client_config_file = optarg;
- break;
- case 'n':
- contract_name = optarg;
+ case -1:
break;
case 'f':
- func_name = optarg;
+ config_file = optarg;
break;
- case 'p':
- contract_path = optarg;
- break;
- case 'a':
- params = optarg;
- break;
- case 's':
- contract_address = optarg;
- break;
- case 'e':
- external_address = optarg; // Handle the 'e' option
+ case 'c':
+ client_config_file = optarg;
break;
case 'h':
ShowUsage();
break;
- default:
- ShowUsage();
- break;
}
}
- printf("cmd = %s config path = %s\n", cmd.c_str(),
- client_config_file.c_str());
+ nlohmann::json js = ReadJSConfig(config_file);
+ std::cout<<js<<std::endl;
+ cmd = GetValue(js, "command");
+
ResDBConfig config = GenerateResDBConfig(client_config_file);
config.SetClientTimeoutMs(100000);
ContractClient client(config);
-
- if (cmd == "create") {
+ printf("cmd = %s\n", cmd.c_str());
+ if (cmd == "create_account") {
CreateAccount(&client);
- } else if (cmd == "add_address") {
- AddAddress(&client, external_address);
} else if (cmd == "deploy") {
+
+ contract_path = GetValue(js, "contract_path");
+ contract_name = GetValue(js, "contract_name");
+ contract_address = GetValue(js, "contract_address");
+ params = GetValue(js, "init_params");
+
+ printf("contract path %s cmd %s contract name %s caller_address %s init
params %s\n", contract_path.c_str(), cmd.c_str(), contract_name.c_str(),
contract_address.c_str(), params.c_str());
+
std::vector<std::string> init_params;
boost::split(init_params, params, boost::is_any_of(","));
- DeployContract(&client, caller_address, contract_name, contract_path,
+ DeployContract(&client, contract_address, contract_name, contract_path,
init_params);
} else if (cmd == "execute") {
+
+ caller_address = GetValue(js, "caller_address");
+ contract_address = GetValue(js, "contract_address");
+ func_name = GetValue(js, "func_name");
+ params = GetValue(js, "params");
+
printf(
"execute\n caller address:%s\n contract address: %s\n func: %s\n "
"params:%s\n",
@@ -155,7 +173,18 @@ int main(int argc, char** argv) {
ExecuteContract(&client, caller_address, contract_address, func_name,
func_params);
- } else {
- ShowUsage();
}
-}
\ No newline at end of file
+ else if (cmd == "get_balance") {
+ std::string address = GetValue(js, "address");
+ auto balance_or = client.GetBalance(address);
+ printf("get address %s balance %s\n", address.c_str(),
(*balance_or).c_str());
+ } else if (cmd == "set_balance") {
+ std::string address = GetValue(js, "address");
+ std::string balance = GetValue(js, "balance");
+ printf("address %s balance %s\n", address.c_str(), balance.c_str());
+ auto ret = client.SetBalance(address, balance);
+ printf("set address %s balance %s ret %s\n", address.c_str(),
balance.c_str(), (*ret).c_str());
+ }
+
+}
+
diff --git a/proto/contract/rpc.proto b/service/tools/kv/api_tools/create.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/kv/api_tools/create.js
index 8df1dd40..79c94f9f 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/kv/api_tools/create.js
@@ -17,36 +17,6 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"create_account",
}
diff --git a/proto/contract/rpc.proto b/service/tools/kv/api_tools/deploy.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/kv/api_tools/deploy.js
index 8df1dd40..5c8cac1b 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/kv/api_tools/deploy.js
@@ -17,36 +17,10 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"deploy",
+ "contract_path": "service/tools/kv/api_tools/example_contract/token.json",
+ "contract_name": "token.sol:Token",
+ "init_params": "1000",
+ "contract_address": "0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8"
}
diff --git a/service/tools/kv/api_tools/example_contract/compile.sh
b/service/tools/kv/api_tools/example_contract/compile.sh
new file mode 100644
index 00000000..062b5ce7
--- /dev/null
+++ b/service/tools/kv/api_tools/example_contract/compile.sh
@@ -0,0 +1,21 @@
+ #
+ # Licensed to the Apache Software Foundation (ASF) under one
+ # or more contributor license agreements. See the NOTICE file
+ # distributed with this work for additional information
+ # regarding copyright ownership. The ASF licenses this file
+ # to you under the Apache License, Version 2.0 (the
+ # "License"); you may not use this file except in compliance
+ # with the License. You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing,
+ # software distributed under the License is distributed on an
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ # KIND, either express or implied. See the License for the
+ # specific language governing permissions and limitations
+ # under the License.
+ #
+
+solc --evm-version homestead --combined-json bin,hashes --pretty-json
--optimize token.sol > token.json
+
diff --git a/service/tools/kv/api_tools/example_contract/token.json
b/service/tools/kv/api_tools/example_contract/token.json
new file mode 100644
index 00000000..eaeaa36f
--- /dev/null
+++ b/service/tools/kv/api_tools/example_contract/token.json
@@ -0,0 +1,13 @@
+{
+ "contracts": {
+ "token.sol:Token": {
+ "bin":
"6080604052348015600f57600080fd5b506040516103f83803806103f8833981016040819052602c916040565b336000908152602081905260409020556058565b600060208284031215605157600080fd5b5051919050565b610391806100676000396000f3fe608060405234801561001057600080fd5b506004361061005d577c0100000000000000000000000000000000000000000000000000000000600035046370a082318114610062578063a5f2a1521461009e578063a9059cbb146100c1575b600080fd5b61008b610070366004610284565b600160a060020a03166000908152602081905260409020
[...]
+ "hashes": {
+ "balanceOf(address)": "70a08231",
+ "transfer(address,uint256)": "a9059cbb",
+ "transferTo(address,address,uint256)": "a5f2a152"
+ }
+ }
+ },
+ "version": "0.8.28+commit.7893614a.Linux.g++"
+}
diff --git a/service/tools/contract/api_tools/example_contract/token.sol
b/service/tools/kv/api_tools/example_contract/token.sol
similarity index 72%
copy from service/tools/contract/api_tools/example_contract/token.sol
copy to service/tools/kv/api_tools/example_contract/token.sol
index f5588212..498cacc1 100644
--- a/service/tools/contract/api_tools/example_contract/token.sol
+++ b/service/tools/kv/api_tools/example_contract/token.sol
@@ -28,4 +28,18 @@ contract Token {
return false;
}
}
+
+ function transferTo(address _from, address _to, uint256 _value) public
returns (bool) {
+ if (balances[_from] >= _value) {
+ balances[_from] -= _value;
+ balances[_to] += _value;
+ emit Transfer(_from, _to, _value);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
}
diff --git a/proto/contract/rpc.proto b/service/tools/kv/api_tools/execute.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/kv/api_tools/execute.js
index 8df1dd40..df863de0 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/kv/api_tools/execute.js
@@ -17,36 +17,11 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"execute",
+ "init_params": "1000",
+ "contract_address": "0xfc08e5bfebdcf7bb4cf5aafc29be03c1d53898f1",
+ "caller_address": "0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8",
+ "func_name":"transfer(address,uint256)",
+ "params":"0x1be8e78d765a2e63339fc99a66320db73158a35a,100"
}
diff --git a/proto/contract/rpc.proto
b/service/tools/kv/api_tools/get_balance.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/kv/api_tools/get_balance.js
index 8df1dd40..cb8a5ec4 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/kv/api_tools/get_balance.js
@@ -17,36 +17,7 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"get_balance",
+ "address":"0x1be8e78d765a2e63339fc99a66320db73158a35a"
}
diff --git a/proto/contract/rpc.proto
b/service/tools/kv/api_tools/set_balance.js
similarity index 52%
copy from proto/contract/rpc.proto
copy to service/tools/kv/api_tools/set_balance.js
index 8df1dd40..dec5d357 100644
--- a/proto/contract/rpc.proto
+++ b/service/tools/kv/api_tools/set_balance.js
@@ -17,36 +17,8 @@
* under the License.
*/
-syntax = "proto3";
-
-package resdb.contract;
-
-import "proto/contract/func_params.proto";
-import "proto/contract/contract.proto";
-import "proto/contract/account.proto";
-
-message Request {
- enum CMD {
- NONE = 0;
- CREATE_ACCOUNT = 1; // deploy contract
- DEPLOY = 2; // deploy contract
- EXECUTE = 3; // execute contract
- ADD_ADDRESS = 4; // add address
- };
-
- CMD cmd = 1;
- string caller_address = 2;
- optional DeployInfo deploy_info = 3;
- optional string contract_address = 4;
- optional Params func_params = 5;
- optional string external_address = 6;
-}
-
-
-
-message Response {
-int32 ret = 1;
-optional Account account = 2;
-optional Contract contract = 3;
-optional string res = 4;
+{
+ "command":"set_balance",
+ "address":"0x1be8e78d765a2e63339fc99a66320db73158a35a",
+ "balance":"2000"
}