diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0471054df..f8e60f19f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,11 +45,11 @@ ENDIF()
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${COMMON_ARGS}")
#libbitcoin has too many ignored-qualifiers, and TODOs
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ${COMMON_ARGS} -pthread -fno-enforce-eh-specs -fnothrow-opt -Wno-reorder -Wno-ignored-qualifiers -Wno-unused-function -Wno-unused-but-set-variable -Wno-sign-compare -Wno-unused-but-set-parameter")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ${COMMON_ARGS} -pthread -fno-enforce-eh-specs -fnothrow-opt -Wno-reorder -Wno-ignored-qualifiers -Wno-unused-function -Wno-unused-but-set-variable -Wno-sign-compare -Wno-unused-but-set-parameter -Wno-implicit-fallthrough")
ELSEIF("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
SET(CMAKE_C_FLAGS "-std=c11 ${COMMON_ARGS}")
- SET(CMAKE_CXX_FLAGS "-std=c++14 ${COMMON_ARGS} -Wno-reorder -Wno-ignored-qualifiers -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-mismatched-tags -Wno-overloaded-virtual -Wno-sometimes-uninitialized -Wno-macro-redefined -Wno-uninitialized -Wno-unused-private-field -Wno-unused-function")
+ SET(CMAKE_CXX_FLAGS "-std=c++14 ${COMMON_ARGS} -Wno-reorder -Wno-ignored-qualifiers -Wno-inconsistent-missing-override -Wno-missing-braces -Wno-mismatched-tags -Wno-overloaded-virtual -Wno-sometimes-uninitialized -Wno-macro-redefined -Wno-uninitialized -Wno-unused-private-field -Wno-unused-function -Wno-implicit-fallthrough")
ENDIF()
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fPIC")
diff --git a/builds/msvc-140/bitcoin/bitcoin.vcxproj b/builds/msvc-140/bitcoin/bitcoin.vcxproj
index 8b861e7cf..ade9b8d18 100644
--- a/builds/msvc-140/bitcoin/bitcoin.vcxproj
+++ b/builds/msvc-140/bitcoin/bitcoin.vcxproj
@@ -83,8 +83,6 @@
-
-
@@ -233,8 +231,6 @@
-
-
diff --git a/builds/msvc-140/bitcoin/bitcoin.vcxproj.filters b/builds/msvc-140/bitcoin/bitcoin.vcxproj.filters
index f86c370d5..d790a3178 100644
--- a/builds/msvc-140/bitcoin/bitcoin.vcxproj.filters
+++ b/builds/msvc-140/bitcoin/bitcoin.vcxproj.filters
@@ -395,12 +395,6 @@
Source Files\message
-
- Source Files\message
-
-
- Source Files\message
-
Source Files\message
@@ -823,9 +817,6 @@
Header Files\math
-
- Header Files\message
-
Header Files\message
@@ -919,9 +910,6 @@
Header Files\message
-
- Header Files\message
-
Header Files\unicode
diff --git a/builds/msvc/vs2015/metaverse.vcxproj b/builds/msvc/vs2015/metaverse.vcxproj
index 9dab7c353..e68b60c70 100644
--- a/builds/msvc/vs2015/metaverse.vcxproj
+++ b/builds/msvc/vs2015/metaverse.vcxproj
@@ -509,8 +509,6 @@
-
-
@@ -1080,13 +1078,11 @@
-
-
diff --git a/builds/msvc/vs2015/metaverse.vcxproj.filters b/builds/msvc/vs2015/metaverse.vcxproj.filters
index 0ffa99291..661489065 100644
--- a/builds/msvc/vs2015/metaverse.vcxproj.filters
+++ b/builds/msvc/vs2015/metaverse.vcxproj.filters
@@ -1176,12 +1176,6 @@
Source Files
-
- Source Files
-
-
- Source Files
-
Source Files
@@ -2900,9 +2894,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -2918,9 +2909,6 @@
Header Files
-
- Header Files
-
Header Files
diff --git a/contrib/jsoncpp/jsoncpp.cpp b/contrib/jsoncpp/jsoncpp.cpp
index a85e280ed..16caaf933 100644
--- a/contrib/jsoncpp/jsoncpp.cpp
+++ b/contrib/jsoncpp/jsoncpp.cpp
@@ -6,28 +6,28 @@
// //////////////////////////////////////////////////////////////////////
/*
-The JsonCpp library's source code, including accompanying documentation,
+The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...
-Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
-jurisdictions which recognize such a disclaimer. In such jurisdictions,
+Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
-In jurisdictions which recognize Public Domain property, the user of this
-software may choose to accept it either as 1) Public Domain, 2) under the
-conditions of the MIT License (see below), or 3) under the terms of dual
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.
The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:
http://en.wikipedia.org/wiki/MIT_License
-
+
The full text of the MIT License follows:
========================================================================
@@ -238,7 +238,7 @@ static inline void fixNumericLocaleInput(char* begin, char* end) {
#include
#if defined(_MSC_VER)
-#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
#define snprintf sprintf_s
#elif _MSC_VER >= 1900 // VC++ 14.0 and above
#define snprintf std::snprintf
@@ -382,7 +382,7 @@ bool Reader::parse(const char* beginDoc,
bool Reader::readValue() {
// readValue() may call itself only if it calls readObject() or ReadArray().
- // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
+ // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
// parse() executes one nodes_.push(), so > instead of >=.
if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
@@ -3549,9 +3549,13 @@ Value& Value::resolveReference(const char* key) {
// @param key is not null-terminated.
Value& Value::resolveReference(char const* key, char const* cend)
{
+ std::string info("in Json::Value::resolveReference(key, end): requires objectValue. ");
+ info += "key: "; info += key;
+ info += ", cend: "; info += cend;
+
JSON_ASSERT_MESSAGE(
type_ == nullValue || type_ == objectValue,
- "in Json::Value::resolveReference(key, end): requires objectValue");
+ info);
if (type_ == nullValue)
*this = Value(objectValue);
CZString actualKey(
@@ -4214,7 +4218,7 @@ Value& Path::make(Value& root) const {
#endif
#endif
-#if defined(__BORLANDC__)
+#if defined(__BORLANDC__)
#include
#define isfinite _finite
#define snprintf _snprintf
@@ -5288,7 +5292,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
bool eyc = settings_["enableYAMLCompatibility"].asBool();
bool dnp = settings_["dropNullPlaceholders"].asBool();
- bool usf = settings_["useSpecialFloats"].asBool();
+ bool usf = settings_["useSpecialFloats"].asBool();
unsigned int pre = settings_["precision"].asUInt();
CommentStyle::Enum cs = CommentStyle::All;
if (cs_str == "All") {
diff --git a/include/metaverse/bitcoin.hpp b/include/metaverse/bitcoin.hpp
index 581bbf589..be431c6da 100644
--- a/include/metaverse/bitcoin.hpp
+++ b/include/metaverse/bitcoin.hpp
@@ -63,8 +63,6 @@
#include
#include
#include
-#include
-#include
#include
#include
#include
diff --git a/include/metaverse/bitcoin/chain/attachment/account/account.hpp b/include/metaverse/bitcoin/chain/attachment/account/account.hpp
index 599e464f0..2f238499f 100644
--- a/include/metaverse/bitcoin/chain/attachment/account/account.hpp
+++ b/include/metaverse/bitcoin/chain/attachment/account/account.hpp
@@ -181,12 +181,6 @@ class BC_API account
uint8_t get_priority() const;
void set_priority(const uint8_t priority);
- void set_user_status(const uint8_t status);
- uint8_t get_user_status() const;
-
- void set_system_status(const uint8_t status);
- uint8_t get_system_status() const;
-
void set_type(uint8_t type);
uint8_t get_type() const;
diff --git a/include/metaverse/bitcoin/chain/attachment/asset/asset_cert.hpp b/include/metaverse/bitcoin/chain/attachment/asset/asset_cert.hpp
index 2d98fd563..a71e29d2f 100644
--- a/include/metaverse/bitcoin/chain/attachment/asset/asset_cert.hpp
+++ b/include/metaverse/bitcoin/chain/attachment/asset/asset_cert.hpp
@@ -120,7 +120,7 @@ class BC_API asset_cert
static std::string get_domain(const std::string& symbol);
static bool is_valid_domain(const std::string& domain);
- static std::string get_key(const std::string&symbol, asset_cert_type bit);
+ static std::string get_key(const std::string&symbol, const asset_cert_type& bit);
private:
// NOTICE: ref CAssetCert in transaction.h
diff --git a/include/metaverse/bitcoin/chain/output.hpp b/include/metaverse/bitcoin/chain/output.hpp
index 0145bfb3a..410997977 100644
--- a/include/metaverse/bitcoin/chain/output.hpp
+++ b/include/metaverse/bitcoin/chain/output.hpp
@@ -64,7 +64,6 @@ class BC_API output
std::string to_string(uint32_t flags) const;
bool is_valid() const;
code check_attachment_address(bc::blockchain::block_chain_impl& chain) const;
- code check_attachment_did_match_address(bc::blockchain::block_chain_impl& chain) const;
std::string get_script_address() const;
void reset();
uint64_t serialized_size() const;
diff --git a/include/metaverse/bitcoin/constants.hpp b/include/metaverse/bitcoin/constants.hpp
index 578dbd134..19ca77991 100644
--- a/include/metaverse/bitcoin/constants.hpp
+++ b/include/metaverse/bitcoin/constants.hpp
@@ -56,6 +56,10 @@ BC_CONSTEXPR uint32_t max_input_sequence = max_uint32;
BC_CONSTEXPR uint32_t total_reward = 100000000;
+BC_CONSTEXPR uint64_t min_fee_to_issue_asset = 10 * 100000000;
+BC_CONSTEXPR uint64_t min_fee_to_register_did = 1 * 100000000;
+BC_CONSTEXPR uint32_t min_fee_percentage_to_miner = 20;
+
// Threshold for nLockTime: below this value it is interpreted as block number,
// otherwise as UNIX timestamp. [Tue Nov 5 00:53:20 1985 UTC]
BC_CONSTEXPR uint32_t locktime_threshold = 500000000;
@@ -117,6 +121,8 @@ BC_CONSTEXPR message::network_address unspecified_network_address
// TODO: make static.
BC_API hash_number max_target();
+BC_API std::string get_developer_community_address(bool is_testnet);
+
} // namespace libbitcoin
#endif
diff --git a/include/metaverse/bitcoin/messages.hpp b/include/metaverse/bitcoin/messages.hpp
index 7a7e08591..5e4d6a7b1 100644
--- a/include/metaverse/bitcoin/messages.hpp
+++ b/include/metaverse/bitcoin/messages.hpp
@@ -23,8 +23,6 @@
#include
#include
-#include
-#include
#include
#include
#include
diff --git a/include/metaverse/bitcoin/version.hpp b/include/metaverse/bitcoin/version.hpp
index d1e948a9a..1acfb06e2 100644
--- a/include/metaverse/bitcoin/version.hpp
+++ b/include/metaverse/bitcoin/version.hpp
@@ -12,9 +12,9 @@
* For interpretation of the versioning scheme see: http://semver.org
*/
-#define MVS_VERSION "0.8.1"
+#define MVS_VERSION "0.8.2"
#define MVS_MAJOR_VERSION 0
#define MVS_MINOR_VERSION 8
-#define MVS_PATCH_VERSION 1
+#define MVS_PATCH_VERSION 2
#endif
diff --git a/include/metaverse/blockchain/block_chain_impl.hpp b/include/metaverse/blockchain/block_chain_impl.hpp
index 8dec047a5..3f9548294 100644
--- a/include/metaverse/blockchain/block_chain_impl.hpp
+++ b/include/metaverse/blockchain/block_chain_impl.hpp
@@ -229,10 +229,6 @@ class BCB_API block_chain_impl
operation_result store_account(std::shared_ptr acc);
std::shared_ptr get_account(const std::string& name);
std::shared_ptr> get_accounts();
- account_status get_account_user_status(const std::string& name);
- account_status get_account_system_status(const std::string& name);
- bool set_account_user_status(const std::string& name, uint8_t status);
- bool set_account_system_status(const std::string& name, uint8_t status);
operation_result delete_account(const std::string& name);
operation_result delete_account_address(const std::string& name);
@@ -257,8 +253,9 @@ class BCB_API block_chain_impl
uint64_t get_account_asset_volume(const std::string& account, const std::string& asset);
uint64_t get_asset_volume(const std::string& asset);
+ // asset api
bool is_asset_exist(const std::string& asset_name, bool check_local_db=true);
- bool get_asset_height(const std::string& asset_name, uint64_t& height);
+ uint64_t get_asset_height(const std::string& asset_name) const ;
std::shared_ptr get_local_assets();
std::shared_ptr get_issued_assets();
std::shared_ptr get_issued_asset(const std::string& symbol);
@@ -269,6 +266,7 @@ class BCB_API block_chain_impl
// cert api
bool is_asset_cert_exist(const std::string& symbol, asset_cert_type cert_type);
+ uint64_t get_asset_cert_height(const std::string& cert_symbol,const asset_cert_type& cert_type);
std::shared_ptr get_issued_asset_certs();
std::shared_ptr get_account_asset_cert(
const std::string& account, const std::string& symbol, asset_cert_type cert_type);
@@ -278,6 +276,8 @@ class BCB_API block_chain_impl
const std::string& address, const std::string& symbol, asset_cert_type cert_type);
// identifiable asset
+ bool is_asset_mit_exist(const std::string& symbol);
+ uint64_t get_asset_mit_height(const std::string& mit_symbol)const;
std::shared_ptr get_registered_mit(const std::string& symbol);
std::shared_ptr get_registered_mits();
std::shared_ptr get_mit_history(const std::string& symbol,
@@ -287,10 +287,10 @@ class BCB_API block_chain_impl
// account did api
bool is_did_exist(const std::string& symbol);
- bool get_did_height(const std::string& symbol, uint64_t& height);
- bool is_address_registered_did(const std::string& address);
+ uint64_t get_did_height(const std::string& symbol) const;
+ bool is_address_registered_did(const std::string& address, uint64_t fork_index = max_uint64);
bool is_account_owned_did(const std::string& account, const std::string& symbol);
- std::string get_did_from_address(const std::string& address);
+ std::string get_did_from_address(const std::string& address, uint64_t fork_index = max_uint64);
std::shared_ptr get_registered_did(const std::string& symbol);
std::shared_ptr get_registered_dids();
std::shared_ptr get_account_dids(const std::string& account);
@@ -320,11 +320,11 @@ class BCB_API block_chain_impl
std::shared_ptr get_account_addresses(const std::string& name);
void uppercase_symbol(std::string& symbol);
- bool is_valid_address(const std::string& address);
- bool is_payment_address(const std::string& address);
- bool is_stealth_address(const std::string& address);
- bool is_script_address(const std::string& address);
- bool is_blackhole_address(const std::string& address);
+ static bool is_valid_address(const std::string& address);
+ static bool is_payment_address(const std::string& address);
+ static bool is_stealth_address(const std::string& address);
+ static bool is_script_address(const std::string& address);
+ static bool is_blackhole_address(const std::string& address);
void fired();
organizer& get_organizer();
diff --git a/include/metaverse/blockchain/validate_block.hpp b/include/metaverse/blockchain/validate_block.hpp
index 417253bfc..4ad066a20 100644
--- a/include/metaverse/blockchain/validate_block.hpp
+++ b/include/metaverse/blockchain/validate_block.hpp
@@ -46,7 +46,7 @@ class BCB_API validate_block
public:
code check_block(blockchain::block_chain_impl& chain) const;
code accept_block() const;
- code connect_block(hash_digest& err_tx) const;
+ code connect_block(hash_digest& err_tx, blockchain::block_chain_impl& chain) const;
/// Required to call before calling accept_block or connect_block.
void initialize_context();
@@ -55,6 +55,15 @@ class BCB_API validate_block
bool get_transaction(const hash_digest& tx_hash, chain::transaction& prev_tx, size_t& prev_height) const;
+ virtual std::string get_did_from_address_consider_orphan_chain(const std::string& address, const std::string& did_symbol) const = 0;
+ virtual bool is_did_match_address_in_orphan_chain(const std::string& symbol, const std::string& address) const = 0;
+ virtual bool is_did_in_orphan_chain(const std::string& symbol) const = 0;
+ virtual bool is_asset_in_orphan_chain(const std::string& symbol) const = 0;
+ virtual bool is_asset_cert_in_orphan_chain(const std::string& symbol, asset_cert_type cert_type) const = 0;
+ virtual bool is_asset_mit_in_orphan_chain(const std::string& symbol) const = 0;
+
+ virtual size_t get_fork_index() const { return max_size_t; }
+
protected:
typedef std::vector versions;
typedef std::function stopped_callback;
diff --git a/include/metaverse/blockchain/validate_block_impl.hpp b/include/metaverse/blockchain/validate_block_impl.hpp
index e9e874d42..e174d0d9a 100644
--- a/include/metaverse/blockchain/validate_block_impl.hpp
+++ b/include/metaverse/blockchain/validate_block_impl.hpp
@@ -44,6 +44,15 @@ class BCB_API validate_block_impl
virtual bool is_valid_proof_of_work(const chain::header& header) const;
virtual bool check_get_coinage_reward_transaction(const chain::transaction& coinage_reward_coinbase, const chain::output& output) const;
+ virtual std::string get_did_from_address_consider_orphan_chain(const std::string& address, const std::string& did_symbol) const override;
+ virtual bool is_did_match_address_in_orphan_chain(const std::string& symbol, const std::string& address) const override;
+ virtual bool is_did_in_orphan_chain(const std::string& symbol) const override;
+ virtual bool is_asset_in_orphan_chain(const std::string& symbol) const override;
+ virtual bool is_asset_cert_in_orphan_chain(const std::string& symbol, asset_cert_type cert_type) const override;
+ virtual bool is_asset_mit_in_orphan_chain(const std::string& symbol) const override;
+
+ virtual size_t get_fork_index() const override { return fork_index_; }
+
protected:
uint64_t median_time_past() const;
u256 previous_block_bits() const;
diff --git a/include/metaverse/blockchain/validate_transaction.hpp b/include/metaverse/blockchain/validate_transaction.hpp
index 5f976165e..0d6645e17 100644
--- a/include/metaverse/blockchain/validate_transaction.hpp
+++ b/include/metaverse/blockchain/validate_transaction.hpp
@@ -67,17 +67,22 @@ class BCB_API validate_transaction
code check_asset_mit_transaction() const;
code check_did_transaction() const;
bool connect_did_input(const did& info) const;
- code connect_input_address_match_did(const output& output) const;
+ bool is_did_match_address_in_orphan_chain(const std::string& symbol, const std::string& address) const;
+ bool is_did_in_orphan_chain(const std::string& did) const;
+ code check_attachment_to_did(const output& output) const;
+ code connect_attachment_from_did(const output& output) const;
bool connect_input(const chain::transaction& previous_tx, size_t parent_height);
- static bool tally_fees(const chain::transaction& tx, uint64_t value_in,
- uint64_t& fees);
+ static bool tally_fees(blockchain::block_chain_impl& chain,
+ const chain::transaction& tx, uint64_t value_in, uint64_t& fees);
+ static bool check_special_fees(bool is_testnet, const chain::transaction& tx, uint64_t fees);
bool check_asset_amount(const transaction& tx) const;
bool check_asset_symbol(const transaction& tx) const;
bool check_asset_certs(const transaction& tx) const;
bool check_asset_mit(const transaction& tx) const;
+ bool check_address_registered_did(const std::string& address) const;
//check input did match output did
bool check_did_symbol_match(const transaction& tx) const;
@@ -115,6 +120,10 @@ class BCB_API validate_transaction
void check_double_spend(const code& ec, const chain::input_point& point);
void check_fees() const;
code check_tx_connect_input() const;
+ bool check_did_exist(const std::string& did) const;
+ bool check_asset_exist(const std::string& symbol) const;
+ bool check_asset_cert_exist(const std::string& cert, asset_cert_type cert_type) const;
+ bool check_asset_mit_exist(const std::string& mit) const;
block_chain_impl& blockchain_;
const transaction_ptr tx_;
diff --git a/include/metaverse/consensus/libethash/internal.c b/include/metaverse/consensus/libethash/internal.c
index c76a1521b..0610fa7d5 100644
--- a/include/metaverse/consensus/libethash/internal.c
+++ b/include/metaverse/consensus/libethash/internal.c
@@ -8,11 +8,11 @@
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with cpp-ethereum. If not, see .
+ along with cpp-ethereum. If not, see .
*/
/** @file internal.c
* @author Tim Hughes
@@ -218,10 +218,10 @@ static bool ethash_hash(
for (unsigned n = 0; n != MIX_NODES; ++n) {
node const* dag_node;
+ node tmp_node;
if (full_nodes) {
dag_node = &full_nodes[MIX_NODES * index + n];
} else {
- node tmp_node;
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light);
dag_node = &tmp_node;
}
@@ -241,7 +241,7 @@ static bool ethash_hash(
#elif defined(__MIC__)
{
// __m512i implementation via union
- // Each vector register (zmm) can store sixteen 32-bit integer numbers
+ // Each vector register (zmm) can store sixteen 32-bit integer numbers
__m512i fnv_prime = _mm512_set1_epi32(FNV_PRIME);
__m512i zmm0 = _mm512_mullo_epi32(fnv_prime, mix[n].zmm[0]);
mix[n].zmm[0] = _mm512_xor_si512(zmm0, dag_node->zmm[0]);
@@ -389,7 +389,7 @@ ethash_return_value_t ethash_light_compute_internal(
uint64_t nonce
)
{
- ethash_return_value_t ret;
+ ethash_return_value_t ret;
ret.success = true;
if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) {
ret.success = false;
@@ -446,42 +446,44 @@ ethash_full_t ethash_full_new_internal(
return NULL;
}
ret->file_size = (size_t)full_size;
- switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
- case ETHASH_IO_FAIL:
- // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
+
+ enum ethash_io_rc err = ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false);
+ if (err == ETHASH_IO_FAIL)
goto fail_free_full;
- case ETHASH_IO_MEMO_MATCH:
- if (!ethash_mmap(ret, f)) {
- ETHASH_CRITICAL("mmap failure()");
- goto fail_close_file;
- }
-#if defined(__MIC__)
- node* tmp_nodes = _mm_malloc((size_t)full_size, 64);
- //copy all nodes from ret->data
- //mmapped_nodes are not aligned properly
- uint32_t const countnodes = (uint32_t) ((size_t)ret->file_size / sizeof(node));
- //fprintf(stderr,"ethash_full_new_internal:countnodes:%d",countnodes);
- for (uint32_t i = 1; i != countnodes; ++i) {
- tmp_nodes[i] = ret->data[i];
- }
- ret->data = tmp_nodes;
-#endif
- return ret;
- case ETHASH_IO_MEMO_SIZE_MISMATCH:
+
+ if (err == ETHASH_IO_MEMO_SIZE_MISMATCH) {
// if a DAG of same filename but unexpected size is found, silently force new file creation
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
goto fail_free_full;
}
- // fallthrough to the mismatch case here, DO NOT go through match
- case ETHASH_IO_MEMO_MISMATCH:
+ // we now need to go through the mismatch case, NOT the match case
+ err = ETHASH_IO_MEMO_MISMATCH;
+ }
+
+ if (err == ETHASH_IO_MEMO_MISMATCH || err == ETHASH_IO_MEMO_MATCH) {
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
- break;
+
+ if (err == ETHASH_IO_MEMO_MATCH) {
+#if defined(__MIC__)
+ node* tmp_nodes = _mm_malloc((size_t)full_size, 64);
+ //copy all nodes from ret->data
+ //mmapped_nodes are not aligned properly
+ uint32_t const countnodes = (uint32_t) ((size_t)ret->file_size / sizeof(node));
+ //fprintf(stderr,"ethash_full_new_internal:countnodes:%d",countnodes);
+ for (uint32_t i = 1; i != countnodes; ++i) {
+ tmp_nodes[i] = ret->data[i];
+ }
+ ret->data = tmp_nodes;
+#endif
+ return ret;
+ }
}
+
#if defined(__MIC__)
ret->data = _mm_malloc((size_t)full_size, 64);
#endif
@@ -568,4 +570,4 @@ void const* ethash_full_dag(ethash_full_t full)
uint64_t ethash_full_dag_size(ethash_full_t full)
{
return full->file_size;
-}
+}
\ No newline at end of file
diff --git a/include/metaverse/database/databases/address_asset_database.hpp b/include/metaverse/database/databases/address_asset_database.hpp
index 0ac6eb4d1..b52a7e83c 100644
--- a/include/metaverse/database/databases/address_asset_database.hpp
+++ b/include/metaverse/database/databases/address_asset_database.hpp
@@ -121,6 +121,10 @@ class BCD_API address_asset_database
const std::string& symbol, asset_cert_type cert_type,
size_t from_height) const;
+ business_history::list get_asset_certs_history(const std::string& address,
+ const std::string& symbol, asset_cert_type cert_type,
+ size_t from_height) const;
+
/// Delete the last row that was added to key.
void delete_last_row(const short_hash& key);
diff --git a/include/metaverse/database/databases/address_did_database.hpp b/include/metaverse/database/databases/address_did_database.hpp
index 158d2e3c3..e9005a34d 100644
--- a/include/metaverse/database/databases/address_did_database.hpp
+++ b/include/metaverse/database/databases/address_did_database.hpp
@@ -112,7 +112,7 @@ class BCD_API address_did_database
business_address_did::list get_dids(const std::string& address,
size_t from_height, business_kind kind) const;
business_address_did::list get_dids(const std::string& address,
- size_t from_height) const;
+ size_t from_height, size_t to_height = max_uint64) const;
business_address_message::list get_messages(const std::string& address,
size_t from_height) const;
diff --git a/include/metaverse/database/databases/blockchain_asset_database.hpp b/include/metaverse/database/databases/blockchain_asset_database.hpp
index 610f3bf38..e61061d2b 100644
--- a/include/metaverse/database/databases/blockchain_asset_database.hpp
+++ b/include/metaverse/database/databases/blockchain_asset_database.hpp
@@ -67,6 +67,12 @@ class BCD_API blockchain_asset_database
uint64_t get_asset_volume(const std::string& name) const;
+ ///
+ std::shared_ptr get_register_history(const std::string & asset_symbol) const;
+ ///
+ uint64_t get_register_height(const std::string & asset_symbol) const;
+
+
void store(const hash_digest& hash, const blockchain_asset& sp_detail);
/// Delete a transaction from database.
diff --git a/include/metaverse/database/databases/blockchain_did_database.hpp b/include/metaverse/database/databases/blockchain_did_database.hpp
index c56d624b7..76e2b6d13 100644
--- a/include/metaverse/database/databases/blockchain_did_database.hpp
+++ b/include/metaverse/database/databases/blockchain_did_database.hpp
@@ -67,6 +67,15 @@ class BCD_API blockchain_did_database
///
std::shared_ptr > get_blockchain_dids() const;
+ ///
+ std::shared_ptr get_register_history(const std::string & did_symbol) const;
+ ///
+ uint64_t get_register_height(const std::string & did_symbol) const;
+
+ std::shared_ptr > getdids_from_address_history(
+ const std::string &address, const uint64_t& fromheight = 0
+ ,const uint64_t & toheight = max_uint64 ) const;
+
void store(const hash_digest& hash, const blockchain_did& sp_detail);
/// Delete a transaction from database.
diff --git a/include/metaverse/database/databases/blockchain_mit_database.hpp b/include/metaverse/database/databases/blockchain_mit_database.hpp
index 682b56112..a6bd5d73c 100644
--- a/include/metaverse/database/databases/blockchain_mit_database.hpp
+++ b/include/metaverse/database/databases/blockchain_mit_database.hpp
@@ -57,6 +57,11 @@ class BCD_API blockchain_mit_database
/// Get all asset certs
std::shared_ptr get_blockchain_mits() const;
+ ///
+ std::shared_ptr get_register_history(const std::string & mit_symbol) const;
+ ///
+ uint64_t get_register_height(const std::string & mit_symbol) const;
+
void store(const asset_mit_info& mit_info);
/// Delete a transaction from database.
diff --git a/include/metaverse/database/impl/slab_hash_table.ipp b/include/metaverse/database/impl/slab_hash_table.ipp
index 37ce68e4d..85d0a49b1 100644
--- a/include/metaverse/database/impl/slab_hash_table.ipp
+++ b/include/metaverse/database/impl/slab_hash_table.ipp
@@ -182,6 +182,7 @@ std::vector slab_hash_table::finds(const KeyType& key) cons
return ret;
}
+
// This is limited to returning all the item in the special index.
template
std::shared_ptr> slab_hash_table::find(uint64_t index) const
@@ -215,7 +216,6 @@ std::shared_ptr> slab_hash_table::find(uint64_t
return vec_memo;
}
-
// This is limited to unlinking the first of multiple matching key values.
template
bool slab_hash_table::unlink(const KeyType& key)
diff --git a/include/metaverse/explorer/extensions/base_helper.hpp b/include/metaverse/explorer/extensions/base_helper.hpp
index b9bddf03d..d0078d976 100644
--- a/include/metaverse/explorer/extensions/base_helper.hpp
+++ b/include/metaverse/explorer/extensions/base_helper.hpp
@@ -147,10 +147,39 @@ struct balances {
uint64_t frozen_balance;
};
+struct deposited_balance {
+ deposited_balance(const std::string& address_, const string& tx_hash_, const string& row_hash_,
+ uint64_t balance_, uint64_t deposited_, uint64_t expiration_)
+ : address(address_)
+ , tx_hash(tx_hash_)
+ , row_hash(row_hash_)
+ , balance(balance_)
+ , deposited_height(deposited_)
+ , expiration_height(expiration_)
+ {}
+
+ std::string address;
+ std::string tx_hash;
+ std::string row_hash;
+ uint64_t balance;
+ uint64_t deposited_height;
+ uint64_t expiration_height;
+
+ // for sort
+ bool operator< (const deposited_balance& other) const {
+ return expiration_height < other.expiration_height;
+ }
+
+ typedef std::vector list;
+};
+
// helper function
void sync_fetchbalance(wallet::payment_address& address,
bc::blockchain::block_chain_impl& blockchain, balances& addr_balance);
+void sync_fetch_deposited_balance(wallet::payment_address& address,
+ bc::blockchain::block_chain_impl& blockchain, std::shared_ptr sh_vec);
+
void sync_fetch_asset_balance(const std::string& address, bool sum_all,
bc::blockchain::block_chain_impl& blockchain,
std::shared_ptr sh_asset_vec);
@@ -165,6 +194,8 @@ std::string get_random_payment_address(std::shared_ptr unissued_asset_;
std::string domain_cert_address_;
std::string attenuation_model_param_;
+ uint32_t fee_percentage_to_miner_;
};
class BCX_API secondary_issuing_asset : public base_transfer_helper
@@ -548,11 +581,13 @@ class BCX_API registering_did : public base_multisig_transfer_helper
public:
registering_did(command& cmd, bc::blockchain::block_chain_impl& blockchain,
std::string&& name, std::string&& passwd,
- std::string&& from, std::string&& symbol, receiver_record::list&& receiver_list, uint64_t fee,
+ std::string&& from, std::string&& symbol, receiver_record::list&& receiver_list,
+ uint64_t fee, uint32_t fee_percentage_to_miner,
account_multisig&& multisig)
: base_multisig_transfer_helper(cmd, blockchain, std::move(name), std::move(passwd),
std::move(from), std::move(receiver_list), fee, std::move(symbol),
std::move(multisig))
+ , fee_percentage_to_miner_(fee_percentage_to_miner)
{}
~registering_did()
@@ -564,6 +599,9 @@ class BCX_API registering_did : public base_multisig_transfer_helper
tx_.version = transaction_version::check_nova_feature;
tx_.locktime = 0;
};
+
+private:
+ uint32_t fee_percentage_to_miner_;
};
class BCX_API sending_multisig_did : public base_transfer_helper
diff --git a/include/metaverse/explorer/extensions/commands/didsend.hpp b/include/metaverse/explorer/extensions/commands/didsend.hpp
index 9987561db..a75088b92 100644
--- a/include/metaverse/explorer/extensions/commands/didsend.hpp
+++ b/include/metaverse/explorer/extensions/commands/didsend.hpp
@@ -43,7 +43,7 @@ class didsend: public send_command
return get_argument_metadata()
.add("ACCOUNTNAME", 1)
.add("ACCOUNTAUTH", 1)
- .add("TODID/TOADDRESS", 1)
+ .add("TO_", 1)
.add("AMOUNT", 1);
}
@@ -53,7 +53,7 @@ class didsend: public send_command
const auto raw = requires_raw_input();
load_input(auth_.name, "ACCOUNTNAME", variables, input, raw);
load_input(auth_.auth, "ACCOUNTAUTH", variables, input, raw);
- load_input(argument_.did, "TODID/TOADDRESS", variables, input, raw);
+ load_input(argument_.did, "TO_", variables, input, raw);
load_input(argument_.amount, "AMOUNT", variables, input, raw);
}
@@ -78,7 +78,7 @@ class didsend: public send_command
BX_ACCOUNT_AUTH
)
(
- "TODID/TOADDRESS",
+ "TO_",
value(&argument_.did)->required(),
"Send to this did/address"
)
diff --git a/include/metaverse/explorer/extensions/commands/didsendasset.hpp b/include/metaverse/explorer/extensions/commands/didsendasset.hpp
index 43f526dc6..24d7146e0 100644
--- a/include/metaverse/explorer/extensions/commands/didsendasset.hpp
+++ b/include/metaverse/explorer/extensions/commands/didsendasset.hpp
@@ -45,7 +45,7 @@ class didsendasset: public command_extension
return get_argument_metadata()
.add("ACCOUNTNAME", 1)
.add("ACCOUNTAUTH", 1)
- .add("TODID/TOADDRESS", 1)
+ .add("TO_", 1)
.add("ASSET", 1)
.add("AMOUNT", 1);
}
@@ -56,7 +56,7 @@ class didsendasset: public command_extension
const auto raw = requires_raw_input();
load_input(auth_.name, "ACCOUNTNAME", variables, input, raw);
load_input(auth_.auth, "ACCOUNTAUTH", variables, input, raw);
- load_input(argument_.did, "TODID/TOADDRESS", variables, input, raw);
+ load_input(argument_.did, "TO_", variables, input, raw);
load_input(argument_.symbol, "ASSET", variables, input, raw);
load_input(argument_.amount, "AMOUNT", variables, input, raw);
}
@@ -82,7 +82,7 @@ class didsendasset: public command_extension
BX_ACCOUNT_AUTH
)
(
- "TODID/TOADDRESS",
+ "TO_",
value(&argument_.did)->required(),
"Asset receiver did/address."
)
diff --git a/include/metaverse/explorer/extensions/commands/didsendassetfrom.hpp b/include/metaverse/explorer/extensions/commands/didsendassetfrom.hpp
index 51206e6b1..2d7236ac7 100644
--- a/include/metaverse/explorer/extensions/commands/didsendassetfrom.hpp
+++ b/include/metaverse/explorer/extensions/commands/didsendassetfrom.hpp
@@ -45,8 +45,8 @@ class didsendassetfrom: public command_extension
return get_argument_metadata()
.add("ACCOUNTNAME", 1)
.add("ACCOUNTAUTH", 1)
- .add("FROMDID/FROMADDRESS", 1)
- .add("TODID/TOADDRESS", 1)
+ .add("FROM_", 1)
+ .add("TO_", 1)
.add("SYMBOL", 1)
.add("AMOUNT", 1);
}
@@ -57,8 +57,8 @@ class didsendassetfrom: public command_extension
const auto raw = requires_raw_input();
load_input(auth_.name, "ACCOUNTNAME", variables, input, raw);
load_input(auth_.auth, "ACCOUNTAUTH", variables, input, raw);
- load_input(argument_.fromdid, "FROMDID/FROMADDRESS", variables, input, raw);
- load_input(argument_.todid, "TODID/TOADDRESS", variables, input, raw);
+ load_input(argument_.fromdid, "FROM_", variables, input, raw);
+ load_input(argument_.todid, "TO_", variables, input, raw);
load_input(argument_.symbol, "SYMBOL", variables, input, raw);
load_input(argument_.amount, "AMOUNT", variables, input, raw);
}
@@ -84,12 +84,12 @@ class didsendassetfrom: public command_extension
BX_ACCOUNT_AUTH
)
(
- "FROMDID/FROMADDRESS",
+ "FROM_",
value(&argument_.fromdid)->required(),
"From did/address"
)
(
- "TODID/TOADDRESS",
+ "TO_",
value(&argument_.todid)->required(),
"Target did/address"
)
diff --git a/include/metaverse/explorer/extensions/commands/didsendfrom.hpp b/include/metaverse/explorer/extensions/commands/didsendfrom.hpp
index 9216475b3..189b3d193 100644
--- a/include/metaverse/explorer/extensions/commands/didsendfrom.hpp
+++ b/include/metaverse/explorer/extensions/commands/didsendfrom.hpp
@@ -45,8 +45,8 @@ class didsendfrom: public send_command
return get_argument_metadata()
.add("ACCOUNTNAME", 1)
.add("ACCOUNTAUTH", 1)
- .add("FROMDID/FROMADDRESS", 1)
- .add("TODID/TOADDRESS", 1)
+ .add("FROM_", 1)
+ .add("TO_", 1)
.add("AMOUNT", 1);
}
@@ -56,8 +56,8 @@ class didsendfrom: public send_command
const auto raw = requires_raw_input();
load_input(auth_.name, "ACCOUNTNAME", variables, input, raw);
load_input(auth_.auth, "ACCOUNTAUTH", variables, input, raw);
- load_input(argument_.fromdid, "FROMDID/FROMADDRESS", variables, input, raw);
- load_input(argument_.todid, "TODID/TOADDRESS", variables, input, raw);
+ load_input(argument_.fromdid, "FROM_", variables, input, raw);
+ load_input(argument_.todid, "TO_", variables, input, raw);
load_input(argument_.amount, "AMOUNT", variables, input, raw);
}
@@ -82,12 +82,12 @@ class didsendfrom: public send_command
BX_ACCOUNT_AUTH
)
(
- "FROMDID/FROMADDRESS",
+ "FROM_",
value(&argument_.fromdid)->required(),
"Send from this did/address"
)
(
- "TODID/TOADDRESS",
+ "TO_",
value(&argument_.todid)->required(),
"Send to this did/address"
)
diff --git a/include/metaverse/explorer/extensions/commands/getaddressasset.hpp b/include/metaverse/explorer/extensions/commands/getaddressasset.hpp
index 4ee135441..0a345b80e 100644
--- a/include/metaverse/explorer/extensions/commands/getaddressasset.hpp
+++ b/include/metaverse/explorer/extensions/commands/getaddressasset.hpp
@@ -43,8 +43,6 @@ class getaddressasset: public command_extension
arguments_metadata& load_arguments() override
{
return get_argument_metadata()
- //.add("ACCOUNTNAME", 1)
- //.add("ACCOUNTAUTH", 1)
.add("ADDRESS", 1);
}
@@ -52,8 +50,6 @@ class getaddressasset: public command_extension
po::variables_map& variables) override
{
const auto raw = requires_raw_input();
- //load_input(auth_.name, "ACCOUNTNAME", variables, input, raw);
- //load_input(auth_.auth, "ACCOUNTAUTH", variables, input, raw);
load_input(argument_.address, "ADDRESS", variables, input, raw);
}
diff --git a/include/metaverse/explorer/extensions/commands/getdid.hpp b/include/metaverse/explorer/extensions/commands/getdid.hpp
index b463ce9d7..3bbb73701 100644
--- a/include/metaverse/explorer/extensions/commands/getdid.hpp
+++ b/include/metaverse/explorer/extensions/commands/getdid.hpp
@@ -43,14 +43,14 @@ class getdid: public command_extension
arguments_metadata& load_arguments() override
{
return get_argument_metadata()
- .add("DID/ADDRESS", 1);
+ .add("DidOrAddress", 1);
}
void load_fallbacks (std::istream& input,
po::variables_map& variables) override
{
const auto raw = requires_raw_input();
- load_input(option_.symbol, "DID/ADDRESS", variables, input, raw);
+ load_input(option_.symbol, "DidOrAddress", variables, input, raw);
}
options_metadata& load_options() override
@@ -64,7 +64,7 @@ class getdid: public command_extension
"Get a description and instructions for this command."
)
(
- "DID/ADDRESS",
+ "DidOrAddress",
value(&option_.symbol),
"Did symbol or standard address; If no input parameters, then display whole network DIDs."
);
diff --git a/include/metaverse/explorer/extensions/commands/issue.hpp b/include/metaverse/explorer/extensions/commands/issue.hpp
index b0e7e449f..f8bba85d4 100644
--- a/include/metaverse/explorer/extensions/commands/issue.hpp
+++ b/include/metaverse/explorer/extensions/commands/issue.hpp
@@ -88,8 +88,13 @@ class issue: public command_extension
)
(
"fee,f",
- value(&argument_.fee)->default_value(1000000000),
- "The fee of tx. default_value 10 etp"
+ value(&argument_.fee)->default_value(10 * 100000000),
+ "The fee of tx. minimum is 10 etp."
+ )
+ (
+ "percentage,p",
+ value(&argument_.percentage)->default_value(20),
+ "Percentage of fee send to miner. minimum is 20."
);
return options;
@@ -106,6 +111,7 @@ class issue: public command_extension
{
std::string symbol;
uint64_t fee;
+ uint32_t percentage;
} argument_;
struct option
diff --git a/include/metaverse/explorer/extensions/commands/listbalances.hpp b/include/metaverse/explorer/extensions/commands/listbalances.hpp
index 193cf1d1e..8b3e95e70 100644
--- a/include/metaverse/explorer/extensions/commands/listbalances.hpp
+++ b/include/metaverse/explorer/extensions/commands/listbalances.hpp
@@ -65,10 +65,15 @@ class listbalances: public command_extension
value()->zero_tokens(),
"Get a description and instructions for this command."
)
+ (
+ "deposited,d",
+ value(&option_.deposited)->zero_tokens()->default_value(false),
+ "list deposited ETPs, default is false."
+ )
(
"nozero,n",
value(&option_.non_zero)->zero_tokens()->default_value(false),
- "Defaults to false."
+ "Default is false."
)
(
"greater_equal,g",
@@ -108,6 +113,7 @@ class listbalances: public command_extension
struct option
{
bool non_zero;
+ bool deposited;
uint64_t greater;
uint64_t lesser;
} option_;
diff --git a/include/metaverse/explorer/extensions/commands/registerdid.hpp b/include/metaverse/explorer/extensions/commands/registerdid.hpp
index 1678856f0..c7d94285c 100644
--- a/include/metaverse/explorer/extensions/commands/registerdid.hpp
+++ b/include/metaverse/explorer/extensions/commands/registerdid.hpp
@@ -93,6 +93,11 @@ class registerdid: public command_extension
"fee,f",
value(&argument_.fee)->default_value(100000000),
"The fee of tx. defaults to 1 etp."
+ )
+ (
+ "percentage,p",
+ value(&argument_.percentage)->default_value(20),
+ "Percentage of fee send to miner. minimum is 20."
);
return options;
@@ -110,6 +115,7 @@ class registerdid: public command_extension
std::string address;
std::string symbol;
uint64_t fee;
+ uint32_t percentage;
} argument_;
struct option
diff --git a/include/metaverse/explorer/impl/json_helper.ipp b/include/metaverse/explorer/impl/json_helper.ipp
index 0d3d9a973..b3600d497 100644
--- a/include/metaverse/explorer/impl/json_helper.ipp
+++ b/include/metaverse/explorer/impl/json_helper.ipp
@@ -40,6 +40,8 @@ Json::Value json_helper::prop_tree_list(const std::string& name, const Values& v
for (const auto& value: values)
list.append(Json::Value()[denormalized_name] = prop_list(value));
+ if(list.isNull())
+ list.resize(0);
return list;
}
@@ -53,6 +55,10 @@ Json::Value json_helper::prop_tree_list_of_lists(const std::string& name,
for (const auto& value: values)
list.append(Json::Value()[denormalized_name] = prop_list(value, json));
+
+ if(list.isNull())
+ list.resize(0);
+
return list;
}
@@ -68,6 +74,9 @@ Json::Value json_helper::prop_value_list(const std::string& name, const Values&
list.append(Json::Value()[denormalized_name] += value);
}
+ if(list.isNull())
+ list.resize(0);
+
return list;
}
diff --git a/include/metaverse/explorer/json_helper.hpp b/include/metaverse/explorer/json_helper.hpp
index 4543c169e..c147ec769 100644
--- a/include/metaverse/explorer/json_helper.hpp
+++ b/include/metaverse/explorer/json_helper.hpp
@@ -275,6 +275,9 @@ BCX_API Json::Value prop_tree(const chain::points_info& points_info, bool json);
*/
BCX_API Json::Value prop_list(const transaction& transaction, bool json);
BCX_API Json::Value prop_list(const transaction& transaction, uint64_t tx_height, bool json);
+
+BCX_API Json::Value prop_list_of_rawtx(const transaction& transaction, bool with_hash, bool ignore_compatibility=false);
+
/**
* Generate a property tree for a transaction.
* @param[in] transaction The transaction.
@@ -464,6 +467,14 @@ BCX_API Json::Value prop_list(const bc::chain::account_multisig& multisign);
*/
BCX_API Json::Value prop_attenuation_model_param(const data_chunk& param);
+/**
+ * Generate a property list for an account.
+ * @param[in] acc The account.
+ * @return A property list.
+ */
+typedef std::tuple account_info;
+BCX_API Json::Value prop_list(const account_info& acc);
+
private:
uint8_t version_{ 1 }; //1 - api v1; 2 - api v2;
};
diff --git a/include/metaverse/explorer/version.hpp b/include/metaverse/explorer/version.hpp
index d5566d76a..4247cf7b2 100644
--- a/include/metaverse/explorer/version.hpp
+++ b/include/metaverse/explorer/version.hpp
@@ -12,9 +12,9 @@
* For interpretation of the versioning scheme see: http://semver.org
*/
-#define MVS_EXPLORER_VERSION "0.8.1"
+#define MVS_EXPLORER_VERSION "0.8.2"
#define MVS_EXPLORER_MAJOR_VERSION 0
#define MVS_EXPLORER_MINOR_VERSION 8
-#define MVS_EXPLORER_PATCH_VERSION 1
+#define MVS_EXPLORER_PATCH_VERSION 2
#endif
diff --git a/include/metaverse/mgbubble/utility/Stream_buf.hpp b/include/metaverse/mgbubble/utility/Stream_buf.hpp
index 53f01af1d..b04da3e23 100644
--- a/include/metaverse/mgbubble/utility/Stream_buf.hpp
+++ b/include/metaverse/mgbubble/utility/Stream_buf.hpp
@@ -30,7 +30,7 @@ namespace mgbubble {
class StreamBuf : public std::streambuf {
public:
- explicit StreamBuf(mbuf& buf) throw(std::bad_alloc);
+ explicit StreamBuf(mbuf& buf);
~StreamBuf() noexcept override;
// Copy.
diff --git a/include/metaverse/network/message_subscriber.hpp b/include/metaverse/network/message_subscriber.hpp
index f46c68a72..31a700269 100644
--- a/include/metaverse/network/message_subscriber.hpp
+++ b/include/metaverse/network/message_subscriber.hpp
@@ -57,7 +57,6 @@ class BCT_API message_subscriber
{
public:
DEFINE_SUBSCRIBER_TYPE(address);
- DEFINE_SUBSCRIBER_TYPE(alert);
DEFINE_SUBSCRIBER_TYPE(block_message);
DEFINE_SUBSCRIBER_TYPE(block_transactions);
DEFINE_SUBSCRIBER_TYPE(compact_block);
@@ -172,7 +171,6 @@ class BCT_API message_subscriber
private:
DEFINE_SUBSCRIBER_OVERLOAD(address);
- DEFINE_SUBSCRIBER_OVERLOAD(alert);
DEFINE_SUBSCRIBER_OVERLOAD(block_message);
DEFINE_SUBSCRIBER_OVERLOAD(block_transactions);
DEFINE_SUBSCRIBER_OVERLOAD(compact_block);
@@ -200,7 +198,6 @@ class BCT_API message_subscriber
DEFINE_SUBSCRIBER_OVERLOAD(version);
DECLARE_SUBSCRIBER(address);
- DECLARE_SUBSCRIBER(alert);
DECLARE_SUBSCRIBER(block_message);
DECLARE_SUBSCRIBER(block_transactions);
DECLARE_SUBSCRIBER(compact_block);
diff --git a/src/lib/bitcoin/chain/attachment/account/account.cpp b/src/lib/bitcoin/chain/attachment/account/account.cpp
index 479a1eaba..b4eca84e6 100644
--- a/src/lib/bitcoin/chain/attachment/account/account.cpp
+++ b/src/lib/bitcoin/chain/attachment/account/account.cpp
@@ -491,26 +491,6 @@ void account::set_priority(uint8_t priority)
this->priority = priority;
}
-void account::set_user_status(uint8_t status)
-{
- this->status |= status;
-}
-
-void account::set_system_status(uint8_t status)
-{
- this->status |= (status << sizeof(uint8_t));
-}
-
-uint8_t account::get_user_status() const
-{
- return static_cast(status & 0xff);
-}
-
-uint8_t account::get_system_status() const
-{
- return static_cast(status >> sizeof(uint8_t));
-}
-
const account_multisig::list& account::get_multisig_vec() const
{
return multisig_vec;
diff --git a/src/lib/bitcoin/chain/attachment/asset/asset_cert.cpp b/src/lib/bitcoin/chain/attachment/asset/asset_cert.cpp
index 2df3c9df5..a8f16e25e 100644
--- a/src/lib/bitcoin/chain/attachment/asset/asset_cert.cpp
+++ b/src/lib/bitcoin/chain/attachment/asset/asset_cert.cpp
@@ -84,7 +84,7 @@ bool asset_cert::is_valid_domain(const std::string& domain)
return !domain.empty();
}
-std::string asset_cert::get_key(const std::string&symbol, asset_cert_type bit)
+std::string asset_cert::get_key(const std::string&symbol, const asset_cert_type& bit)
{
return std::string(symbol + ":^#`@:" + std::to_string(bit));
}
diff --git a/src/lib/bitcoin/chain/attachment/asset/attenuation_model.cpp b/src/lib/bitcoin/chain/attachment/asset/attenuation_model.cpp
index 2bcbb2ae4..453c7da46 100644
--- a/src/lib/bitcoin/chain/attachment/asset/attenuation_model.cpp
+++ b/src/lib/bitcoin/chain/attachment/asset/attenuation_model.cpp
@@ -650,12 +650,16 @@ bool attenuation_model::check_model_param_uc_uq(attenuation_model& parser)
log::debug(LOG_HEADER) << "attenuation param error: UQ.size() != UN";
return false;
}
- if (sum_and_check_numbers(UCs, is_positive_number) != LP) {
- log::debug(LOG_HEADER) << "attenuation param error: LP != sum(UC) or exist UC <= 0";
+ auto value = sum_and_check_numbers(UCs, is_positive_number);
+ if (value != LP) {
+ log::debug(LOG_HEADER) << "attenuation param error: LP("
+ << std::to_string(LP) <<") != sum(UC)(" << std::to_string(value) << ") or exist UC <= 0";
return false;
}
- if (sum_and_check_numbers(UQs, is_positive_number) != LQ) {
- log::debug(LOG_HEADER) << "attenuation param error: LQ != sum(UQ) or exist UQ <= 0";
+ value = sum_and_check_numbers(UQs, is_positive_number);
+ if (value != LQ) {
+ log::debug(LOG_HEADER) << "attenuation param error: LQ("
+ << std::to_string(LQ) <<") != sum(UQ)(" << std::to_string(value) << ") or exist UQ <= 0";
return false;
}
return true;
diff --git a/src/lib/bitcoin/chain/block.cpp b/src/lib/bitcoin/chain/block.cpp
index 94fd5e44f..27c460c8e 100644
--- a/src/lib/bitcoin/chain/block.cpp
+++ b/src/lib/bitcoin/chain/block.cpp
@@ -146,7 +146,7 @@ data_chunk block::to_data(bool with_transaction_count) const
data_sink ostream(data);
to_data(ostream, with_transaction_count);
ostream.flush();
- BITCOIN_ASSERT(data.size() == serialized_size(with_transaction_count));
+ BITCOIN_ASSERT(header.number <= 1270000 || data.size() == serialized_size(with_transaction_count));
return data;
}
diff --git a/src/lib/bitcoin/chain/output.cpp b/src/lib/bitcoin/chain/output.cpp
index 12906cc1e..3e66aa60c 100644
--- a/src/lib/bitcoin/chain/output.cpp
+++ b/src/lib/bitcoin/chain/output.cpp
@@ -157,31 +157,21 @@ code output::check_attachment_address(bc::blockchain::block_chain_impl& chain) c
if (is_asset || is_did) {
auto script_address = get_script_address();
if (attachment_address != script_address) {
- if (is_asset)
+ log::debug("output::check_attachment_address")
+ << (is_asset ? "asset" : "did")
+ << " attachment address " << attachment_address
+ << " is not equal to script address " << script_address;
+ if (is_asset) {
return error::asset_address_not_match;
- if (is_did)
+ }
+ if (is_did) {
return error::did_address_not_match;
+ }
}
}
return error::success;
}
-code output::check_attachment_did_match_address(bc::blockchain::block_chain_impl& chain) const
-{
-
- auto todid = attach_data.get_to_did();
- if (!todid.empty())
- {
- auto address = get_script_address();
- if (todid != chain.get_did_from_address(address))
- {
- return error::did_address_not_match;
- }
- }
-
- return error::success;
-}
-
void output::reset()
{
value = 0;
diff --git a/src/lib/bitcoin/constants.cpp b/src/lib/bitcoin/constants.cpp
index 270a1fab7..6d8b26207 100644
--- a/src/lib/bitcoin/constants.cpp
+++ b/src/lib/bitcoin/constants.cpp
@@ -30,4 +30,13 @@ hash_number max_target()
return max_target;
}
+std::string get_developer_community_address(bool is_testnet)
+{
+ std::string address("MAwLwVGwJyFsTBfNj2j5nCUrQXGVRvHzPh"); // developer-community address for mainnet
+ if (is_testnet) {
+ address = "tJNo92g6DavpaCZbYjrH45iQ8eAKnLqmms"; // developer-community address for testnet
+ }
+ return address;
+}
+
} // namespace libbitcoin
diff --git a/src/lib/bitcoin/message/heading.cpp b/src/lib/bitcoin/message/heading.cpp
index 942fcd2f2..5156bb405 100644
--- a/src/lib/bitcoin/message/heading.cpp
+++ b/src/lib/bitcoin/message/heading.cpp
@@ -150,8 +150,6 @@ message_type heading::type() const
// TODO: convert to static map.
if (command == address::command)
return message_type::address;
- if (command == alert::command)
- return message_type::alert;
if (command == block_transactions::command)
return message_type::block_transactions;
if (command == block_message::command)
diff --git a/src/lib/blockchain/block_chain_impl.cpp b/src/lib/blockchain/block_chain_impl.cpp
index da2a05c9d..7f24fc184 100644
--- a/src/lib/blockchain/block_chain_impl.cpp
+++ b/src/lib/blockchain/block_chain_impl.cpp
@@ -24,6 +24,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -1450,6 +1452,11 @@ bool block_chain_impl::is_asset_cert_exist(const std::string& symbol, asset_cert
return database_.certs.get(key) != nullptr;
}
+bool block_chain_impl::is_asset_mit_exist(const std::string& symbol)
+{
+ return get_registered_mit(symbol) != nullptr;
+}
+
std::shared_ptr block_chain_impl::get_registered_mit(const std::string& symbol)
{
BITCOIN_ASSERT(!symbol.empty());
@@ -1845,11 +1852,9 @@ bool block_chain_impl::is_did_exist(const std::string& did_name)
/* check did address exist or not
*/
-bool block_chain_impl::is_address_registered_did(const std::string& did_address)
+bool block_chain_impl::is_address_registered_did(const std::string& did_address, uint64_t fork_index)
{
- // find from blockchain database
- auto&& did_vec = database_.address_dids.get_dids(did_address, 0);
- return !did_vec.empty();
+ return !get_did_from_address(did_address, fork_index).empty();
}
bool block_chain_impl::is_account_owned_did(const std::string& account, const std::string& symbol)
@@ -1877,28 +1882,49 @@ std::shared_ptr block_chain_impl::get_account_dids(const std::
auto pvaddr = get_account_addresses(account);
if (pvaddr) {
for (const auto& account_address : *pvaddr) {
- auto&& did_vec = database_.address_dids.get_dids(account_address.get_address(), 0);
- if (!did_vec.empty()) {
- sh_vec->emplace_back(std::move(did_vec[0].detail));
+ auto did_address = account_address.get_address();
+ auto did_symbol = get_did_from_address(did_address);
+ if (!did_symbol.empty()) {
+ sh_vec->emplace_back(did_detail(did_symbol, did_address));
}
}
}
return sh_vec;
}
-
/* find did by address
*/
-std::string block_chain_impl::get_did_from_address(const std::string& did_address)
+std::string block_chain_impl::get_did_from_address(const std::string& did_address, uint64_t fork_index)
{
- // find from blockchain database
- business_address_did::list did_vec = database_.address_dids.get_dids(did_address, 0);
+ //search from address_did_database first
+ business_address_did::list did_vec = database_.address_dids.get_dids(did_address, 0, fork_index);
- if (!did_vec.empty()) {
- return did_vec[0].detail.get_symbol();
+ std::string did_symbol= "";
+ if(!did_vec.empty())
+ did_symbol = did_vec[0].detail.get_symbol();
+
+ if(did_symbol != "")
+ {
+ //double check
+ std::shared_ptr blockchain_didlist = get_did_history_addresses(did_symbol);
+ auto iter = std::find_if(blockchain_didlist->begin(), blockchain_didlist->end(),
+ [fork_index](const blockchain_did & item){
+ return is_blackhole_address(item.get_did().get_address()) || item.get_height() <= fork_index;
+ });
+
+ if(iter == blockchain_didlist->end() || iter->get_did().get_address() != did_address)
+ return "";
+ }
+ else if(did_symbol == "" && fork_index != max_uint64)
+ {
+ // search from dids database
+ auto sp_did_vec = database_.dids.getdids_from_address_history(did_address, 0, fork_index);
+ if (sp_did_vec && !sp_did_vec->empty()) {
+ did_symbol = sp_did_vec->back().get_did().get_symbol();
+ }
}
- return "";
+ return did_symbol;
}
/* find history addresses by the did symbol
@@ -1987,48 +2013,6 @@ std::shared_ptr block_chain_impl::get_account_me
return sp_asset_vec;
}
-account_status block_chain_impl::get_account_user_status(const std::string& name)
-{
- account_status ret_val = account_status::error;
- auto account = get_account(name);
- if (account) // account exist
- ret_val = static_cast(account->get_user_status());
- return ret_val;
-}
-
-account_status block_chain_impl::get_account_system_status(const std::string& name)
-{
- account_status ret_val = account_status::error;
- auto account = get_account(name);
- if (account) // account exist
- ret_val = static_cast(account->get_system_status());
- return ret_val;
-}
-
-bool block_chain_impl::set_account_user_status(const std::string& name, uint8_t status)
-{
- bool ret_val = false;
- auto account = get_account(name);
- if (account) // account exist
- {
- account->set_user_status(status);
- ret_val = true;
- }
- return ret_val;
-}
-
-bool block_chain_impl::set_account_system_status(const std::string& name, uint8_t status)
-{
- bool ret_val = false;
- auto account = get_account(name);
- if (account) // account exist
- {
- account->set_system_status(status);
- ret_val = true;
- }
- return ret_val;
-}
-
void block_chain_impl::fired()
{
organizer_.fired();
@@ -2058,30 +2042,34 @@ bool block_chain_impl::is_asset_exist(const std::string& asset_name, bool check_
return false;
}
-bool block_chain_impl::get_asset_height(const std::string& asset_name, uint64_t& height)
+uint64_t block_chain_impl::get_asset_height(const std::string& asset_name)const
{
- const auto hash = get_hash(asset_name);
-
- // std::shared_ptr
- auto sp_asset = database_.assets.get(hash);
- if(sp_asset) {
- height = sp_asset->get_height();
- }
-
- return (sp_asset != nullptr);
+ return database_.assets.get_register_height(asset_name);
}
-bool block_chain_impl::get_did_height(const std::string& did_name, uint64_t& height)
+uint64_t block_chain_impl::get_did_height(const std::string& did_name)const
{
- const auto hash = get_hash(did_name);
+ return database_.dids.get_register_height(did_name);
+}
- // std::shared_ptr
- auto sp_did = database_.dids.get(hash);
- if(sp_did) {
- height = sp_did->get_height();
+uint64_t block_chain_impl::get_asset_cert_height(const std::string& cert_symbol,const asset_cert_type& cert_type)
+{
+ auto&& key_str = asset_cert::get_key(cert_symbol, cert_type);
+ const auto key = get_hash(key_str);
+ auto cert = database_.certs.get(key);
+ if(cert)
+ {
+ business_history::list history_cert = database_.address_assets.get_asset_certs_history(cert->get_address(), cert_symbol, cert_type, 0);
+ if(history_cert.size()>0){
+ return history_cert.back().output_height;
+ }
}
+ return max_uint64;
+}
- return (sp_did != nullptr);
+uint64_t block_chain_impl::get_asset_mit_height(const std::string& mit_symbol) const
+{
+ return database_.mits.get_register_height(mit_symbol);
}
/// get asset from local database including all account's assets
diff --git a/src/lib/blockchain/organizer.cpp b/src/lib/blockchain/organizer.cpp
index cc338d100..bf89f34ca 100644
--- a/src/lib/blockchain/organizer.cpp
+++ b/src/lib/blockchain/organizer.cpp
@@ -109,27 +109,31 @@ code organizer::verify(uint64_t fork_point,
};
// Validates current_block
- validate_block_impl validate(chain_, fork_point, orphan_chain,
- orphan_index, height, *current_block, use_testnet_rules_, checkpoints_,
- callback);
+ validate_block_impl validate(chain_, fork_point, orphan_chain, orphan_index, height,
+ *current_block, use_testnet_rules_, checkpoints_, callback);
// Checks that are independent of the chain.
auto ec = validate.check_block(static_cast(this->chain_));
-
- if (ec)
+ if (error::success != ec) {
+ log::debug(LOG_BLOCKCHAIN) << "organizer: check_block failed! fork_point: "
+ << std::to_string(fork_point) << ", orphan_index: " << std::to_string(orphan_index);
return ec;
+ }
validate.initialize_context();
// Checks that are dependent on height and preceding blocks.
ec = validate.accept_block();
-
- if (ec)
+ if (error::success != ec) {
+ log::debug(LOG_BLOCKCHAIN) << "organizer: accept_block failed! fork_point: "
+ << std::to_string(fork_point) << ", orphan_index: " << std::to_string(orphan_index);
return ec;
+ }
// Start strict validation if past last checkpoint.
- if (!strict(fork_point))
+ if (!strict(fork_point)) {
return ec;
+ }
const auto total_inputs = count_inputs(*current_block);
const auto total_transactions = current_block->transactions.size();
@@ -143,7 +147,7 @@ code organizer::verify(uint64_t fork_point,
{
hash_digest err_tx;
// Checks that include input->output traversal.
- ec = validate.connect_block(err_tx);
+ ec = validate.connect_block(err_tx, static_cast(this->chain_));
if(ec && err_tx != null_hash) {
dynamic_cast(chain_).pool().delete_tx(err_tx);
}
diff --git a/src/lib/blockchain/orphan_pool.cpp b/src/lib/blockchain/orphan_pool.cpp
index 70f1c85c5..6fcc90958 100644
--- a/src/lib/blockchain/orphan_pool.cpp
+++ b/src/lib/blockchain/orphan_pool.cpp
@@ -88,7 +88,7 @@ void orphan_pool::remove(block_detail::ptr block)
log::debug(LOG_BLOCKCHAIN)
<< "Orphan pool removed block [" << encode_hash(block->hash())
- << "] old size (" << old_size << ").";
+ << "] old size (" << old_size << "). with status: " << block->error().message();
}
// TODO: use hash table pool to eliminate this O(n^2) search.
diff --git a/src/lib/blockchain/transaction_pool.cpp b/src/lib/blockchain/transaction_pool.cpp
index a20658044..ccf3ec2ff 100644
--- a/src/lib/blockchain/transaction_pool.cpp
+++ b/src/lib/blockchain/transaction_pool.cpp
@@ -162,100 +162,123 @@ code transaction_pool::check_symbol_repeat(transaction_ptr tx)
std::set asset_mits;
std::set dids;
std::set didaddreses;
+ std::set didattaches;
- for (auto& item : buffer_)
+ auto check_outputs = [&](transaction_ptr txs)->code
{
- if (!item.tx)
- continue;
-
- for (auto& output : item.tx->outputs)
+ for (auto &output : txs->outputs)
{
- if (output.is_asset_issue()) {
+ //add attachment check;avoid send with did while transfer
+ if (output.attach_data.get_version() == DID_ATTACH_VERIFY_VERSION)
+ {
+ auto check_did = [&dids, &didattaches](string attach_did) {
+ if (!attach_did.empty() && dids.find(attach_did) != dids.end())
+ {
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_symbol_repeat attachment did: " + attach_did
+ << " already exists in memorypool!";
+ return false;
+ }
+
+ didattaches.insert(attach_did);
+ return true;
+ };
+
+ if (!check_did(output.attach_data.get_from_did())
+ || !check_did(output.attach_data.get_to_did())) {
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_symbol_repeat from_did " + output.attach_data.get_from_did()
+ << " to_did " + output.attach_data.get_to_did()
+ << " check failed!"
+ << " " << tx->to_string(1);
+ return error::did_exist;
+ }
+ }
+
+ if (output.is_asset_issue())
+ {
auto r = assets.insert(output.get_asset_symbol());
- if (r.second == false) {
+ if (r.second == false)
+ {
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_symbol_repeat asset " + output.get_asset_symbol()
+ << " already exists in memorypool!"
+ << " " << tx->to_string(1);
return error::asset_exist;
}
}
- else if (output.is_asset_cert()) {
- auto&& key = output.get_asset_cert().get_key();
+ else if (output.is_asset_cert())
+ {
+ auto &&key = output.get_asset_cert().get_key();
auto r = asset_certs.insert(key);
- if (r.second == false) {
+ if (r.second == false)
+ {
log::debug(LOG_BLOCKCHAIN)
- << " cert " + output.get_asset_cert_symbol()
+ << "check_symbol_repeat cert " + output.get_asset_cert_symbol()
<< " with type " << output.get_asset_cert_type()
- << " already exists in pool!"
+ << " already exists in memorypool!"
<< " " << tx->to_string(1);
return error::asset_cert_exist;
}
}
- else if (output.is_asset_mit()) {
+ else if (output.is_asset_mit())
+ {
auto r = asset_mits.insert(output.get_asset_symbol());
- if (r.second == false) {
+ if (r.second == false)
+ {
log::debug(LOG_BLOCKCHAIN)
- << " mit " + output.get_asset_symbol()
- << " already exists in block!"
+ << "check_symbol_repeat mit " + output.get_asset_symbol()
+ << " already exists in memorypool!"
<< " " << tx->to_string(1);
return error::mit_exist;
}
}
- else if (output.is_did()) {
- auto didexist = dids.insert(output.get_did_symbol());
+ else if (output.is_did())
+ {
+ auto didsymbol = output.get_did_symbol();
+ auto didexist = dids.insert(didsymbol);
if (didexist.second == false) {
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_symbol_repeat did " + didsymbol
+ << " already exists in memorypool!"
+ << " " << tx->to_string(1);
return error::did_exist;
}
auto didaddress = didaddreses.insert(output.get_did_address());
- if (didaddress.second == false ) {
+ if (didaddress.second == false)
+ {
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_symbol_repeat did address " + output.get_did_address()
+ << " already has did on it in memorypool!"
+ << " " << tx->to_string(1);
return error::address_registered_did;
}
+
+ if (didattaches.find(didsymbol) != didattaches.end())
+ {
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_symbol_repeat attachment did: " + didsymbol
+ << " already transfer in memorypool!"
+ << " " << tx->to_string(1);
+ return error::did_exist;
+ }
}
}
- }
+ return error::success;
+ };
- for (auto& output : tx->outputs)
+ code ec;
+ for (auto &item : buffer_)
{
- if (output.is_asset_issue()) {
- auto r = assets.insert(output.get_asset_symbol());
- if (r.second == false) {
- return error::asset_exist;
- }
- }
- else if (output.is_asset_cert()) {
- auto&& key = output.get_asset_cert().get_key();
- auto r = asset_certs.insert(key);
- if (r.second == false) {
- log::debug(LOG_BLOCKCHAIN)
- << " cert " + output.get_asset_cert_symbol()
- << " with type " << output.get_asset_cert_type()
- << " already exists!"
- << " " << tx->to_string(1);
- return error::asset_cert_exist;
- }
- }
- else if (output.is_asset_mit()) {
- auto r = asset_mits.insert(output.get_asset_symbol());
- if (r.second == false) {
- log::debug(LOG_BLOCKCHAIN)
- << " mit " + output.get_asset_symbol()
- << " already exists!"
- << " " << tx->to_string(1);
- return error::mit_exist;
- }
- }
- else if (output.is_did()) {
- auto didexist = dids.insert(output.get_did_symbol());
- if (didexist.second == false) {
- return error::did_exist;
- }
+ if (!item.tx)
+ continue;
- auto didaddress = didaddreses.insert(output.get_did_address());
- if (didaddress.second == false ) {
- return error::address_registered_did;
- }
- }
+ if((ec = check_outputs(item.tx)) != error::success)
+ break;
}
- return error::success;
+ return ec != error::success ? ec : check_outputs(tx);
}
// handle_confirm will never fire if handle_validate returns a failure code.
diff --git a/src/lib/blockchain/validate_block.cpp b/src/lib/blockchain/validate_block.cpp
index 8ee89da6a..798b63871 100644
--- a/src/lib/blockchain/validate_block.cpp
+++ b/src/lib/blockchain/validate_block.cpp
@@ -272,24 +272,28 @@ code validate_block::check_block(blockchain::block_chain_impl& chain) const
std::set asset_mits;
std::set dids;
std::set didaddreses;
+ code first_tx_ec = error::success;
for (const auto& tx : transactions)
{
RETURN_IF_STOPPED();
const auto validate_tx = std::make_shared(chain, tx, *this);
auto ec = validate_tx->check_transaction();
- if (ec)
- return ec;
-
- ec = validate_tx->check_transaction_connect_input(header.number);
- if (ec)
- return ec;
+ if (!ec) {
+ ec = validate_tx->check_transaction_connect_input(header.number);
+ }
- for (auto& output : const_cast(tx).outputs) {
+ for (size_t i = 0; (!ec) && (i < tx.outputs.size()); ++i) {
+ const auto& output = tx.outputs[i];
if (output.is_asset_issue()) {
auto r = assets.insert(output.get_asset_symbol());
if (r.second == false) {
- return error::asset_exist;
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_block asset " + output.get_asset_symbol()
+ << " already exists in block!"
+ << " " << tx.to_string(1);
+ ec = error::asset_exist;
+ break;
}
}
else if (output.is_asset_cert()) {
@@ -297,35 +301,58 @@ code validate_block::check_block(blockchain::block_chain_impl& chain) const
auto r = asset_certs.insert(key);
if (r.second == false) {
log::debug(LOG_BLOCKCHAIN)
- << " cert " + output.get_asset_cert_symbol()
+ << "check_block cert " + output.get_asset_cert_symbol()
<< " with type " << output.get_asset_cert_type()
<< " already exists in block!"
<< " " << tx.to_string(1);
- return error::asset_cert_exist;
+ ec = error::asset_cert_exist;
+ break;
}
}
else if (output.is_asset_mit()) {
auto r = asset_mits.insert(output.get_asset_symbol());
if (r.second == false) {
log::debug(LOG_BLOCKCHAIN)
- << " mit " + output.get_asset_symbol()
+ << "check_block mit " + output.get_asset_symbol()
<< " already exists in block!"
<< " " << tx.to_string(1);
- return error::mit_exist;
+ ec = error::mit_exist;
+ break;
}
}
else if (output.is_did()) {
auto didexist = dids.insert(output.get_did_symbol());
if (didexist.second == false) {
- return error::did_exist;
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_block did " + output.get_did_symbol()
+ << " already exists in block!"
+ << " " << tx.to_string(1);
+ ec = error::did_exist;
+ break;
}
auto didaddress = didaddreses.insert(output.get_did_address());
if (didaddress.second == false ) {
- return error::address_registered_did;
+ log::debug(LOG_BLOCKCHAIN)
+ << "check_block did " + output.get_did_address()
+ << " address_registered_did!"
+ << " " << tx.to_string(1);
+ ec = error::address_registered_did;
+ break;
}
}
}
+
+ if (ec) {
+ if (!first_tx_ec) {
+ first_tx_ec = ec;
+ }
+ chain.pool().delete_tx(tx.hash());
+ }
+ }
+
+ if (first_tx_ec) {
+ return first_tx_ec;
}
RETURN_IF_STOPPED();
@@ -547,7 +574,7 @@ bool validate_block::is_valid_coinbase_height(size_t height, const block& block)
return std::equal(expected.begin(), expected.end(), actual.begin());
}
-code validate_block::connect_block(hash_digest& err_tx) const
+code validate_block::connect_block(hash_digest& err_tx, blockchain::block_chain_impl& chain) const
{
err_tx = null_hash;
const auto& transactions = current_block_.transactions;
@@ -612,7 +639,7 @@ code validate_block::connect_block(hash_digest& err_tx) const
RETURN_IF_STOPPED();
- if (!validate_transaction::tally_fees(tx, value_in, fees))
+ if (!validate_transaction::tally_fees(chain, tx, value_in, fees))
{
err_tx = tx.hash();
return error::fees_out_of_range;
diff --git a/src/lib/blockchain/validate_block_impl.cpp b/src/lib/blockchain/validate_block_impl.cpp
index 07d3d7527..e710742dc 100644
--- a/src/lib/blockchain/validate_block_impl.cpp
+++ b/src/lib/blockchain/validate_block_impl.cpp
@@ -35,26 +35,27 @@ namespace blockchain {
static constexpr size_t median_time_past_blocks = 11;
validate_block_impl::validate_block_impl(simple_chain& chain,
- size_t fork_index, const block_detail::list& orphan_chain,
- size_t orphan_index, size_t height, const chain::block& block,
- bool testnet, const config::checkpoint::list& checks,
- stopped_callback stopped)
- : validate_block(height, block, testnet, checks, stopped),
- chain_(chain),
- height_(height),
- fork_index_(fork_index),
- orphan_index_(orphan_index),
- orphan_chain_(orphan_chain)
+ size_t fork_index, const block_detail::list& orphan_chain,
+ size_t orphan_index, size_t height, const chain::block& block,
+ bool testnet, const config::checkpoint::list& checks,
+ stopped_callback stopped)
+ : validate_block(height, block, testnet, checks, stopped),
+ chain_(chain),
+ height_(height),
+ fork_index_(fork_index),
+ orphan_index_(orphan_index),
+ orphan_chain_(orphan_chain)
{
}
bool validate_block_impl::is_valid_proof_of_work(const chain::header& header) const
{
chain::header parent_header;
- if(orphan_index_ != 0) {
+ if (orphan_index_ != 0) {
parent_header = orphan_chain_[orphan_index_ - 1]->actual()->header;
- }else{
- static_cast(chain_).get_header(parent_header, header.number - 1);
+ }
+ else {
+ static_cast(chain_).get_header(parent_header, header.number - 1);
}
return MinerAux::verifySeal(const_cast(header), parent_header);
}
@@ -93,8 +94,7 @@ uint64_t validate_block_impl::actual_time_span(size_t interval) const
BITCOIN_ASSERT(height_ > 0 && height_ >= interval);
// height - interval and height - 1, return time difference
- return fetch_block(height_ - 1).timestamp -
- fetch_block(height_ - interval).timestamp;
+ return fetch_block(height_ - 1).timestamp - fetch_block(height_ - interval).timestamp;
}
uint64_t validate_block_impl::median_time_past() const
@@ -113,8 +113,7 @@ uint64_t validate_block_impl::median_time_past() const
chain::header validate_block_impl::fetch_block(size_t fetch_height) const
{
- if (fetch_height > fork_index_)
- {
+ if (fetch_height > fork_index_) {
const auto fetch_index = fetch_height - fork_index_ - 1;
BITCOIN_ASSERT(fetch_index <= orphan_index_);
BITCOIN_ASSERT(orphan_index_ < orphan_chain_.size());
@@ -122,7 +121,7 @@ chain::header validate_block_impl::fetch_block(size_t fetch_height) const
}
chain::header out;
- DEBUG_ONLY(const auto result =) chain_.get_header(out, fetch_height);
+ DEBUG_ONLY(const auto result = ) chain_.get_header(out, fetch_height);
BITCOIN_ASSERT(result);
return out;
}
@@ -158,7 +157,7 @@ bool validate_block_impl::is_output_spent(
}
bool validate_block_impl::fetch_transaction(chain::transaction& tx,
- size_t& tx_height, const hash_digest& tx_hash) const
+ size_t& tx_height, const hash_digest& tx_hash) const
{
uint64_t out_height;
const auto result = chain_.get_transaction(tx, out_height, tx_hash);
@@ -166,23 +165,20 @@ bool validate_block_impl::fetch_transaction(chain::transaction& tx,
BITCOIN_ASSERT(out_height <= max_size_t);
tx_height = static_cast(out_height);
- if (!result || tx_after_fork(tx_height, fork_index_))
+ if (!result || tx_after_fork(tx_height, fork_index_)) {
return fetch_orphan_transaction(tx, tx_height, tx_hash);
+ }
return true;
}
bool validate_block_impl::fetch_orphan_transaction(chain::transaction& tx,
- size_t& tx_height, const hash_digest& tx_hash) const
+ size_t& tx_height, const hash_digest& tx_hash) const
{
- for (size_t orphan = 0; orphan <= orphan_index_; ++orphan)
- {
+ for (size_t orphan = 0; orphan <= orphan_index_; ++orphan) {
const auto& orphan_block = orphan_chain_[orphan]->actual();
-
- for (const auto& orphan_tx: orphan_block->transactions)
- {
- if (orphan_tx.hash() == tx_hash)
- {
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ if (orphan_tx.hash() == tx_hash) {
// TRANSACTION COPY
tx = orphan_tx;
tx_height = fork_index_ + orphan + 1;
@@ -194,6 +190,165 @@ bool validate_block_impl::fetch_orphan_transaction(chain::transaction& tx,
return false;
}
+std::string validate_block_impl::get_did_from_address_consider_orphan_chain(
+ const std::string& address, const std::string& did_symbol) const
+{
+ BITCOIN_ASSERT(!address.empty());
+
+ if (address.empty()) {
+ log::debug("blockchain") << "get_did_from_address_consider_orphan_chain: address is empty";
+ return "";
+ }
+
+ auto orphan = orphan_index_;
+ while (orphan > 0) {
+ const auto& orphan_block = orphan_chain_[--orphan]->actual();
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ // iter outputs
+ for (const auto& output : orphan_tx.outputs) {
+ if (output.is_did_register() || output.is_did_transfer()) {
+ if (address == output.get_did_address()) {
+ return output.get_did_symbol();
+ }
+ }
+ }
+
+ // iter inputs
+ for (const auto& input : orphan_tx.inputs) {
+ size_t previous_height;
+ transaction previous_tx;
+ const auto& previous_output = input.previous_output;
+
+ // This searches the blockchain and then the orphan pool up to and
+ // including the current (orphan) block and excluding blocks above fork.
+ if (!fetch_transaction(previous_tx, previous_height, previous_output.hash))
+ {
+ log::warning(LOG_BLOCKCHAIN)
+ << "Failure fetching input transaction ["
+ << encode_hash(previous_output.hash) << "]";
+ return "";
+ }
+
+ const auto& previous_tx_out = previous_tx.outputs[previous_output.index];
+
+ if (previous_tx_out.is_did_register() || previous_tx_out.is_did_transfer()) {
+ if (address == previous_tx_out.get_did_address()) {
+ return "";
+ }
+ }
+ }
+ }
+ }
+
+ return did_symbol;
+}
+
+bool validate_block_impl::is_did_match_address_in_orphan_chain(const std::string& did, const std::string& address) const
+{
+ BITCOIN_ASSERT(!did.empty());
+ BITCOIN_ASSERT(!address.empty());
+
+ if (address.empty()) {
+ log::debug("blockchain") << "check did match address in orphan chain: address is null for did: " << did;
+ return false;
+ }
+
+ auto orphan = orphan_index_;
+ while (orphan > 0) {
+ const auto& orphan_block = orphan_chain_[--orphan]->actual();
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ for (auto& output : orphan_tx.outputs) {
+ if (output.is_did_register() || output.is_did_transfer()) {
+ if (did == output.get_did_symbol()) {
+ return address == output.get_did_address();
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool validate_block_impl::is_did_in_orphan_chain(const std::string& did) const
+{
+ BITCOIN_ASSERT(!did.empty());
+
+ for (size_t orphan = 0; orphan < orphan_index_; ++orphan) {
+ const auto& orphan_block = orphan_chain_[orphan]->actual();
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ for (auto& output : orphan_tx.outputs) {
+ if (output.is_did_register()) {
+ if (did == output.get_did_symbol()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool validate_block_impl::is_asset_in_orphan_chain(const std::string& symbol) const
+{
+ BITCOIN_ASSERT(!symbol.empty());
+
+ for (size_t orphan = 0; orphan < orphan_index_; ++orphan) {
+ const auto& orphan_block = orphan_chain_[orphan]->actual();
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ for (const auto& output : orphan_tx.outputs) {
+ if (output.is_asset_issue()) {
+ if (symbol == output.get_asset_symbol()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool validate_block_impl::is_asset_cert_in_orphan_chain(const std::string& symbol, asset_cert_type cert_type) const
+{
+ BITCOIN_ASSERT(!symbol.empty());
+
+ for (size_t orphan = 0; orphan < orphan_index_; ++orphan) {
+ const auto& orphan_block = orphan_chain_[orphan]->actual();
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ for (const auto& output : orphan_tx.outputs) {
+ if (symbol == output.get_asset_cert_symbol() &&
+ cert_type == output.get_asset_cert_type()) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool validate_block_impl::is_asset_mit_in_orphan_chain(const std::string& symbol) const
+{
+ BITCOIN_ASSERT(!symbol.empty());
+
+ for (size_t orphan = 0; orphan < orphan_index_; ++orphan) {
+ const auto& orphan_block = orphan_chain_[orphan]->actual();
+ for (const auto& orphan_tx : orphan_block->transactions) {
+ for (const auto& output : orphan_tx.outputs) {
+ if (output.is_asset_mit_register()) {
+ if (symbol == output.get_asset_mit_symbol()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
bool validate_block_impl::is_output_spent(
const chain::output_point& previous_output,
size_t index_in_parent, size_t input_index) const
@@ -214,27 +369,21 @@ bool validate_block_impl::orphan_is_spent(
const chain::output_point& previous_output,
size_t skip_tx, size_t skip_input) const
{
- for (size_t orphan = 0; orphan <= orphan_index_; ++orphan)
- {
+ for (size_t orphan = 0; orphan <= orphan_index_; ++orphan) {
const auto& orphan_block = orphan_chain_[orphan]->actual();
const auto& transactions = orphan_block->transactions;
BITCOIN_ASSERT(!transactions.empty());
BITCOIN_ASSERT(transactions.front().is_coinbase());
- for (size_t tx_index = 0; tx_index < transactions.size();
- ++tx_index)
- {
+ for (size_t tx_index = 0; tx_index < transactions.size(); ++tx_index) {
// TODO: too deep, move this section to subfunction.
const auto& orphan_tx = transactions[tx_index];
- for (size_t input_index = 0; input_index < orphan_tx.inputs.size();
- ++input_index)
- {
+ for (size_t input_index = 0; input_index < orphan_tx.inputs.size(); ++input_index) {
const auto& orphan_input = orphan_tx.inputs[input_index];
- if (orphan == orphan_index_ && tx_index == skip_tx &&
- input_index == skip_input)
+ if (orphan == orphan_index_ && tx_index == skip_tx && input_index == skip_input)
continue;
if (orphan_input.previous_output == previous_output)
@@ -254,11 +403,12 @@ bool validate_block_impl::check_get_coinage_reward_transaction(const chain::tran
wallet::payment_address addr2 = wallet::payment_address::extract(output.script);
uint64_t coinage_reward_value = libbitcoin::consensus::miner::calculate_lockblock_reward(lock_height, output.value);
- if(addr1 == addr2
- && lock_height == coinbase_lock_height
- && coinage_reward_value == coinage_reward_coinbase.outputs[0].value) {
+ if (addr1 == addr2
+ && lock_height == coinbase_lock_height
+ && coinage_reward_value == coinage_reward_coinbase.outputs[0].value) {
return true;
- } else {
+ }
+ else {
return false;
}
}
diff --git a/src/lib/blockchain/validate_transaction.cpp b/src/lib/blockchain/validate_transaction.cpp
index ea6c22778..690167f0b 100644
--- a/src/lib/blockchain/validate_transaction.cpp
+++ b/src/lib/blockchain/validate_transaction.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -316,7 +317,7 @@ code validate_transaction::check_tx_connect_input() const
{
uint64_t fee = 0;
- if (!tally_fees(*tx_, value_in_, fee)) {
+ if (!tally_fees(blockchain_, *tx_, value_in_, fee)) {
return error::fees_out_of_range;
}
@@ -559,7 +560,7 @@ code validate_transaction::check_asset_issue_transaction() const
if (!check_same(asset_address, detail.get_address())) {
return error::asset_issue_error;
}
- if (chain.is_asset_exist(asset_symbol, false)) {
+ if (check_asset_exist(asset_symbol)) {
return error::asset_exist;
}
if (operation::is_pay_key_hash_with_attenuation_model_pattern(output.script.operations)) {
@@ -710,7 +711,7 @@ code validate_transaction::check_asset_cert_transaction() const
}
// check cert not exists
- if (chain.is_asset_cert_exist(cert_symbol, cur_cert_type)) {
+ if (check_asset_cert_exist(cert_symbol, cur_cert_type)) {
log::debug(LOG_BLOCKCHAIN) << "issue cert: "
<< cert_info.get_symbol() << " already exists.";
return error::asset_cert_exist;
@@ -731,14 +732,6 @@ code validate_transaction::check_asset_cert_transaction() const
<< cert_info.get_symbol() << " does not match.";
return error::asset_cert_error;
}
-
- // check cert exists
- auto cur_cert_type = cert_info.get_type();
- if (!chain.is_asset_cert_exist(cert_symbol, cur_cert_type)) {
- log::debug(LOG_BLOCKCHAIN) << "transfer cert: "
- << cert_info.get_symbol() << " not exists.";
- return error::asset_cert_not_exist;
- }
}
else if (output.is_asset_cert()) {
asset_cert&& cert_info = output.get_asset_cert();
@@ -818,7 +811,7 @@ code validate_transaction::check_asset_cert_transaction() const
}
// check asset not exist.
- if (chain.is_asset_exist(cert_symbol, false)) {
+ if (check_asset_exist(cert_symbol)) {
log::debug(LOG_BLOCKCHAIN) << "issue cert: "
<< "asset symbol '" + cert_symbol + "' already exists in blockchain!";
return error::asset_exist;
@@ -866,7 +859,7 @@ code validate_transaction::check_asset_mit_transaction() const
}
// check asset not exists
- if (nullptr != chain.get_registered_mit(asset_symbol)) {
+ if (check_asset_mit_exist(asset_symbol)) {
log::debug(LOG_BLOCKCHAIN) << "register MIT: "
<< asset_symbol << " already exists.";
return error::mit_exist;
@@ -880,13 +873,6 @@ code validate_transaction::check_asset_mit_transaction() const
auto&& asset_info = output.get_asset_mit();
asset_symbol = asset_info.get_symbol();
-
- // check asset exists
- if (nullptr == chain.get_registered_mit(asset_symbol)) {
- log::debug(LOG_BLOCKCHAIN) << "transfer MIT: "
- << asset_symbol << " not exists.";
- return error::mit_not_exist;
- }
}
else if (output.is_etp()) {
if (!check_same(asset_address, output.get_script_address())) {
@@ -949,10 +935,96 @@ code validate_transaction::check_asset_mit_transaction() const
return error::success;
}
+bool validate_transaction::check_did_exist(const std::string& did) const
+{
+ uint64_t height = blockchain_.get_did_height(did);
+
+ if (validate_block_ ) {
+ //register before fork or find in orphan chain
+ if (height <= validate_block_->get_fork_index() || validate_block_->is_did_in_orphan_chain(did)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return height != max_uint64;
+}
+
+bool validate_transaction::check_asset_exist(const std::string& symbol) const
+{
+ uint64_t height = blockchain_.get_asset_height(symbol);
+
+ if (validate_block_) {
+ //register before fork or find in orphan chain
+ if (height <= validate_block_->get_fork_index() || validate_block_->is_asset_in_orphan_chain(symbol)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return height != max_uint64;
+}
+
+bool validate_transaction::check_asset_cert_exist(const std::string& cert, asset_cert_type cert_type) const
+{
+ uint64_t height = blockchain_.get_asset_cert_height(cert, cert_type);
+
+ if (validate_block_) {
+ //register before fork or find in orphan chain
+ if (height <= validate_block_->get_fork_index() || validate_block_->is_asset_cert_in_orphan_chain(cert, cert_type)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return height != max_uint64;
+}
+
+bool validate_transaction::check_asset_mit_exist(const std::string& mit) const
+{
+ uint64_t height = blockchain_.get_asset_mit_height(mit);
+
+ if (validate_block_) {
+ //register before fork or find in orphan chain
+ if (height <= validate_block_->get_fork_index() || validate_block_->is_asset_mit_in_orphan_chain(mit)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return height != max_uint64;
+}
+
+bool validate_transaction::check_address_registered_did(const std::string& address) const
+{
+ uint64_t fork_index = validate_block_ ? validate_block_->get_fork_index() : max_uint64;
+ auto did_symbol = blockchain_.get_did_from_address(address, fork_index);
+
+ if (!validate_block_) {
+ if (did_symbol.empty()) {
+ return false;
+ }
+ }
+ else {
+ did_symbol = validate_block_->get_did_from_address_consider_orphan_chain(address, did_symbol);
+ if (did_symbol.empty()) {
+ return false;
+ }
+ }
+
+ log::debug(LOG_BLOCKCHAIN) << "address " << address << " already exists did " << did_symbol;
+ return true;
+}
+
code validate_transaction::check_did_transaction() const
{
const chain::transaction& tx = *tx_;
blockchain::block_chain_impl& chain = blockchain_;
+ uint64_t fork_index = validate_block_ ? validate_block_->get_fork_index() : max_uint64;
code ret = error::success;
@@ -964,11 +1036,11 @@ code validate_transaction::check_did_transaction() const
return ret;
//to_did check(strong check)
- if ((ret = output.check_attachment_did_match_address(chain)) != error::success)
+ if ((ret = check_attachment_to_did(output)) != error::success)
return ret;
//from_did (weak check)
- if ((ret = connect_input_address_match_did(output)) != error::success) {
+ if ((ret = connect_attachment_from_did(output)) != error::success) {
return ret;
}
@@ -977,11 +1049,15 @@ code validate_transaction::check_did_transaction() const
return error::did_symbol_invalid;
}
- if (chain.is_did_exist(output.get_did_symbol())) {
+ if (check_did_exist(output.get_did_symbol())) {
+ log::debug(LOG_BLOCKCHAIN) << "did_register: "
+ << output.get_did_symbol() << " already exists";
return error::did_exist;
}
- if (chain.is_address_registered_did(output.get_did_address())) {
+ if (check_address_registered_did(output.get_did_address())) {
+ log::debug(LOG_BLOCKCHAIN) << "address "
+ << output.get_did_address() << " already exists did, cannot register did.";
return error::address_registered_did;
}
@@ -995,12 +1071,9 @@ code validate_transaction::check_did_transaction() const
}
}
else if (output.is_did_transfer()) {
- //did transfer only for did is exist
- if (!chain.is_did_exist(output.get_did_symbol())) {
- return error::did_not_exist;
- }
-
- if (chain.is_address_registered_did(output.get_did_address())) {
+ if (check_address_registered_did(output.get_did_address())) {
+ log::debug(LOG_BLOCKCHAIN) << "address "
+ << output.get_did_address() << " already exists did, cannot transfer did.";
return error::address_registered_did;
}
@@ -1082,35 +1155,83 @@ bool validate_transaction::connect_did_input(const did& info) const
|| (found_address_info && info.get_status() == DID_DETAIL_TYPE);
}
-code validate_transaction::connect_input_address_match_did(const output& output) const
+bool validate_transaction::is_did_match_address_in_orphan_chain(const std::string& did, const std::string& address) const
{
- const chain::transaction& tx = *tx_;
- blockchain::block_chain_impl& chain = blockchain_;
+ if (validate_block_ && validate_block_->is_did_match_address_in_orphan_chain(did, address)) {
+ log::debug(LOG_BLOCKCHAIN) << "did_in_orphan_chain: "
+ << did << ", match address: " << address;
+ return true;
+ }
- const attachment& attach = output.attach_data;
+ return false;
+}
+
+bool validate_transaction::is_did_in_orphan_chain(const std::string& did) const
+{
+ if (validate_block_ && validate_block_->is_did_in_orphan_chain(did)) {
+ log::debug(LOG_BLOCKCHAIN) << "did_in_orphan_chain: " << did << " exist";
+ return true;
+ }
+
+ return false;
+}
- if (attach.get_from_did().empty()) {
+code validate_transaction::check_attachment_to_did(const output& output) const
+{
+ auto todid = output.attach_data.get_to_did();
+ if (todid.empty()) {
return error::success;
}
- for ( auto & input : tx.inputs)
- {
+ auto address = output.get_script_address();
+
+ if (is_did_match_address_in_orphan_chain(todid, address)) {
+ return error::success;
+ }
+
+ uint64_t fork_index = validate_block_ ? validate_block_->get_fork_index() : max_uint64;
+ auto did = blockchain_.get_did_from_address(address, fork_index);
+ if (todid == did) {
+ return error::success;
+ }
+
+ log::debug(LOG_BLOCKCHAIN) << "check_attachment_to_did: "
+ << todid << ", address: " << address
+ << "; get did from address is " << did;
+ return error::did_address_not_match;
+}
+
+code validate_transaction::connect_attachment_from_did(const output& output) const
+{
+ auto from_did = output.attach_data.get_from_did();
+ if (from_did.empty()) {
+ return error::success;
+ }
+
+ for (auto& input : tx_->inputs) {
chain::transaction prev_tx;
uint64_t prev_height{0};
if (!get_previous_tx(prev_tx, prev_height, input)) {
- log::debug(LOG_BLOCKCHAIN) << "connect_input_address_match_did: input not found: "
+ log::debug(LOG_BLOCKCHAIN) << "connect_attachment_from_did: input not found: "
<< encode_hash(input.previous_output.hash);
return error::input_not_found;
}
auto prev_output = prev_tx.outputs.at(input.previous_output.index);
auto address = prev_output.get_script_address();
- if (attach.get_from_did() == chain.get_did_from_address(address)) {
+
+ if (is_did_match_address_in_orphan_chain(from_did, address)) {
return error::success;
}
- }
+ uint64_t fork_index = validate_block_ ? validate_block_->get_fork_index() : max_uint64;
+ if (from_did == blockchain_.get_did_from_address(address, fork_index)) {
+ return error::success;
+ }
+ }
+ log::debug(LOG_BLOCKCHAIN) << "connect_attachment_from_did: input not found for from_did: "
+ << from_did;
return error::did_address_not_match;
}
@@ -1231,7 +1352,7 @@ code validate_transaction::check_transaction_basic() const
}
else if (output.is_asset_cert()) {
auto&& asset_cert = output.get_asset_cert();
- if (!chain.is_did_exist(asset_cert.get_owner())) {
+ if (!check_did_exist(asset_cert.get_owner())) {
return error::did_address_needed;
}
}
@@ -1426,8 +1547,81 @@ bool validate_transaction::connect_input( const transaction& previous_tx, size_t
return value_in_ <= max_money();
}
-bool validate_transaction::tally_fees(const transaction& tx, uint64_t value_in,
- uint64_t& total_fees)
+bool validate_transaction::check_special_fees(bool is_testnet, const chain::transaction& tx, uint64_t fee)
+{
+ // check fee of issue asset or register did
+ auto developer_community_address = bc::get_developer_community_address(is_testnet);
+ std::vector etp_vec;
+ uint32_t special_fee_type = 0;
+ std::string to_address;
+ for (auto& output: tx.outputs) {
+ if (output.is_etp()) {
+ if (output.get_script_address() == developer_community_address) {
+ etp_vec.push_back(output.value);
+ }
+ else {
+ etp_vec.push_back(0);
+ }
+ }
+ else if (output.is_asset_issue()) {
+ special_fee_type = 1;
+ to_address = output.get_script_address();
+ }
+ else if (output.is_did_register()) {
+ special_fee_type = 2;
+ to_address = output.get_script_address();
+ }
+ }
+
+ // skip transaction to developer community address
+ if (special_fee_type > 0 && to_address != developer_community_address) {
+ uint64_t fee_to_developer = std::accumulate(etp_vec.begin() , etp_vec.end(), (uint64_t)0);
+ if (fee_to_developer > 0) {
+ uint64_t total_fee = fee + fee_to_developer;
+ uint32_t percentage_to_miner = (uint32_t)std::ceil((fee * 100.0) / total_fee);
+
+ bool result = false;
+ if (special_fee_type == 1) {
+ result = (total_fee >= bc::min_fee_to_issue_asset
+ && percentage_to_miner >= min_fee_percentage_to_miner);
+
+ }
+ else if (special_fee_type == 2) {
+ result = (total_fee >= bc::min_fee_to_register_did
+ && percentage_to_miner >= min_fee_percentage_to_miner);
+ }
+
+ if (!result) {
+ log::debug(LOG_BLOCKCHAIN) << "check fees failed: "
+ << (special_fee_type == 1 ? "issue asset" : "register did")
+ << ", total_fee: " << std::to_string(total_fee)
+ << ", fee_percentage_to_miner: " << std::to_string(percentage_to_miner);
+ return false;
+ }
+ }
+ else {
+ if (special_fee_type == 1) {
+ if (fee < bc::min_fee_to_issue_asset) {
+ log::debug(LOG_BLOCKCHAIN) << "check fees failed: fee for issuing asset less than "
+ << std::to_string(bc::min_fee_to_issue_asset);
+ return false;
+ }
+ }
+ else if (special_fee_type == 2) {
+ if (fee < bc::min_fee_to_register_did) {
+ log::debug(LOG_BLOCKCHAIN) << "check fees failed: fee for registerring did less than "
+ << std::to_string(bc::min_fee_to_register_did);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool validate_transaction::tally_fees(blockchain::block_chain_impl& chain,
+ const transaction& tx, uint64_t value_in, uint64_t& total_fees)
{
const auto value_out = tx.total_output_value();
@@ -1435,8 +1629,10 @@ bool validate_transaction::tally_fees(const transaction& tx, uint64_t value_in,
return false;
const auto fee = value_in - value_out;
- if (fee < min_tx_fee)
+ if (fee < min_tx_fee) {
return false;
+ }
+
total_fees += fee;
return total_fees <= max_money();
}
diff --git a/src/lib/consensus/miner.cpp b/src/lib/consensus/miner.cpp
index 2cb83272e..e4eeac206 100644
--- a/src/lib/consensus/miner.cpp
+++ b/src/lib/consensus/miner.cpp
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#define LOG_HEADER "consensus"
using namespace std;
@@ -82,7 +83,7 @@ miner::~miner()
}
bool miner::get_input_etp(const transaction& tx, const std::vector& transactions,
- uint64_t& total_inputs, previous_out_map_t& previous_out_map) const
+ uint64_t& total_inputs, previous_out_map_t& previous_out_map) const
{
total_inputs = 0;
block_chain_impl& block_chain = node_.chain_impl();
@@ -122,7 +123,7 @@ bool miner::get_input_etp(const transaction& tx, const std::vector& transactions,
- previous_out_map_t& previous_out_map, tx_fee_map_t& tx_fee_map) const
+ previous_out_map_t& previous_out_map, tx_fee_map_t& tx_fee_map) const
{
boost::mutex mutex;
mutex.lock();
@@ -140,13 +141,30 @@ bool miner::get_transaction(std::vector& transactions,
for (auto i = transactions.begin(); i != transactions.end(); ) {
auto& tx = **i;
auto hash = tx.hash();
- auto transaction_is_ok = true;
- uint64_t fee = 0;
+ uint64_t total_input_value = 0;
+ bool ready = get_input_etp(tx, transactions, total_input_value, previous_out_map);
+ if (!ready) {
+ // erase tx but not delete it from pool if parent tx is not ready
+ i = transactions.erase(i);
+ break;
+ }
+ uint64_t total_output_value = tx.total_output_value();
+ uint64_t fee = total_input_value - total_output_value;
+
+ // check fees
+ if (fee < min_tx_fee || !blockchain::validate_transaction::check_special_fees(setting_.use_testnet_rules, tx, fee)) {
+ i = transactions.erase(i);
+ // delete it from pool if not enough fee
+ node_.pool().delete_tx(hash);
+ break;
+ }
+
+ auto transaction_is_ok = true;
for (auto& output : tx.outputs) {
if (tx.version >= transaction_version::check_output_script
- && output.script.pattern() == script_pattern::non_standard) {
+ && output.script.pattern() == script_pattern::non_standard) {
#ifdef MVS_DEBUG
log::error(LOG_HEADER) << "transaction output script error! tx:" << tx.to_string(1);
#endif
@@ -154,43 +172,6 @@ bool miner::get_transaction(std::vector& transactions,
transaction_is_ok = false;
break;
}
-
- uint64_t total_input_value = 0;
- bool ready = get_input_etp(tx, transactions, total_input_value, previous_out_map);
- if (!ready) {
- // erase tx but not delete it from pool if parent tx is not ready
- transaction_is_ok = false;
- break;
- }
-
- uint64_t total_output_value = tx.total_output_value();
-
- // check normal fee
- if (total_input_value < total_output_value + min_tx_fee) {
- transaction_is_ok = false;
- }
- else {
- fee = total_input_value - total_output_value;
- // check fee for issue asset
- if (output.is_asset_issue() && fee < coin_price(10)) {
- transaction_is_ok = false;
- }
- // check fee for issue did
- else if (output.is_did_register() && fee < coin_price(1)) {
- transaction_is_ok = false;
- }
- }
-
- if (!transaction_is_ok) {
-#ifdef MVS_DEBUG
- log::debug(LOG_HEADER) << "not enough fee! input: "
- << total_input_value << ", output: " << total_output_value
- << ", tx: " << tx.to_string(1);
-#endif
- // delete ifrom pool if not enough fee
- node_.pool().delete_tx(hash);
- break;
- }
}
if (transaction_is_ok && (sets.find(hash) == sets.end())) {
diff --git a/src/lib/database/data_base.cpp b/src/lib/database/data_base.cpp
index 2abd25fb9..b508cf1f8 100644
--- a/src/lib/database/data_base.cpp
+++ b/src/lib/database/data_base.cpp
@@ -813,12 +813,12 @@ void data_base::push(const block& block, uint64_t height)
if (!tx.is_coinbase())
push_inputs(tx_hash, height, tx.inputs);
- std::string didaddress = tx.get_did_transfer_old_address();
- if (!didaddress.empty()) {
- data_chunk data(didaddress.begin(), didaddress.end());
- short_hash key = ripemd160_hash(data);
- address_dids.delete_old_did(key);
- }
+ // std::string didaddress = tx.get_did_transfer_old_address();
+ // if (!didaddress.empty()) {
+ // data_chunk data(didaddress.begin(), didaddress.end());
+ // short_hash key = ripemd160_hash(data);
+ // address_dids.delete_old_did(key);
+ // }
// Add outputs
push_outputs(tx_hash, height, tx.outputs);
diff --git a/src/lib/database/databases/address_asset_database.cpp b/src/lib/database/databases/address_asset_database.cpp
index bf761c1a2..00482d95c 100644
--- a/src/lib/database/databases/address_asset_database.cpp
+++ b/src/lib/database/databases/address_asset_database.cpp
@@ -778,6 +778,41 @@ business_address_asset_cert::list address_asset_database::get_asset_certs(const
return unspent;
}
+
+business_history::list address_asset_database::get_asset_certs_history(const std::string& address,
+ const std::string& symbol, asset_cert_type cert_type,
+ size_t from_height) const
+{
+ data_chunk data(address.begin(), address.end());
+ auto key = ripemd160_hash(data);
+ business_history::list result = get_business_history(key, from_height);
+ business_history::list unspent(result.size());
+
+ auto it = std::copy_if(result.begin(), result.end(), unspent.begin(), [&symbol,&cert_type](business_history & row)
+ {
+ if ((row.data.get_kind_value() != business_kind::asset_cert)) // asset_cert
+ return false;
+
+ auto cert_info = boost::get(row.data.get_data());
+ if (!symbol.empty()) {
+ if (symbol != cert_info.get_symbol()) {
+ return false;
+ }
+ }
+
+ if (cert_type != asset_cert_ns::none) {
+ if (cert_type != cert_info.get_type()) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ unspent.resize(std::distance(unspent.begin(),it));
+ return unspent;
+}
+
+
void address_asset_database::sync()
{
lookup_manager_.sync();
diff --git a/src/lib/database/databases/address_did_database.cpp b/src/lib/database/databases/address_did_database.cpp
index f2f1698c5..8fa588a6f 100644
--- a/src/lib/database/databases/address_did_database.cpp
+++ b/src/lib/database/databases/address_did_database.cpp
@@ -673,7 +673,7 @@ business_address_did::list address_did_database::get_dids(const std::string& add
// get all kinds of did in the database(blockchain)
business_address_did::list address_did_database::get_dids(const std::string& address,
- size_t from_height) const
+ size_t from_height, size_t to_height) const
{
data_chunk data(address.begin(), address.end());
auto key = ripemd160_hash(data);
@@ -685,6 +685,13 @@ business_address_did::list address_did_database::get_dids(const std::string& add
&& (row.data.get_kind_value() != business_kind::did_transfer)) // did_transfer
continue;
+ if(address != wallet::payment_address::blackhole_address)
+ {
+ if (row.output_height > to_height) {
+ continue;
+ }
+ }
+
uint8_t status = 0xff;
if (row.spend.hash == null_hash)
status = 0; // 0 -- unspent 1 -- confirmed
diff --git a/src/lib/database/databases/blockchain_asset_cert_database.cpp b/src/lib/database/databases/blockchain_asset_cert_database.cpp
index 7902624c0..0c8b53f43 100644
--- a/src/lib/database/databases/blockchain_asset_cert_database.cpp
+++ b/src/lib/database/databases/blockchain_asset_cert_database.cpp
@@ -145,6 +145,7 @@ std::shared_ptr> blockchain_asset_cert_database::get_blo
return vec_acc;
}
+
void blockchain_asset_cert_database::store(const asset_cert& sp_cert)
{
auto&& key_str = sp_cert.get_key();
diff --git a/src/lib/database/databases/blockchain_asset_database.cpp b/src/lib/database/databases/blockchain_asset_database.cpp
index 3c6e36b3a..69173bb07 100644
--- a/src/lib/database/databases/blockchain_asset_database.cpp
+++ b/src/lib/database/databases/blockchain_asset_database.cpp
@@ -165,6 +165,34 @@ std::shared_ptr> blockchain_asset_database::get_bl
return vec_acc;
}
+///
+std::shared_ptr blockchain_asset_database::get_register_history(const std::string & asset_symbol) const
+{
+ std::shared_ptr blockchain_asset_ = nullptr;
+ data_chunk data(asset_symbol.begin(), asset_symbol.end());
+ auto key = sha256_hash(data);
+
+ auto memo = lookup_map_.rfind(key);
+ if(memo)
+ {
+ blockchain_asset_ = std::make_shared();
+ const auto memory = REMAP_ADDRESS(memo);
+ auto deserial = make_deserializer_unsafe(memory);
+ blockchain_asset_->from_data(deserial);
+ }
+
+ return blockchain_asset_;
+}
+
+///
+uint64_t blockchain_asset_database::get_register_height(const std::string & asset_symbol) const
+{
+ std::shared_ptr blockchain_asset_ = get_register_history(asset_symbol);
+ if(blockchain_asset_)
+ return blockchain_asset_->get_height();
+ return max_uint64;
+}
+
void blockchain_asset_database::store(const hash_digest& hash, const blockchain_asset& sp_detail)
{
// Write block data.
diff --git a/src/lib/database/databases/blockchain_did_database.cpp b/src/lib/database/databases/blockchain_did_database.cpp
index 92790b6f3..877e7b4cb 100644
--- a/src/lib/database/databases/blockchain_did_database.cpp
+++ b/src/lib/database/databases/blockchain_did_database.cpp
@@ -131,8 +131,6 @@ std::shared_ptr blockchain_did_database::get(const hash_digest&
std::shared_ptr> blockchain_did_database::get_history_dids(const hash_digest &hash) const
{
auto did_details = std::make_shared>();
- if (!did_details)
- return nullptr;
const auto raw_memory_vec = lookup_map_.finds(hash);
for(const auto& raw_memory : raw_memory_vec) {
@@ -169,6 +167,35 @@ std::shared_ptr> blockchain_did_database::get_blockc
return vec_acc;
}
+///
+std::shared_ptr blockchain_did_database::get_register_history(const std::string & did_symbol) const
+{
+ std::shared_ptr blockchain_did_ = nullptr;
+ data_chunk data(did_symbol.begin(), did_symbol.end());
+ auto key = sha256_hash(data);
+
+ auto memo = lookup_map_.rfind(key);
+ if(memo)
+ {
+ blockchain_did_ = std::make_shared();
+ const auto memory = REMAP_ADDRESS(memo);
+ auto deserial = make_deserializer_unsafe(memory);
+ blockchain_did_->from_data(deserial);
+ }
+
+ return blockchain_did_;
+}
+
+ uint64_t blockchain_did_database::get_register_height(const std::string & did_symbol) const
+ {
+ std::shared_ptr blockchain_did_ = get_register_history(did_symbol);
+ if(blockchain_did_)
+ return blockchain_did_->get_height();
+
+ return max_uint64;
+ }
+
+
void blockchain_did_database::store(const hash_digest& hash, const blockchain_did& sp_detail)
{
// Write block data.
@@ -219,6 +246,39 @@ std::shared_ptr blockchain_did_database::update_address_status(c
return detail;
}
+std::shared_ptr > blockchain_did_database::getdids_from_address_history(const std::string &address,
+ const uint64_t &fromheight, const uint64_t &toheight) const
+{
+ auto vec_acc = std::make_shared>();
+ uint64_t i = 0;
+ for( i = 0; i < number_buckets; i++ ) {
+ auto sp_memo = lookup_map_.find(i);
+ for(auto& elem : *sp_memo)
+ {
+ const auto memory = REMAP_ADDRESS(elem);
+ auto deserial = make_deserializer_unsafe(memory);
+ blockchain_did blockchain_did_ = blockchain_did::factory_from_data(deserial);
+
+ const auto height = blockchain_did_.get_height();
+ const auto did_address = blockchain_did_.get_did().get_address();
+
+ if (did_address == address) {
+ if((height >= fromheight && height <= toheight)
+ || (height == max_uint32 && address == wallet::payment_address::blackhole_address)) {
+ vec_acc->emplace_back(blockchain_did_);
+ }
+ }
+ }
+ }
+
+ std::sort(vec_acc->begin(), vec_acc->end(), []( blockchain_did & first, blockchain_did & second)
+ {
+ return first.get_height() < second.get_height();
+ });
+ return vec_acc;
+
+}
+
std::shared_ptr blockchain_did_database::pop_did_transfer(const hash_digest &hash)
{
lookup_map_.unlink(hash);
diff --git a/src/lib/database/databases/blockchain_mit_database.cpp b/src/lib/database/databases/blockchain_mit_database.cpp
index f6eca3961..588d3459e 100644
--- a/src/lib/database/databases/blockchain_mit_database.cpp
+++ b/src/lib/database/databases/blockchain_mit_database.cpp
@@ -143,6 +143,35 @@ std::shared_ptr blockchain_mit_database::get_blockchain_mi
return vec_acc;
}
+///
+std::shared_ptr blockchain_mit_database::get_register_history(const std::string & mit_symbol) const
+{
+ std::shared_ptr asset_mit_ = nullptr;
+ data_chunk data(mit_symbol.begin(), mit_symbol.end());
+ auto key = sha256_hash(data);
+
+ auto memo = lookup_map_.rfind(key);
+ if(memo)
+ {
+ asset_mit_ = std::make_shared();
+ const auto memory = REMAP_ADDRESS(memo);
+ auto deserial = make_deserializer_unsafe(memory);
+ *asset_mit_ = asset_mit_info::factory_from_data(deserial);
+ }
+
+ return asset_mit_;
+}
+
+///
+uint64_t blockchain_mit_database::get_register_height(const std::string & mit_symbol) const
+{
+ std::shared_ptr asset_mit_ = get_register_history(mit_symbol);
+ if(asset_mit_)
+ return asset_mit_->output_height;
+
+ return max_uint64;
+}
+
void blockchain_mit_database::store(const asset_mit_info& mit_info)
{
const auto& key_str = mit_info.mit.get_symbol();
diff --git a/src/lib/explorer/extensions/base_helper.cpp b/src/lib/explorer/extensions/base_helper.cpp
index fd222b528..c0303b460 100644
--- a/src/lib/explorer/extensions/base_helper.cpp
+++ b/src/lib/explorer/extensions/base_helper.cpp
@@ -256,10 +256,75 @@ void sync_fetch_asset_balance(const std::string& address, bool sum_all,
}
}
+static uint32_t get_domain_cert_count(bc::blockchain::block_chain_impl& blockchain,
+ const std::string& account_name)
+{
+ auto pvaddr = blockchain.get_account_addresses(account_name);
+ if (!pvaddr) {
+ return 0;
+ }
+
+ auto sh_vec = std::make_shared();
+ for (auto& each : *pvaddr){
+ sync_fetch_asset_cert_balance(each.get_address(), "", blockchain, sh_vec, asset_cert_ns::domain);
+ }
+
+ return sh_vec->size();
+}
+
+void sync_fetch_deposited_balance(wallet::payment_address& address,
+ bc::blockchain::block_chain_impl& blockchain, std::shared_ptr sh_vec)
+{
+ chain::transaction tx_temp;
+ uint64_t tx_height;
+ uint64_t height = 0;
+ blockchain.get_last_height(height);
+
+ auto&& address_str = address.encoded();
+ auto&& rows = blockchain.get_address_history(address, false);
+ for (auto& row: rows) {
+ if (row.output_height == 0) {
+ continue;
+ }
+
+ // spend unconfirmed (or no spend attempted)
+ if ((row.spend.hash == null_hash)
+ && blockchain.get_transaction(row.output.hash, tx_temp, tx_height)) {
+ BITCOIN_ASSERT(row.output.index < tx_temp.outputs.size());
+ auto output = tx_temp.outputs.at(row.output.index);
+
+ if (chain::operation::is_pay_key_hash_with_lock_height_pattern(output.script.operations)) {
+ // deposit utxo in block
+ uint64_t deposit_height = chain::operation::
+ get_lock_height_from_pay_key_hash_with_lock_height(output.script.operations);
+ uint64_t expiration_height = row.output_height + deposit_height;
+
+ if (expiration_height > height) {
+ auto&& tx_hash = encode_hash(tx_temp.hash());
+ const auto match = [&tx_hash](const deposited_balance& balance) {
+ return balance.tx_hash == tx_hash;
+ };
+ auto iter = std::find_if(sh_vec->begin(), sh_vec->end(), match);
+ if (iter != sh_vec->end()) {
+ // interest of deposit
+ iter->balance += row.value;
+ }
+ else {
+ auto&& row_hash = encode_hash(row.output.hash);
+ deposited_balance balance(address_str, tx_hash, row_hash,
+ row.value, deposit_height, expiration_height);
+ sh_vec->push_back(std::move(balance));
+ }
+ }
+ }
+ }
+ }
+}
+
void sync_fetchbalance(wallet::payment_address& address,
bc::blockchain::block_chain_impl& blockchain, balances& addr_balance)
{
- auto&& rows = blockchain.get_address_history(address);
+ auto&& rows = blockchain.get_address_history(address, false);
uint64_t total_received = 0;
uint64_t confirmed_balance = 0;
@@ -271,9 +336,10 @@ void sync_fetchbalance(wallet::payment_address& address,
uint64_t height = 0;
blockchain.get_last_height(height);
- for (auto& row: rows)
- {
- total_received += row.value;
+ for (auto& row: rows) {
+ if (row.output_height == 0) {
+ continue;
+ }
// spend unconfirmed (or no spend attempted)
if ((row.spend.hash == null_hash)
@@ -282,23 +348,17 @@ void sync_fetchbalance(wallet::payment_address& address,
auto output = tx_temp.outputs.at(row.output.index);
if (chain::operation::is_pay_key_hash_with_lock_height_pattern(output.script.operations)) {
- if (row.output_height == 0) {
- // deposit utxo in transaction pool
+ // deposit utxo in block
+ uint64_t lock_height = chain::operation::
+ get_lock_height_from_pay_key_hash_with_lock_height(output.script.operations);
+ if ((row.output_height + lock_height) > height) {
+ // utxo already in block but deposit not expire
frozen_balance += row.value;
}
- else {
- // deposit utxo in block
- uint64_t lock_height = chain::operation::
- get_lock_height_from_pay_key_hash_with_lock_height(output.script.operations);
- if((row.output_height + lock_height) > height) {
- // utxo already in block but deposit not expire
- frozen_balance += row.value;
- }
- }
}
else if (tx_temp.is_coinbase()) { // coin base etp maturity etp check
// add not coinbase_maturity etp into frozen
- if ((row.output_height == 0) || ((row.output_height + coinbase_maturity) > height)) {
+ if ((row.output_height + coinbase_maturity) > height) {
frozen_balance += row.value;
}
}
@@ -306,8 +366,9 @@ void sync_fetchbalance(wallet::payment_address& address,
unspent_balance += row.value;
}
- if (row.output_height != 0 &&
- (row.spend.hash == null_hash || row.spend_height == 0))
+ total_received += row.value;
+
+ if ((row.spend.hash == null_hash || row.spend_height == 0))
confirmed_balance += row.value;
}
@@ -1385,13 +1446,23 @@ void issuing_asset::sum_payment_amount()
throw asset_symbol_notfound_exception{symbol_ + " not created"};
}
- if (payment_etp_ < 1000000000) { // 10 etp now
- throw asset_issue_poundage_exception{"fee must at least 1000000000 satoshi == 10 etp"};
+ uint64_t min_fee = bc::min_fee_to_issue_asset;
+ if (payment_etp_ < min_fee) {
+ throw asset_issue_poundage_exception("fee must at least "
+ + std::to_string(min_fee) + " satoshi == "
+ + std::to_string(min_fee/100000000) + " etp");
}
if (!attenuation_model_param_.empty()) {
check_model_param_initial(attenuation_model_param_, unissued_asset_->get_maximum_supply());
}
+
+ uint64_t amount = (uint64_t)std::floor(payment_etp_ * ((100 - fee_percentage_to_miner_) / 100.0));
+ if (amount > 0) {
+ auto&& address = bc::get_developer_community_address(blockchain_.chain_settings().use_testnet_rules);
+ auto&& did = blockchain_.get_did_from_address(address);
+ receiver_list_.push_back({address, "", amount, 0, utxo_attach_type::etp, attachment("", did)});
+ }
}
chain::operation::stack
@@ -1544,8 +1615,19 @@ void issuing_asset_cert::sum_payment_amount()
void registering_did::sum_payment_amount()
{
base_transfer_common::sum_payment_amount();
- if (payment_etp_ < 100000000) {
- throw did_register_poundage_exception{"fee must at least 100000000 satoshi == 1 etp"};
+
+ uint64_t min_fee = bc::min_fee_to_register_did;
+ if (payment_etp_ < min_fee) {
+ throw did_register_poundage_exception("fee must at least "
+ + std::to_string(min_fee) + " satoshi == "
+ + std::to_string(min_fee/100000000) + " etp");
+ }
+
+ uint64_t amount = (uint64_t)std::floor(payment_etp_ * ((100 - fee_percentage_to_miner_) / 100.0));
+ if (amount > 0) {
+ auto&& address = bc::get_developer_community_address(blockchain_.chain_settings().use_testnet_rules);
+ auto&& did = blockchain_.get_did_from_address(address);
+ receiver_list_.push_back({address, "", amount, 0, utxo_attach_type::etp, attachment("", did)});
}
}
diff --git a/src/lib/explorer/extensions/commands/burn.cpp b/src/lib/explorer/extensions/commands/burn.cpp
index dbfed13d7..7a4630e38 100644
--- a/src/lib/explorer/extensions/commands/burn.cpp
+++ b/src/lib/explorer/extensions/commands/burn.cpp
@@ -45,7 +45,7 @@ console_result burn::invoke(Json::Value& jv_output,
std::stringstream sout("");
const char* cmds[]{"didsendasset", auth_.name.c_str(), auth_.auth.c_str(), blackhole_did.c_str(), argument_.symbol.c_str(), amount.c_str()};
- if (dispatch_command(6, cmds, jv_output, node, 2) != console_result::okay) {
+ if (dispatch_command(6, cmds, jv_output, node, get_api_version()) != console_result::okay) {
throw address_generate_exception(sout.str());
}
diff --git a/src/lib/explorer/extensions/commands/changepasswd.cpp b/src/lib/explorer/extensions/commands/changepasswd.cpp
index 6288ff9d3..10e621b1f 100644
--- a/src/lib/explorer/extensions/commands/changepasswd.cpp
+++ b/src/lib/explorer/extensions/commands/changepasswd.cpp
@@ -63,7 +63,7 @@ console_result changepasswd::invoke(Json::Value& jv_output,
auto& jv = jv_output;
jv["name"] = auth_.name;
- jv["status"] = "password changed";
+ jv["status"] = "changed successfully";
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/createasset.cpp b/src/lib/explorer/extensions/commands/createasset.cpp
index ce4666bbe..7f26325d0 100644
--- a/src/lib/explorer/extensions/commands/createasset.cpp
+++ b/src/lib/explorer/extensions/commands/createasset.cpp
@@ -107,9 +107,15 @@ console_result createasset::invoke(Json::Value& jv_output,
blockchain.store_account_asset(acc, auth_.name);
- Json::Value asset_data = config::json_helper(get_api_version()).prop_list(*acc, true);
- asset_data["status"] = "unissued";
- jv_output["asset"] = asset_data;
+ if (get_api_version() <= 2) {
+ Json::Value asset_data = config::json_helper(get_api_version()).prop_list(*acc, true);
+ asset_data["status"] = "unissued";
+ jv_output["asset"] = asset_data;
+ }
+ else {
+ jv_output = config::json_helper(get_api_version()).prop_list(*acc, true);
+ jv_output["status"] = "unissued";
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/createmultisigtx.cpp b/src/lib/explorer/extensions/commands/createmultisigtx.cpp
index cb75f9f5a..b51238946 100644
--- a/src/lib/explorer/extensions/commands/createmultisigtx.cpp
+++ b/src/lib/explorer/extensions/commands/createmultisigtx.cpp
@@ -94,15 +94,7 @@ console_result createmultisigtx::invoke(
// output json
auto && tx = sp_send_helper->get_transaction();
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx);
- if (get_api_version() <= 2) {
- jv_output = tx_buf.str();
- }
- else {
- // TODO support restful API format
- jv_output["raw"] = tx_buf.str();
- }
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx, false, true);
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/createrawtx.cpp b/src/lib/explorer/extensions/commands/createrawtx.cpp
index c2ad93bf6..24de0b42e 100644
--- a/src/lib/explorer/extensions/commands/createrawtx.cpp
+++ b/src/lib/explorer/extensions/commands/createrawtx.cpp
@@ -19,6 +19,7 @@
*/
+#include
#include
#include
#include
@@ -137,15 +138,7 @@ console_result createrawtx::invoke(Json::Value& jv_output,
auto&& tx = sp_send_helper->get_transaction();
// output json
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx);
- if (get_api_version() <= 2) {
- jv_output["hex"] = tx_buf.str();
- }
- else {
- // TODO support restful API format
- jv_output["raw"] = tx_buf.str();
- }
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx, false);
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/decoderawtx.cpp b/src/lib/explorer/extensions/commands/decoderawtx.cpp
index 057fbd280..6da644168 100644
--- a/src/lib/explorer/extensions/commands/decoderawtx.cpp
+++ b/src/lib/explorer/extensions/commands/decoderawtx.cpp
@@ -33,7 +33,7 @@ console_result decoderawtx::invoke(Json::Value& jv_output,
libbitcoin::server::server_node& node)
{
tx_type tx_ = argument_.transaction;
- jv_output = config::json_helper(get_api_version()).prop_tree(tx_, true);
+ jv_output = config::json_helper(get_api_version()).prop_tree(tx_, true);
return console_result::okay;
}
@@ -41,4 +41,3 @@ console_result decoderawtx::invoke(Json::Value& jv_output,
} // namespace commands
} // namespace explorer
} // namespace libbitcoin
-
diff --git a/src/lib/explorer/extensions/commands/deleteaccount.cpp b/src/lib/explorer/extensions/commands/deleteaccount.cpp
index 9b757831d..8b687903d 100644
--- a/src/lib/explorer/extensions/commands/deleteaccount.cpp
+++ b/src/lib/explorer/extensions/commands/deleteaccount.cpp
@@ -46,10 +46,8 @@ console_result deleteaccount::invoke(Json::Value& jv_output,
// delete account
blockchain.delete_account(acc->get_name());
- auto& jv = jv_output;
- jv["name"] = acc->get_name();
- jv["status"]= "removed successfully";
-
+ jv_output["name"] = acc->get_name();
+ jv_output["status"]= "removed successfully";
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/deletelocalasset.cpp b/src/lib/explorer/extensions/commands/deletelocalasset.cpp
index 70bc1e1c8..37a7a5f08 100644
--- a/src/lib/explorer/extensions/commands/deletelocalasset.cpp
+++ b/src/lib/explorer/extensions/commands/deletelocalasset.cpp
@@ -86,12 +86,15 @@ console_result deletelocalasset::invoke(Json::Value& jv_output,
throw asset_notfound_exception{"asset " + option_.symbol + " does not existed or do not belong to " + auth_.name + "."};
}
- Json::Value result;
- result["symbol"] = option_.symbol;
- result["operate"] = "delete";
- result["result"] = "success";
-
- jv_output = result;
+ if (get_api_version() <= 2) {
+ jv_output["symbol"] = option_.symbol;
+ jv_output["operate"] = "delete";
+ jv_output["result"] = "success";
+ }
+ else {
+ jv_output["symbol"] = option_.symbol;
+ jv_output["status"]= "deleted successfully";
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/deletemultisig.cpp b/src/lib/explorer/extensions/commands/deletemultisig.cpp
index 14d195098..1c93677ca 100644
--- a/src/lib/explorer/extensions/commands/deletemultisig.cpp
+++ b/src/lib/explorer/extensions/commands/deletemultisig.cpp
@@ -88,20 +88,20 @@ console_result deletemultisig::invoke(Json::Value& jv_output,
}
// output json
+ jv_output.resize(0);
auto helper = config::json_helper(get_api_version());
if (get_api_version() <= 2) {
auto& acc_multisig = *(multisig_vec->begin());
jv_output = helper.prop_list(acc_multisig);
}
else {
- // TODO support new functionality
Json::Value nodes;
for(auto& acc_multisig : *multisig_vec) {
Json::Value node = helper.prop_list(acc_multisig);
nodes.append(node);
}
- jv_output["multisig"] = nodes;
+ jv_output = nodes;
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/didchangeaddress.cpp b/src/lib/explorer/extensions/commands/didchangeaddress.cpp
index 72281b8d2..66317ce29 100644
--- a/src/lib/explorer/extensions/commands/didchangeaddress.cpp
+++ b/src/lib/explorer/extensions/commands/didchangeaddress.cpp
@@ -111,11 +111,7 @@ console_result didchangeaddress::invoke(Json::Value& jv_output,
send_helper.exec();
// json output
auto && tx = send_helper.get_transaction();
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx);
- jv_output = tx_buf.str();
- // TODO support restful API format
- // jv_output["raw"] = tx_buf.str();
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx, false, true);
}
else
{
diff --git a/src/lib/explorer/extensions/commands/dumpkeyfile.cpp b/src/lib/explorer/extensions/commands/dumpkeyfile.cpp
index 02c373fe7..77c80f683 100644
--- a/src/lib/explorer/extensions/commands/dumpkeyfile.cpp
+++ b/src/lib/explorer/extensions/commands/dumpkeyfile.cpp
@@ -56,6 +56,7 @@ console_result dumpkeyfile::invoke(Json::Value& jv_output,
//file_root["accounts"] = ss.str();
Json::Value multisig_lst;
+ multisig_lst.resize(0);
for (auto ms : acc->get_multisig_vec()) {
Json::Value multisig;
multisig["m"] = ms.get_m();
diff --git a/src/lib/explorer/extensions/commands/getaccount.cpp b/src/lib/explorer/extensions/commands/getaccount.cpp
index c5f2f7fd4..9d0471906 100644
--- a/src/lib/explorer/extensions/commands/getaccount.cpp
+++ b/src/lib/explorer/extensions/commands/getaccount.cpp
@@ -33,7 +33,7 @@ using namespace bc::explorer::config;
/************************ getaccount *************************/
console_result getaccount::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
auto& blockchain = node.chain_impl();
auto acc = blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
@@ -42,14 +42,23 @@ console_result getaccount::invoke(Json::Value& jv_output,
std::string&& mnemonic = blockchain.is_account_lastwd_valid(*acc, auth_.auth, argument_.last_word);
auto& root = jv_output;
- root["name"] = acc->get_name();
- root["mnemonic-key"] = mnemonic;
+
if (get_api_version() == 1) {
- root["address-count"] += acc->get_hd_index();
- root["user-status"] += acc->get_user_status();
- } else {
- root["address-count"] = acc->get_hd_index();
- root["user-status"] = acc->get_user_status();
+ root["name"] = acc->get_name();
+ root["mnemonic-key"] = mnemonic;
+ root["address-count"] += acc->get_hd_index() + 1;
+ root["user-status"] += (uint8_t)account_status::normal;
+ }
+ else if (get_api_version() == 2) {
+ root["name"] = acc->get_name();
+ root["mnemonic-key"] = mnemonic;
+ root["address-count"] = acc->get_hd_index() + 1;
+ root["user-status"] = (uint8_t)account_status::normal;
+ }
+ else {
+ root["name"] = acc->get_name();
+ root["mnemonic"] = mnemonic;
+ root["address_count"] = acc->get_hd_index() + 1;
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/getaccountasset.cpp b/src/lib/explorer/extensions/commands/getaccountasset.cpp
index ffa28515c..46a5def46 100644
--- a/src/lib/explorer/extensions/commands/getaccountasset.cpp
+++ b/src/lib/explorer/extensions/commands/getaccountasset.cpp
@@ -66,6 +66,10 @@ console_result getaccountasset::invoke(Json::Value& jv_output,
Json::Value asset_cert = json_helper.prop_list(elem);
json_value.append(asset_cert);
+
+ if (!argument_.symbol.empty()) {
+ break;
+ }
}
}
else {
@@ -91,6 +95,10 @@ console_result getaccountasset::invoke(Json::Value& jv_output,
Json::Value asset_data = json_helper.prop_list(elem, *issued_asset);
asset_data["status"] = "unspent";
json_value.append(asset_data);
+
+ if (!argument_.symbol.empty()) {
+ break;
+ }
}
// 2. get asset in local database
@@ -101,18 +109,29 @@ console_result getaccountasset::invoke(Json::Value& jv_output,
// symbol filter
if(!argument_.symbol.empty() && argument_.symbol != symbol)
continue;
+
Json::Value asset_data = json_helper.prop_list(elem.detail, false);
asset_data["status"] = "unissued";
json_value.append(asset_data);
+
+ if (!argument_.symbol.empty()) {
+ break;
+ }
}
}
if (get_api_version() == 1 && json_value.isNull()) { //compatible for v1
jv_output[json_key] = "";
}
- else {
+ else if (get_api_version() <= 2) {
jv_output[json_key] = json_value;
}
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+
+ jv_output = json_value;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getaddressasset.cpp b/src/lib/explorer/extensions/commands/getaddressasset.cpp
index 7618c6ac3..38594b648 100644
--- a/src/lib/explorer/extensions/commands/getaddressasset.cpp
+++ b/src/lib/explorer/extensions/commands/getaddressasset.cpp
@@ -42,7 +42,7 @@ console_result getaddressasset::invoke(Json::Value& jv_output,
std::string json_key;
Json::Value json_value;
- auto json_helper = config::json_helper(get_api_version());
+ auto json_helper = config::json_helper(get_api_version());;
if (option_.is_cert) { // only get asset certs
json_key = "assetcerts";
@@ -75,9 +75,15 @@ console_result getaddressasset::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && json_value.isNull()) { //compatible for v1
jv_output[json_key] = "";
}
- else {
+ else if (get_api_version() <= 2) {
jv_output[json_key] = json_value;
}
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+
+ jv_output = json_value;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getaddressetp.cpp b/src/lib/explorer/extensions/commands/getaddressetp.cpp
index bd4f50ca1..6443da16f 100644
--- a/src/lib/explorer/extensions/commands/getaddressetp.cpp
+++ b/src/lib/explorer/extensions/commands/getaddressetp.cpp
@@ -32,7 +32,7 @@ using namespace bc::explorer::config;
/************************ getaddressetp *************************/
console_result getaddressetp::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
auto& blockchain = node.chain_impl();
auto& addr = argument_.address;
@@ -48,14 +48,20 @@ console_result getaddressetp::invoke(Json::Value& jv_output,
jv["received"] = std::to_string(addr_balance.total_received);
jv["unspent"] = std::to_string(addr_balance.unspent_balance);
jv["frozen"] = std::to_string(addr_balance.frozen_balance);
- } else {
+ }
+ else {
jv["confirmed"] = addr_balance.confirmed_balance;
jv["received"] = addr_balance.total_received;
jv["unspent"] = addr_balance.unspent_balance;
jv["frozen"] = addr_balance.frozen_balance;
}
- jv_output["balance"] = jv;
+ if (get_api_version() <= 2) {
+ jv_output["balance"] = jv;
+ }
+ else {
+ jv_output = jv;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getasset.cpp b/src/lib/explorer/extensions/commands/getasset.cpp
index e9259921c..2c3ba3715 100644
--- a/src/lib/explorer/extensions/commands/getasset.cpp
+++ b/src/lib/explorer/extensions/commands/getasset.cpp
@@ -111,9 +111,15 @@ console_result getasset::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && json_value.isNull()) { //compatible for v1
jv_output[json_key] = "";
}
- else {
+ else if (get_api_version() <= 2) {
jv_output[json_key] = json_value;
}
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+
+ jv_output = json_value;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getbalance.cpp b/src/lib/explorer/extensions/commands/getbalance.cpp
index 9050371d7..37c35ec79 100644
--- a/src/lib/explorer/extensions/commands/getbalance.cpp
+++ b/src/lib/explorer/extensions/commands/getbalance.cpp
@@ -60,19 +60,27 @@ console_result getbalance::invoke(Json::Value& jv_output,
total_frozen += addr_balance.frozen_balance;
}
- if (get_api_version() == 1){
+ if (get_api_version() == 1) {
aroot["total-confirmed"] += total_confirmed;
aroot["total-received"] += total_received;
aroot["total-unspent"] += total_unspent;
aroot["total-available"] += (total_unspent - total_frozen);
aroot["total-frozen"] += total_frozen;
- } else {
+ }
+ else if (get_api_version() == 2) {
aroot["total-confirmed"] = total_confirmed;
aroot["total-received"] = total_received;
aroot["total-unspent"] = total_unspent;
aroot["total-available"] = (total_unspent - total_frozen);
aroot["total-frozen"] = total_frozen;
}
+ else {
+ aroot["total_confirmed"] = total_confirmed;
+ aroot["total_received"] = total_received;
+ aroot["total_unspent"] = total_unspent;
+ aroot["total_available"] = (total_unspent - total_frozen);
+ aroot["total_frozen"] = total_frozen;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getblock.cpp b/src/lib/explorer/extensions/commands/getblock.cpp
index 1fa552b57..212d78b9a 100644
--- a/src/lib/explorer/extensions/commands/getblock.cpp
+++ b/src/lib/explorer/extensions/commands/getblock.cpp
@@ -33,7 +33,7 @@ namespace commands {
/************************ getblock *************************/
console_result getblock::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
auto json = option_.json;
auto tx_json = option_.tx_json;
@@ -46,18 +46,17 @@ console_result getblock::invoke(Json::Value& jv_output,
std::promise p;
auto& blockchain = node.chain_impl();
- blockchain.fetch_block(block_height, [&p, &jv_output, json, tx_json, this](const code& ec, chain::block::ptr block) {
+ blockchain.fetch_block(block_height, [&p, &jv_output, json, tx_json, this](const code & ec, chain::block::ptr block) {
if (ec) {
p.set_value(ec);
return;
}
if (json) {
- jv_output = config::json_helper(get_api_version()).prop_tree(*block, json, tx_json);
+ jv_output = config::json_helper(get_api_version()).prop_tree(*block, json, tx_json);
}
- else
- {
- jv_output = config::json_helper(get_api_version()).prop_tree(*block, false, false);
+ else {
+ jv_output = config::json_helper(get_api_version()).prop_tree(*block, false, false);
}
p.set_value(error::success);
});
@@ -66,27 +65,25 @@ console_result getblock::invoke(Json::Value& jv_output,
if (result) {
throw block_height_get_exception{ result.message() };
}
-
}
- else {
+ else {
// fetch_block via hash
bc::config::hash256 block_hash(argument_.hash_or_height);
std::promise p;
auto& blockchain = node.chain_impl();
- blockchain.fetch_block(block_hash, [&p, &jv_output, json, tx_json, this](const code& ec, chain::block::ptr block) {
+ blockchain.fetch_block(block_hash, [&p, &jv_output, json, tx_json, this](const code & ec, chain::block::ptr block) {
if (ec) {
p.set_value(ec);
return;
}
if (json) {
- jv_output = config::json_helper(get_api_version()).prop_tree(*block, json, tx_json);
+ jv_output = config::json_helper(get_api_version()).prop_tree(*block, json, tx_json);
}
- else
- {
- jv_output = config::json_helper(get_api_version()).prop_tree(*block, false, false);
+ else {
+ jv_output = config::json_helper(get_api_version()).prop_tree(*block, false, false);
}
p.set_value(error::success);
});
@@ -95,7 +92,6 @@ console_result getblock::invoke(Json::Value& jv_output,
if (result) {
throw block_height_get_exception{ result.message() };
}
-
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/getblockheader.cpp b/src/lib/explorer/extensions/commands/getblockheader.cpp
index 251118a92..d73d04bbd 100644
--- a/src/lib/explorer/extensions/commands/getblockheader.cpp
+++ b/src/lib/explorer/extensions/commands/getblockheader.cpp
@@ -38,13 +38,14 @@ using namespace bc::explorer::config;
/************************ getblockheader *************************/
console_result getblockheader::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
uint64_t height = 0;
auto& blockchain = node.chain_impl();
- if(!blockchain.get_last_height(height))
+ if (!blockchain.get_last_height(height)) {
throw block_last_height_get_exception{"query last height failure."};
+ }
if (option_.height != std::numeric_limits::max()) {
height = option_.height;
@@ -54,38 +55,54 @@ console_result getblockheader::invoke(Json::Value& jv_output,
obelisk_client client(connection);
- if (!client.connect(connection))
- {
+ if (!client.connect(connection)) {
throw connection_exception{"Could not connect to mvsd port 9921."};
}
+
encoding json_format{"json"};
std::ostringstream output;
callback_state state(output, output, json_format);
- auto on_done = [this, &jv_output](const chain::header& header)
+ auto on_done = [this, &jv_output](const chain::header & header)
{
auto&& jheader = config::json_helper(get_api_version()).prop_tree(header);
- if( !jheader.isObject()
- || !jheader["result"].isObject()
- || !jheader["result"]["hash"].isString()) {
+ if (get_api_version() <= 2) {
+ if ( !jheader.isObject()
+ || !jheader["result"].isObject()
+ || !jheader["result"]["hash"].isString()) {
+ throw block_hash_get_exception{"getbestblockhash got parser exception."};
+ }
- throw block_hash_get_exception{"getbestblockhash got parser exception."};
+ if (option_.is_getbestblockhash) {
+ auto&& blockhash = jheader["result"]["hash"].asString();
+ jv_output = blockhash;
+ }
+ else {
+ if (get_api_version() == 1) {
+ jv_output = jheader;
+ }
+ else {
+ jv_output = jheader["result"];
+ }
+ }
}
+ else {
+ if (!jheader.isObject() || !jheader["hash"].isString()) {
+ throw block_hash_get_exception{"getbestblockhash parser exception."};
+ }
- if (option_.is_getbestblockhash) {
- auto&& blockhash = jheader["result"]["hash"].asString();
- jv_output = blockhash;
- } else {
- if (get_api_version() == 1) {
+ if (option_.is_getbestblockhash) {
+ auto&& blockhash = jheader["hash"].asString();
+ jv_output = blockhash;
+ }
+ else {
jv_output = jheader;
- } else {
- jv_output = jheader["result"];
}
}
};
- auto on_error = [&state](const code& error)
+ auto on_error = [&state](const code & error)
{
state.succeeded(error);
};
@@ -93,10 +110,12 @@ console_result getblockheader::invoke(Json::Value& jv_output,
// Height is ignored if both are specified.
// Use the null_hash as sentinel to determine whether to use height or hash.
const hash_digest& hash = option_.hash;
- if (hash == null_hash)
+ if (hash == null_hash) {
client.blockchain_fetch_block_header(on_error, on_done, height);
- else
+ }
+ else {
client.blockchain_fetch_block_header(on_error, on_done, hash);
+ }
client.wait();
diff --git a/src/lib/explorer/extensions/commands/getdid.cpp b/src/lib/explorer/extensions/commands/getdid.cpp
index eb982b007..1d6919643 100644
--- a/src/lib/explorer/extensions/commands/getdid.cpp
+++ b/src/lib/explorer/extensions/commands/getdid.cpp
@@ -31,73 +31,72 @@ namespace explorer {
namespace commands {
console_result getdid::invoke (Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
Json::Value json_value;
auto& blockchain = node.chain_impl();
- if(option_.symbol.empty())
- {
+ if (option_.symbol.empty()) {
+
auto sh_vec = blockchain.get_registered_dids();
+ std::sort(sh_vec->begin(), sh_vec->end());
// add blockchain dids
- for (auto& elem: *sh_vec)
+ for (auto& elem : *sh_vec) {
json_value.append(elem.get_symbol());
+ }
- if (get_api_version() == 1 && json_value.isNull()) { //compatible for v1
- jv_output["dids"] = "";
+ if (get_api_version() <= 2) {
+ jv_output["dids"] = json_value;
}
else {
- jv_output["dids"] = json_value;
+ jv_output = json_value;
}
}
- else
- {
-
+ else {
auto didSymbol = option_.symbol;
- if(blockchain.is_valid_address(didSymbol))
- {
+ if (blockchain.is_valid_address(didSymbol)) {
didSymbol = blockchain.get_did_from_address(didSymbol);
- if(didSymbol.empty())
+ if (didSymbol.empty()) {
throw address_not_bound_did_exception{"address is not binded with some did on the blockchain"};
+ }
}
// check did symbol
check_did_symbol(didSymbol);
// check did exists
- if (!blockchain.is_did_exist(didSymbol))
+ if (!blockchain.is_did_exist(didSymbol)) {
throw did_symbol_notfound_exception{"did symbol does not exist on the blockchain"};
+ }
auto blockchain_dids = blockchain.get_did_history_addresses(didSymbol);
if (blockchain_dids) {
Json::Value json_address;
Json::Value did_data;
- for (auto &did : *blockchain_dids){
+ for (auto &did : *blockchain_dids) {
did_data["address"] = did.get_did().get_address();
did_data["status"] = did.get_status_string();
+ if (get_api_version() >= 3) {
+ did_data["symbol"] = didSymbol;
+ }
json_value.append(did_data);
}
-
-
- if (get_api_version() == 1 && json_value.isNull()) { //compatible for v1
- jv_output["did"] = didSymbol;
- jv_output["addresses"] = "";
- }
- else {
+
+ if (get_api_version() <= 2) {
jv_output["did"] = didSymbol;
jv_output["addresses"] = json_value;
}
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+ jv_output = json_value;
+ }
}
-
-
}
-
-
-
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getinfo.cpp b/src/lib/explorer/extensions/commands/getinfo.cpp
index a5dd01fdd..20102e9a9 100644
--- a/src/lib/explorer/extensions/commands/getinfo.cpp
+++ b/src/lib/explorer/extensions/commands/getinfo.cpp
@@ -33,26 +33,17 @@ using namespace bc::explorer::config;
/************************ getinfo *************************/
console_result getinfo::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
auto& blockchain = node.chain_impl();
administrator_required_checker(node, auth_.name, auth_.auth);
- auto& jv = jv_output;
- jv["protocol-version"] = node.network_settings().protocol;
- jv["wallet-version"] = MVS_EXPLORER_VERSION;
- jv["database-version"] = MVS_DATABASE_VERSION;
- jv["testnet"] = blockchain.chain_settings().use_testnet_rules;
- jv["peers"] = get_connections_count(node);
-
auto sh_vec = blockchain.get_issued_assets();
std::set symbols;
- for (const auto& elem: *sh_vec) {
+ for (const auto& elem : *sh_vec) {
symbols.insert(elem.get_symbol());
}
- jv["network-assets-count"] = static_cast(symbols.size());
- jv["wallet-account-count"] = static_cast(blockchain.get_accounts()->size());
uint64_t height;
uint64_t rate;
@@ -60,11 +51,37 @@ console_result getinfo::invoke(Json::Value& jv_output,
bool is_solo_mining;
node.miner().get_state(height, rate, difficulty, is_solo_mining);
- jv["height"] = height;
- jv["difficulty"] = difficulty;
- jv["is-mining"] = is_solo_mining;
- jv["hash-rate"] = rate;
+ auto& jv = jv_output;
+ if (get_api_version() <= 2) {
+ jv["protocol-version"] = node.network_settings().protocol;
+ jv["wallet-version"] = MVS_EXPLORER_VERSION;
+ jv["database-version"] = MVS_DATABASE_VERSION;
+ jv["testnet"] = blockchain.chain_settings().use_testnet_rules;
+ jv["peers"] = get_connections_count(node);
+
+ jv["network-assets-count"] = static_cast(symbols.size());
+ jv["wallet-account-count"] = static_cast(blockchain.get_accounts()->size());
+ jv["height"] = height;
+ jv["difficulty"] = difficulty;
+ jv["is-mining"] = is_solo_mining;
+ jv["hash-rate"] = rate;
+ }
+ else {
+ jv["protocol_version"] = node.network_settings().protocol;
+ jv["wallet_version"] = MVS_EXPLORER_VERSION;
+ jv["database_version"] = MVS_DATABASE_VERSION;
+ jv["testnet"] = blockchain.chain_settings().use_testnet_rules;
+ jv["peers"] = get_connections_count(node);
+
+ jv["asset_count"] = static_cast(symbols.size());
+ jv["wallet_account_count"] = static_cast(blockchain.get_accounts()->size());
+
+ jv["height"] = height;
+ jv["difficulty"] = difficulty;
+ jv["is_mining"] = is_solo_mining;
+ jv["hash_rate"] = rate;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getmemorypool.cpp b/src/lib/explorer/extensions/commands/getmemorypool.cpp
index 80ae00fef..1fa3dabae 100644
--- a/src/lib/explorer/extensions/commands/getmemorypool.cpp
+++ b/src/lib/explorer/extensions/commands/getmemorypool.cpp
@@ -34,7 +34,7 @@ namespace commands {
/************************ getbalance *************************/
console_result getmemorypool::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
administrator_required_checker(node, auth_.name, auth_.auth);
@@ -43,28 +43,29 @@ console_result getmemorypool::invoke(Json::Value& jv_output,
using transaction_ptr = message::transaction_message::ptr ;
auto& blockchain = node.chain_impl();
std::promise p;
- blockchain.pool().fetch([&jv_output, &p, &json, this](const code& ec, const std::vector& txs){
- if (ec)
- {
+ blockchain.pool().fetch([&jv_output, &p, &json, this](const code & ec, const std::vector& txs) {
+ if (ec) {
p.set_value(ec);
return;
}
+
std::vector txs1;
txs1.reserve(txs.size());
- for (auto tp:txs) {
+ for (auto tp : txs) {
txs1.push_back(*tp);
}
- if(json) {
- jv_output = config::json_helper(get_api_version()).prop_tree(txs1, true);
- } else {
- jv_output = config::json_helper(get_api_version()).prop_tree(txs1, false);
+ if (json) {
+ jv_output = config::json_helper(get_api_version()).prop_tree(txs1, true);
+ }
+ else {
+ jv_output = config::json_helper(get_api_version()).prop_tree(txs1, false);
}
p.set_value(ec);
});
auto result = p.get_future().get();
- if(result){
+ if (result) {
throw tx_fetch_exception{result.message()};
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/getmininginfo.cpp b/src/lib/explorer/extensions/commands/getmininginfo.cpp
index c59246d4a..783b677ac 100644
--- a/src/lib/explorer/extensions/commands/getmininginfo.cpp
+++ b/src/lib/explorer/extensions/commands/getmininginfo.cpp
@@ -32,25 +32,32 @@ using namespace bc::explorer::config;
/************************ getmininginfo *************************/
console_result getmininginfo::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
administrator_required_checker(node, auth_.name, auth_.auth);
- auto& aroot = jv_output;
- Json::Value info;
-
- auto& miner = node.miner();
-
uint64_t height, rate;
std::string difficulty;
bool is_mining;
+ auto& miner = node.miner();
miner.get_state(height, rate, difficulty, is_mining);
- info["is-mining"] = is_mining;
- info["height"] += height;
- info["rate"] += rate;
- info["difficulty"] = difficulty;
- aroot["mining-info"] = info;
+
+ if (get_api_version() <= 2) {
+ auto& aroot = jv_output;
+ Json::Value info;
+ info["is-mining"] = is_mining;
+ info["height"] += height;
+ info["rate"] += rate;
+ info["difficulty"] = difficulty;
+ aroot["mining-info"] = info;
+ }
+ else {
+ jv_output["is_mining"] = is_mining;
+ jv_output["height"] += height;
+ jv_output["rate"] += rate;
+ jv_output["difficulty"] = difficulty;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getmit.cpp b/src/lib/explorer/extensions/commands/getmit.cpp
index 8e6180675..498e64c36 100644
--- a/src/lib/explorer/extensions/commands/getmit.cpp
+++ b/src/lib/explorer/extensions/commands/getmit.cpp
@@ -78,7 +78,12 @@ console_result getmit::invoke(Json::Value& jv_output,
json_value.append(elem.mit.get_symbol());
}
- jv_output["mits"] = json_value;
+ if (get_api_version() <=2 ) {
+ jv_output["mits"] = json_value;
+ }
+ else {
+ jv_output = json_value;
+ }
}
else {
if (option_.show_history) {
@@ -88,7 +93,15 @@ console_result getmit::invoke(Json::Value& jv_output,
json_value.append(asset_data);
}
- jv_output["mits"] = json_value;
+ if (get_api_version() <=2 ) {
+ jv_output["mits"] = json_value;
+ }
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+
+ jv_output = json_value;
+ }
}
else {
if (option_.show_current) {
diff --git a/src/lib/explorer/extensions/commands/getnewaccount.cpp b/src/lib/explorer/extensions/commands/getnewaccount.cpp
index 985583da2..4cd9cea42 100644
--- a/src/lib/explorer/extensions/commands/getnewaccount.cpp
+++ b/src/lib/explorer/extensions/commands/getnewaccount.cpp
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-
+#include
#include
#include
#include
@@ -36,7 +36,6 @@ using namespace bc::explorer::config;
console_result getnewaccount::invoke(Json::Value& jv_output,
libbitcoin::server::server_node& node)
{
-
#ifdef NDEBUG
if (auth_.name.length() > 128 || auth_.name.length() < 3 ||
auth_.auth.length() > 128 || auth_.auth.length() < 6)
@@ -48,8 +47,6 @@ console_result getnewaccount::invoke(Json::Value& jv_output,
throw account_existed_exception{"account already exist"};
}
- auto& root = jv_output;
-
auto acc = std::make_shared();
acc->set_name(auth_.name);
acc->set_passwd(auth_.auth);
@@ -59,7 +56,6 @@ console_result getnewaccount::invoke(Json::Value& jv_output,
auto&& words_list = get_mnemonic_new(opt_language , seed);
auto&& words = bc::join(words_list);
- root["mnemonic"] = words;
acc->set_mnemonic(words, auth_.auth);
// flush to db
@@ -70,17 +66,27 @@ console_result getnewaccount::invoke(Json::Value& jv_output,
Json::Value jv_temp;
const char* cmds2[]{"getnewaddress", auth_.name.c_str(), auth_.auth.c_str()};
- if (dispatch_command(3, cmds2, jv_temp, node, 2) != console_result::okay) {
+ if (dispatch_command(3, cmds2, jv_temp, node, get_api_version()) != console_result::okay) {
throw address_generate_exception(sout.str());
}
- root["default-address"] = jv_temp["addresses"][0].asString();
+ if (get_api_version() == 1) {
+ jv_output["mnemonic"] = words;
+ jv_output["default-address"] = jv_temp;
+ }
+ else if (get_api_version() == 2) {
+ jv_output["mnemonic"] = words;
+ jv_output["default-address"] = jv_temp["addresses"][0].asString();
+ }
+ else {
+ config::json_helper::account_info acc(auth_.name, words, jv_temp);
+ jv_output = config::json_helper(get_api_version()).prop_list(acc);
+ }
return console_result::okay;
}
-
} // namespace commands
} // namespace explorer
} // namespace libbitcoin
diff --git a/src/lib/explorer/extensions/commands/getnewaddress.cpp b/src/lib/explorer/extensions/commands/getnewaddress.cpp
index 58323bc2f..a1f8b1a7c 100644
--- a/src/lib/explorer/extensions/commands/getnewaddress.cpp
+++ b/src/lib/explorer/extensions/commands/getnewaddress.cpp
@@ -54,7 +54,7 @@ console_result getnewaddress::invoke(Json::Value& jv_output,
}
Json::Value addresses;
-
+
std::vector> account_addresses;
account_addresses.reserve(option_.count);
const auto seed = decode_mnemonic(words);
@@ -108,9 +108,14 @@ console_result getnewaddress::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && option_.count == 1) {
jv_output = addresses[0];
}
- else {
+ else if (get_api_version() <= 2) {
jv_output["addresses"] = addresses;
}
+ else {
+ if(addresses.isNull())
+ addresses.resize(0);
+ jv_output = addresses;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getpeerinfo.cpp b/src/lib/explorer/extensions/commands/getpeerinfo.cpp
index a2145322a..30457023f 100644
--- a/src/lib/explorer/extensions/commands/getpeerinfo.cpp
+++ b/src/lib/explorer/extensions/commands/getpeerinfo.cpp
@@ -34,20 +34,28 @@ using namespace bc::explorer::config;
/************************ getpeerinfo *************************/
console_result getpeerinfo::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
-
administrator_required_checker(node, auth_.name, auth_.auth);
- auto& root = jv_output;
Json::Value array;
- for(auto authority : node.connections_ptr()->authority_list()) {
+ for (auto authority : node.connections_ptr()->authority_list()) {
// invalid authority
if (authority.to_hostname() == "[::]" && authority.port() == 0)
continue;
array.append(authority.to_string());
}
- root["peers"] = array;
+
+ if (get_api_version() <= 2) {
+ auto& root = jv_output;
+ root["peers"] = array;
+ }
+ else {
+ if(array.isNull())
+ array.resize(0);
+
+ jv_output = array;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/getpublickey.cpp b/src/lib/explorer/extensions/commands/getpublickey.cpp
index 318b3475b..0c9f2513b 100644
--- a/src/lib/explorer/extensions/commands/getpublickey.cpp
+++ b/src/lib/explorer/extensions/commands/getpublickey.cpp
@@ -71,8 +71,14 @@ console_result getpublickey::invoke(Json::Value& jv_output,
}
auto& root = jv_output;
- root["public-key"] = pub_key;
- root["address"] = argument_.address;
+ if (get_api_version() <= 2) {
+ root["public-key"] = pub_key;
+ root["address"] = argument_.address;
+ }
+ else {
+ root["public_key"] = pub_key;
+ root["address"] = argument_.address;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/gettx.cpp b/src/lib/explorer/extensions/commands/gettx.cpp
index 5d8595e77..7a48f3891 100644
--- a/src/lib/explorer/extensions/commands/gettx.cpp
+++ b/src/lib/explorer/extensions/commands/gettx.cpp
@@ -33,25 +33,27 @@ namespace commands {
/************************ gettx *************************/
/// extent fetch-tx command , add tx height in tx content
console_result gettx::invoke(Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
bc::chain::transaction tx;
uint64_t tx_height = 0;
auto& blockchain = node.chain_impl();
auto exist = blockchain.get_transaction(argument_.hash, tx, tx_height);
- if(!exist)
+ if (!exist) {
throw tx_notfound_exception{"transaction does not exist!"};
+ }
+ auto json_helper = config::json_helper(get_api_version());
if (option_.json) {
if (get_api_version() == 1 && option_.is_fetch_tx) { // compatible for v1 fetch-tx
- jv_output = config::json_helper(get_api_version()).prop_tree(tx, true);
- } else {
- jv_output = config::json_helper(get_api_version()).prop_list(tx, tx_height, true);
+ jv_output = json_helper.prop_tree(tx, true);
}
-
- } else {
- config::transaction config_tx{tx};
- jv_output = config::json_helper(get_api_version()).prop_tree(config_tx, false);
+ else {
+ jv_output = json_helper.prop_list(tx, tx_height, true);
+ }
+ }
+ else {
+ jv_output = json_helper.prop_tree(tx, false);
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/importaccount.cpp b/src/lib/explorer/extensions/commands/importaccount.cpp
index 4a3ee33b0..eddefc537 100644
--- a/src/lib/explorer/extensions/commands/importaccount.cpp
+++ b/src/lib/explorer/extensions/commands/importaccount.cpp
@@ -47,8 +47,7 @@ console_result importaccount::invoke(Json::Value& jv_output,
throw argument_exceed_limit_exception{"name length in [3, 128], password length in [6, 128]"};
#endif
- if (argument_.words.size() == 1)
- {
+ if (argument_.words.size() == 1) {
argument_.words = bc::split(argument_.words[0], " ", true);
}
@@ -70,25 +69,38 @@ console_result importaccount::invoke(Json::Value& jv_output,
blockchain.store_account(acc);
// generate all account address
- auto& root = jv_output;
- root["name"] = auth_.name;
- root["mnemonic"] = mnemonic;
- if (get_api_version() == 1) {
- root["hd_index"] += option_.hd_index;
- } else {
- root["hd_index"] = option_.hd_index;
- }
-
- uint32_t idx = 0;
auto&& str_idx = std::to_string(option_.hd_index);
const char* cmds2[]{"getnewaddress", auth_.name.c_str(), option_.passwd.c_str(), "-n", str_idx.c_str()};
Json::Value addresses;
- if (dispatch_command(5, cmds2, addresses, node, 2) != console_result::okay) {
+ if (dispatch_command(5, cmds2, addresses, node, get_api_version()) != console_result::okay) {
throw address_generate_exception{"getnewaddress got exception."};
}
- root["addresses"] = addresses["addresses"];
+ if (get_api_version() <= 2) {
+ if (get_api_version() == 1) {
+ jv_output["hd_index"] += option_.hd_index;
+ if (option_.hd_index == 1) {
+ Json::Value addr;
+ addr.append(addresses.asString());
+ jv_output["addresses"] = addr;
+ }
+ else {
+ jv_output["addresses"] = addresses["addresses"];
+ }
+ }
+ else if (get_api_version() == 2) {
+ jv_output["hd_index"] = option_.hd_index;
+ jv_output["addresses"] = addresses["addresses"];
+ }
+
+ jv_output["name"] = auth_.name;
+ jv_output["mnemonic"] = mnemonic;
+ }
+ else {
+ config::json_helper::account_info acc(auth_.name, mnemonic, addresses);
+ jv_output = config::json_helper(get_api_version()).prop_list(acc);
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/importkeyfile.cpp b/src/lib/explorer/extensions/commands/importkeyfile.cpp
index 8f35ba393..a0d069915 100644
--- a/src/lib/explorer/extensions/commands/importkeyfile.cpp
+++ b/src/lib/explorer/extensions/commands/importkeyfile.cpp
@@ -102,7 +102,7 @@ console_result importkeyfile::invoke(Json::Value& jv_output,
const char *cmds2[]{"getnewaddress", auth_.name.c_str(), auth_.auth.c_str(), "--number",
address_count.c_str()};
- if (dispatch_command(5, cmds2, jv_temp, node, 2) != console_result::okay) {
+ if (dispatch_command(5, cmds2, jv_temp, node, get_api_version()) != console_result::okay) {
throw address_generate_exception{std::string("Failed to generate address.")};
}
}
@@ -138,14 +138,22 @@ console_result importkeyfile::invoke(Json::Value& jv_output,
vec_cmds.push_back(s.c_str());
}
- if (dispatch_command(vec_cmds.size(), vec_cmds.data(), jv_temp, node, 2) != console_result::okay) {
+ if (dispatch_command(vec_cmds.size(), vec_cmds.data(), jv_temp, node, get_api_version()) != console_result::okay) {
throw address_generate_exception{std::string("Failed to generate address.")};
}
-
-
}
}
+ Json::Value jv_temp;
+ std::vector vec_cmds = {"listaddresses", auth_.name.c_str(), auth_.auth.c_str()};
+ if (dispatch_command(vec_cmds.size(), vec_cmds.data(), jv_temp, node, get_api_version()) != console_result::okay) {
+ throw account_address_get_exception{std::string("Failed to list account addresses.")};
+ }
+
+ auto& root = jv_output;
+ config::json_helper::account_info acc(auth_.name, "", jv_temp);
+ root = config::json_helper(get_api_version()).prop_list(acc);
+
return console_result::okay;
}
else {
@@ -170,13 +178,17 @@ console_result importkeyfile::invoke(Json::Value& jv_output,
if (get_api_version() == 1) {
root["address-count"] += acc.get_hd_index();
root["unissued-asset-count"] += all_info.get_account_asset().size();
- } else {
+ }
+ else if (get_api_version() <= 2) {
root["address-count"] = acc.get_hd_index();
root["unissued-asset-count"] = static_cast(all_info.get_account_asset().size());
}
+ else {
+ root["address_count"] = acc.get_hd_index();
+ root["unissued_asset_count"] = static_cast(all_info.get_account_asset().size());
+ }
return console_result::okay;
-
}
}
diff --git a/src/lib/explorer/extensions/commands/issue.cpp b/src/lib/explorer/extensions/commands/issue.cpp
index 776ebf2cb..336dad86d 100644
--- a/src/lib/explorer/extensions/commands/issue.cpp
+++ b/src/lib/explorer/extensions/commands/issue.cpp
@@ -35,7 +35,7 @@ namespace commands {
console_result issue::invoke (Json::Value& jv_output,
- libbitcoin::server::server_node& node)
+ libbitcoin::server::server_node& node)
{
auto& blockchain = node.chain_impl();
@@ -45,15 +45,32 @@ console_result issue::invoke (Json::Value& jv_output,
// check asset symbol
check_asset_symbol(argument_.symbol);
- if (argument_.fee < 1000000000)
- throw asset_issue_poundage_exception{"issue asset fee less than 1000000000!"};
+ // check fee
+ if (argument_.fee < bc::min_fee_to_issue_asset) {
+ throw asset_issue_poundage_exception{
+ "issue asset fee less than "
+ + std::to_string(bc::min_fee_to_issue_asset) + " that's "
+ + std::to_string(bc::min_fee_to_issue_asset / 100000000) + " ETPs"};
+ }
+
+ if (argument_.percentage < bc::min_fee_percentage_to_miner || argument_.percentage > 100) {
+ throw asset_issue_poundage_exception{
+ "issue asset minimum percentage of fee to miner less than "
+ + std::to_string(bc::min_fee_percentage_to_miner)
+ + " or greater than 100."};
+ }
+
// fail if asset is already in blockchain
- if (blockchain.is_asset_exist(argument_.symbol, false))
- throw asset_symbol_existed_exception{"asset symbol is already exist in blockchain"};
+ if (blockchain.is_asset_exist(argument_.symbol, false)) {
+ throw asset_symbol_existed_exception{
+ "asset " + argument_.symbol + " already exists in blockchain"};
+ }
+
// local database asset check
auto sh_asset = blockchain.get_account_unissued_asset(auth_.name, argument_.symbol);
- if (!sh_asset)
- throw asset_symbol_notfound_exception{argument_.symbol + " not found"};
+ if (!sh_asset) {
+ throw asset_symbol_notfound_exception{"asset " + argument_.symbol + " not found"};
+ }
auto to_did = sh_asset->get_issuer();
auto to_address = get_address_from_did(to_did, blockchain);
@@ -113,23 +130,28 @@ console_result issue::invoke (Json::Value& jv_output,
auto certs = sh_asset->get_asset_cert_mask();
if (!certs.empty()) {
for (auto each_cert_type : certs) {
- receiver.push_back({to_address, argument_.symbol, 0, 0,
- each_cert_type, utxo_attach_type::asset_cert_autoissue, attachment("", to_did)});
+ receiver.push_back(
+ { to_address, argument_.symbol, 0, 0,
+ each_cert_type, utxo_attach_type::asset_cert_autoissue, attachment("", to_did)
+ });
}
}
// domain cert or naming cert
if (asset_cert::is_valid_domain(domain)) {
- receiver.push_back({to_address, cert_symbol, 0, 0, cert_type,
+ receiver.push_back(
+ { to_address, cert_symbol, 0, 0, cert_type,
(is_domain_cert_exist ? utxo_attach_type::asset_cert : utxo_attach_type::asset_cert_autoissue),
- attachment("", to_did)});
+ attachment("", to_did)
+ });
}
- auto issue_helper = issuing_asset(*this, blockchain,
- std::move(auth_.name), std::move(auth_.auth),
- "", std::move(argument_.symbol),
- std::move(option_.attenuation_model_param),
- std::move(receiver), argument_.fee);
+ auto issue_helper = issuing_asset(
+ *this, blockchain,
+ std::move(auth_.name), std::move(auth_.auth),
+ "", std::move(argument_.symbol),
+ std::move(option_.attenuation_model_param),
+ std::move(receiver), argument_.fee, argument_.percentage);
issue_helper.exec();
diff --git a/src/lib/explorer/extensions/commands/listaddresses.cpp b/src/lib/explorer/extensions/commands/listaddresses.cpp
index 44a92793a..29ed068d1 100644
--- a/src/lib/explorer/extensions/commands/listaddresses.cpp
+++ b/src/lib/explorer/extensions/commands/listaddresses.cpp
@@ -51,9 +51,15 @@ console_result listaddresses::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && addresses.isNull()) { // compatible for v1
aroot["addresses"] = "";
}
- else {
+ else if (get_api_version() <= 2) {
aroot["addresses"] = addresses;
}
+ else {
+ if(addresses.isNull())
+ addresses.resize(0);
+
+ aroot = addresses;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/listassets.cpp b/src/lib/explorer/extensions/commands/listassets.cpp
index 99e443fc1..a8ad4dd8b 100644
--- a/src/lib/explorer/extensions/commands/listassets.cpp
+++ b/src/lib/explorer/extensions/commands/listassets.cpp
@@ -40,6 +40,7 @@ console_result listassets::invoke(Json::Value& jv_output,
std::string json_key;
Json::Value json_value;
+
auto json_helper = config::json_helper(get_api_version());
if (option_.is_cert) { // only get asset certs
@@ -123,9 +124,15 @@ console_result listassets::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && json_value.isNull()) { //compatible for v1
jv_output[json_key] = "";
}
- else {
+ else if (get_api_version() <= 2) {
jv_output[json_key] = json_value;
}
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+
+ jv_output = json_value;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/listbalances.cpp b/src/lib/explorer/extensions/commands/listbalances.cpp
index 13efb79bb..03506edd7 100644
--- a/src/lib/explorer/extensions/commands/listbalances.cpp
+++ b/src/lib/explorer/extensions/commands/listbalances.cpp
@@ -40,61 +40,109 @@ console_result listbalances::invoke(Json::Value& jv_output,
auto& blockchain = node.chain_impl();
blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
- auto& aroot = jv_output;
Json::Value all_balances;
- Json::Value address_balances;
-
+
auto vaddr = blockchain.get_account_addresses(auth_.name);
- if(!vaddr) throw address_list_nullptr_exception{"nullptr for address list"};
-
- for (auto& i: *vaddr){
- Json::Value address_balance;
- balances addr_balance{0, 0, 0, 0};
- auto waddr = wallet::payment_address(i.get_address());
- sync_fetchbalance(waddr, blockchain, addr_balance);
- address_balance["address"] = i.get_address();
-
- if (get_api_version() == 1) {
- address_balance["confirmed"] += addr_balance.confirmed_balance;
- address_balance["received"] += addr_balance.total_received;
- address_balance["unspent"] += addr_balance.unspent_balance;
- address_balance["available"] += (addr_balance.unspent_balance - addr_balance.frozen_balance);
- address_balance["frozen"] += addr_balance.frozen_balance;
- } else {
- address_balance["confirmed"] = addr_balance.confirmed_balance;
- address_balance["received"] = addr_balance.total_received;
- address_balance["unspent"] = addr_balance.unspent_balance;
- address_balance["available"] = (addr_balance.unspent_balance - addr_balance.frozen_balance);
- address_balance["frozen"] = addr_balance.frozen_balance;
+ if(!vaddr) {
+ throw address_list_nullptr_exception{"nullptr for address list"};
+ }
+
+ if (!option_.greater && option_.non_zero) {
+ option_.greater = 1;
+ }
+
+ if (option_.deposited) {
+ auto deposited_balances = std::make_shared();
+
+ for (auto& i: *vaddr){
+ auto waddr = wallet::payment_address(i.get_address());
+ sync_fetch_deposited_balance(waddr, blockchain, deposited_balances);
}
- Json::Value target_balance;
+ for (auto& balance : *deposited_balances) {
+ // non-zero lesser
+ if (option_.lesser) {
+ if (balance.balance > option_.lesser || balance.balance < option_.greater) {
+ continue;
+ }
+ }
+ else {
+ if (balance.balance < option_.greater) {
+ continue;
+ }
+ }
+
+ Json::Value json_balance;
+ json_balance["address"] = balance.address;
+ json_balance["deposited_balance"] = balance.balance;
+ json_balance["deposited_height"] = balance.deposited_height;
+ json_balance["expiration_height"] = balance.expiration_height;
- if (!option_.greater && option_.non_zero) {
- option_.greater = 1;
+ all_balances.append(json_balance);
}
- // non-zero lesser
- if (option_.lesser){
- if (addr_balance.unspent_balance <= option_.lesser &&
- addr_balance.unspent_balance >= option_.greater){
+ }
+ else {
+ for (auto& i: *vaddr){
+ balances addr_balance{0, 0, 0, 0};
+ auto waddr = wallet::payment_address(i.get_address());
+ sync_fetchbalance(waddr, blockchain, addr_balance);
+
+ // non-zero lesser
+ if (option_.lesser) {
+ if (addr_balance.unspent_balance > option_.lesser || addr_balance.unspent_balance < option_.greater) {
+ continue;
+ }
+ }
+ else {
+ if (addr_balance.unspent_balance < option_.greater) {
+ continue;
+ }
+ }
+
+ Json::Value address_balance;
+ address_balance["address"] = i.get_address();
+
+ if (get_api_version() == 1) {
+ address_balance["confirmed"] += addr_balance.confirmed_balance;
+ address_balance["received"] += addr_balance.total_received;
+ address_balance["unspent"] += addr_balance.unspent_balance;
+ address_balance["available"] += (addr_balance.unspent_balance - addr_balance.frozen_balance);
+ address_balance["frozen"] += addr_balance.frozen_balance;
+ }
+ else {
+ address_balance["confirmed"] = addr_balance.confirmed_balance;
+ address_balance["received"] = addr_balance.total_received;
+ address_balance["unspent"] = addr_balance.unspent_balance;
+ address_balance["available"] = (addr_balance.unspent_balance - addr_balance.frozen_balance);
+ address_balance["frozen"] = addr_balance.frozen_balance;
+ }
+
+ if (get_api_version() <= 2) {
+ Json::Value target_balance;
target_balance["balance"] = address_balance;
all_balances.append(target_balance);
}
- } else {
- if (addr_balance.unspent_balance >= option_.greater){
- target_balance["balance"] = address_balance;
- all_balances.append(target_balance);
+ else {
+ all_balances.append(address_balance);
}
}
}
+ auto& aroot = jv_output;
if (get_api_version() == 1 && all_balances.isNull()) { //compatible for v1
aroot["balances"] = "";
- } else {
+ }
+ else if (get_api_version() <= 2) {
aroot["balances"] = all_balances;
}
- return console_result::okay;
+ else {
+ if(all_balances.isNull())
+ all_balances.resize(0);
+
+ aroot = all_balances;
+ }
+ return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/listdids.cpp b/src/lib/explorer/extensions/commands/listdids.cpp
index 31a2e33ca..90fcef3c6 100644
--- a/src/lib/explorer/extensions/commands/listdids.cpp
+++ b/src/lib/explorer/extensions/commands/listdids.cpp
@@ -64,9 +64,15 @@ console_result listdids::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && dids.isNull()) { //compatible for v1
jv_output["dids"] = "";
}
- else {
+ else if (get_api_version() <= 2) {
jv_output["dids"] = dids;
}
+ else {
+ if(dids.isNull())
+ dids.resize(0);
+
+ jv_output = dids;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/listmits.cpp b/src/lib/explorer/extensions/commands/listmits.cpp
index a54c589f8..cbca4e3b3 100644
--- a/src/lib/explorer/extensions/commands/listmits.cpp
+++ b/src/lib/explorer/extensions/commands/listmits.cpp
@@ -73,7 +73,15 @@ console_result listmits::invoke(Json::Value& jv_output,
}
}
- jv_output["mits"] = json_value;
+ if (get_api_version() <= 2) {
+ jv_output["mits"] = json_value;
+ }
+ else {
+ if(json_value.isNull())
+ json_value.resize(0);
+
+ jv_output = json_value;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/listmultisig.cpp b/src/lib/explorer/extensions/commands/listmultisig.cpp
index 83b32bb91..480b1f9fd 100644
--- a/src/lib/explorer/extensions/commands/listmultisig.cpp
+++ b/src/lib/explorer/extensions/commands/listmultisig.cpp
@@ -39,7 +39,6 @@ console_result listmultisig::invoke(Json::Value& jv_output,
auto acc = blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
Json::Value nodes;
-
auto multisig_vec = acc->get_multisig_vec();
auto helper = config::json_helper(get_api_version());
for(auto& acc_multisig : multisig_vec) {
@@ -50,9 +49,15 @@ console_result listmultisig::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && nodes.isNull()) { // compatible for v1
jv_output["multisig"] = "";
}
- else {
+ else if (get_api_version() <= 2) {
jv_output["multisig"] = nodes;
}
+ else {
+ if(nodes.isNull())
+ nodes.resize(0);
+
+ jv_output = nodes;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/listtxs.cpp b/src/lib/explorer/extensions/commands/listtxs.cpp
index 1bf3ca5b5..8d4765f74 100644
--- a/src/lib/explorer/extensions/commands/listtxs.cpp
+++ b/src/lib/explorer/extensions/commands/listtxs.cpp
@@ -198,7 +198,8 @@ console_result listtxs::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && input_addrs.isNull()) { // compatible for v1
tx_item["inputs"] = "";
- } else {
+ }
+ else {
tx_item["inputs"] = input_addrs;
}
@@ -234,10 +235,15 @@ console_result listtxs::invoke(Json::Value& jv_output,
if (get_api_version() == 1) {
pt_output["locked_height_range"] += lock_height;
pt_output["etp-value"] += op.value;
- } else {
+ }
+ else if (get_api_version() == 2) {
pt_output["locked_height_range"] = lock_height;
pt_output["etp-value"] = op.value;
}
+ else {
+ pt_output["locked_height_range"] = lock_height;
+ pt_output["etp_value"] = op.value;
+ }
if (chain::operation::is_pay_key_hash_with_attenuation_model_pattern(op.script.operations)) {
const auto& model_param = op.get_attenuation_model_param();
@@ -274,7 +280,8 @@ console_result listtxs::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && pt_outputs.isNull()) { // compatible for v1
tx_item["outputs"] = "";
- } else {
+ }
+ else {
tx_item["outputs"] = pt_outputs;
}
@@ -304,9 +311,16 @@ console_result listtxs::invoke(Json::Value& jv_output,
if (get_api_version() == 1 && balances.isNull()) { // compatible for v1
aroot["transactions"] = "";
- } else {
+ }
+ else if (get_api_version() <= 2) {
aroot["transactions"] = balances;
}
+ else {
+ if(balances.isNull())
+ balances.resize(0);
+
+ aroot = balances;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/registerdid.cpp b/src/lib/explorer/extensions/commands/registerdid.cpp
index 08d476077..86eb59385 100644
--- a/src/lib/explorer/extensions/commands/registerdid.cpp
+++ b/src/lib/explorer/extensions/commands/registerdid.cpp
@@ -33,7 +33,7 @@ namespace commands
{
console_result registerdid::invoke(Json::Value &jv_output,
- libbitcoin::server::server_node &node)
+ libbitcoin::server::server_node &node)
{
auto &blockchain = node.chain_impl();
auto acc = blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
@@ -41,13 +41,29 @@ console_result registerdid::invoke(Json::Value &jv_output,
// check did symbol
check_did_symbol(argument_.symbol, true);
- if (blockchain.is_valid_address(argument_.symbol))
+ if (blockchain.is_valid_address(argument_.symbol)) {
throw address_invalid_exception{"symbol cannot be an address!"};
+ }
+
+ // check fee
+ if (argument_.fee < bc::min_fee_to_register_did) {
+ throw did_register_poundage_exception{
+ "register did: fee less than "
+ + std::to_string(bc::min_fee_to_register_did) + " that's "
+ + std::to_string(bc::min_fee_to_register_did / 100000000) + " ETPs"};
+ }
- if (argument_.fee < 100000000)
- throw did_register_poundage_exception{"register did fee must be at least 100000000 satoshi = 1 etp!"};
- if (!blockchain.is_valid_address(argument_.address))
+ if (argument_.percentage < bc::min_fee_percentage_to_miner || argument_.percentage > 100) {
+ throw did_register_poundage_exception{
+ "register did minimum percentage of fee to miner less than "
+ + std::to_string(bc::min_fee_percentage_to_miner)
+ + " or greater than 100."};
+ }
+
+ // check address
+ if (!blockchain.is_valid_address(argument_.address)) {
throw address_invalid_exception{"invalid address parameter!"};
+ }
if (!blockchain.get_account_address(auth_.name, argument_.address)) {
throw address_dismatch_account_exception{
@@ -78,24 +94,19 @@ console_result registerdid::invoke(Json::Value &jv_output,
{argument_.address, argument_.symbol, 0, 0, utxo_attach_type::did_register, attachment()}};
auto register_helper = registering_did(
- *this, blockchain, std::move(auth_.name), std::move(auth_.auth),
- std::move(argument_.address), std::move(argument_.symbol),
- std::move(receiver), argument_.fee,
- std::move(acc_multisig));
+ *this, blockchain, std::move(auth_.name), std::move(auth_.auth),
+ std::move(argument_.address), std::move(argument_.symbol),
+ std::move(receiver), argument_.fee, argument_.percentage,
+ std::move(acc_multisig));
register_helper.exec();
// output json
+ auto && tx = register_helper.get_transaction();
if (is_multisig_address) {
- auto && tx = register_helper.get_transaction();
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx);
- jv_output = tx_buf.str();
- // TODO support restful API format
- // jv_output["raw"] = tx_buf.str();
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx, false, true);
}
else {
- auto &&tx = register_helper.get_transaction();
jv_output = config::json_helper(get_api_version()).prop_tree(tx, true);
}
diff --git a/src/lib/explorer/extensions/commands/sendrawtx.cpp b/src/lib/explorer/extensions/commands/sendrawtx.cpp
index c6d26eff3..a7a0fb6f4 100644
--- a/src/lib/explorer/extensions/commands/sendrawtx.cpp
+++ b/src/lib/explorer/extensions/commands/sendrawtx.cpp
@@ -52,7 +52,12 @@ console_result sendrawtx::invoke(Json::Value& jv_output,
if (blockchain.broadcast_transaction(tx_))
throw tx_broadcast_exception{"broadcast transaction failure"};
- jv_output["hash"] = encode_hash(tx_.hash());
+ if (get_api_version() <= 2) {
+ jv_output["hash"] = encode_hash(tx_.hash());
+ }
+ else {
+ jv_output = encode_hash(tx_.hash());
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/signmultisigtx.cpp b/src/lib/explorer/extensions/commands/signmultisigtx.cpp
index 7fefe6a08..e072aa4eb 100644
--- a/src/lib/explorer/extensions/commands/signmultisigtx.cpp
+++ b/src/lib/explorer/extensions/commands/signmultisigtx.cpp
@@ -212,18 +212,15 @@ console_result signmultisigtx::invoke(
}
// output json
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx_);
if (get_api_version() <= 2) {
- jv_output = tx_buf.str();
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx_, false, true);
}
else {
- // TODO support restful API format
- jv_output["raw"] = tx_buf.str();
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx_, true);
}
if (option_.broadcast_flag /* TODO && fullfilled */) {
- log::trace("multisig") << "validate and broadcast multisig transaction: " << tx_buf.str();
+ log::trace("multisig") << "validate and broadcast multisig transaction." << tx_.to_string(1);
if (blockchain.validate_transaction(tx_)) {
throw tx_validate_exception{"validate transaction failure"};
diff --git a/src/lib/explorer/extensions/commands/signrawtx.cpp b/src/lib/explorer/extensions/commands/signrawtx.cpp
index 242634e9b..498a94717 100644
--- a/src/lib/explorer/extensions/commands/signrawtx.cpp
+++ b/src/lib/explorer/extensions/commands/signrawtx.cpp
@@ -100,21 +100,12 @@ console_result signrawtx::invoke(Json::Value& jv_output,
}
// get raw tx
- if (blockchain.validate_transaction(tx_))
- throw tx_validate_exception{std::string("validate transaction failure")};
-
- auto& aroot = jv_output;
- aroot["hash"] = encode_hash(tx_.hash());
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx_);
- if (get_api_version() <= 2) {
- jv_output["hex"] = tx_buf.str();
- }
- else {
- // TODO support restful API format
- jv_output["raw"] = tx_buf.str();
+ if (blockchain.validate_transaction(tx_)) {
+ throw tx_validate_exception{"validate transaction failure"};
}
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx_, true);
+
return console_result::okay;
}
diff --git a/src/lib/explorer/extensions/commands/startmining.cpp b/src/lib/explorer/extensions/commands/startmining.cpp
index 977a73eca..87ba5c2e6 100644
--- a/src/lib/explorer/extensions/commands/startmining.cpp
+++ b/src/lib/explorer/extensions/commands/startmining.cpp
@@ -54,12 +54,21 @@ console_result startmining::invoke(Json::Value& jv_output,
// get new address
const char* cmds2[]{"getnewaddress", auth_.name.c_str(), auth_.auth.c_str()};
- if (dispatch_command(3, cmds2, jv_temp, node, 2) != console_result::okay) {
+ if (dispatch_command(3, cmds2, jv_temp, node, get_api_version()) != console_result::okay) {
throw address_generate_exception(jv_temp.asString());
}
- str_addr = jv_temp["addresses"][0].asString();
- } else {
+ if (get_api_version() == 1) {
+ str_addr = jv_temp.asString();
+ }
+ else if (get_api_version() == 2) {
+ str_addr = jv_temp["addresses"][0].asString();
+ }
+ else {
+ str_addr = jv_temp[0].asString();
+ }
+ }
+ else {
blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
if (!blockchain.is_valid_address(str_addr)) {
diff --git a/src/lib/explorer/extensions/commands/submitwork.cpp b/src/lib/explorer/extensions/commands/submitwork.cpp
index 42ba6267e..337510c48 100644
--- a/src/lib/explorer/extensions/commands/submitwork.cpp
+++ b/src/lib/explorer/extensions/commands/submitwork.cpp
@@ -53,21 +53,20 @@ console_result submitwork::invoke(Json::Value& jv_output,
auto& root = jv_output;
if (ret) {
-
if (get_api_version() == 1) {
root["result"] = "true"; // boost json parser output as string, for compatible.
- } else {
+ }
+ else {
root = true;
}
-
- } else {
-
+ }
+ else {
if (get_api_version() == 1) {
root["result"] = "false"; // boost json parser output as string, for compatible.
- } else {
+ }
+ else {
root = false;
}
-
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/transfercert.cpp b/src/lib/explorer/extensions/commands/transfercert.cpp
index 8fae83b32..9c93e3afe 100644
--- a/src/lib/explorer/extensions/commands/transfercert.cpp
+++ b/src/lib/explorer/extensions/commands/transfercert.cpp
@@ -107,17 +107,13 @@ console_result transfercert::invoke (Json::Value& jv_output,
helper.exec();
- // json output
+ // json output
+ auto && tx = helper.get_transaction();
if (is_multisig_address) {
- // out rawtx for multisig cert
- auto && tx = helper.get_transaction();
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx);
- jv_output = tx_buf.str();
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx, false, true);
}
else {
- auto tx = helper.get_transaction();
- jv_output = config::json_helper(get_api_version()).prop_tree(tx, true);
+ jv_output = config::json_helper(get_api_version()).prop_tree(tx, true);
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/transfermit.cpp b/src/lib/explorer/extensions/commands/transfermit.cpp
index d645b1a5e..0ba77c180 100644
--- a/src/lib/explorer/extensions/commands/transfermit.cpp
+++ b/src/lib/explorer/extensions/commands/transfermit.cpp
@@ -85,16 +85,12 @@ console_result transfermit::invoke (Json::Value& jv_output,
helper.exec();
// json output
+ auto tx = helper.get_transaction();
if (is_multisig_address) {
- // out rawtx for multisig asset
- auto && tx = helper.get_transaction();
- std::ostringstream tx_buf;
- tx_buf << config::transaction(tx);
- jv_output = tx_buf.str();
+ jv_output = config::json_helper(get_api_version()).prop_list_of_rawtx(tx, false, true);
}
else {
- auto tx = helper.get_transaction();
- jv_output = config::json_helper(get_api_version()).prop_tree(tx, true);
+ jv_output = config::json_helper(get_api_version()).prop_tree(tx, true);
}
return console_result::okay;
diff --git a/src/lib/explorer/extensions/commands/validateaddress.cpp b/src/lib/explorer/extensions/commands/validateaddress.cpp
index 4bec72b74..194a30d08 100644
--- a/src/lib/explorer/extensions/commands/validateaddress.cpp
+++ b/src/lib/explorer/extensions/commands/validateaddress.cpp
@@ -58,10 +58,18 @@ console_result validateaddress::invoke(Json::Value& jv_output,
}
auto& jv = jv_output;
- jv["address-type"] = version_info;
- jv["test-net"] = use_testnet_rules;
- jv["is-valid"] = is_valid;
- jv["message"] = message;
+ if (get_api_version() <= 2) {
+ jv["address-type"] = version_info;
+ jv["test-net"] = use_testnet_rules;
+ jv["is-valid"] = is_valid;
+ jv["message"] = message;
+ }
+ else {
+ jv["address_type"] = version_info;
+ jv["testnet"] = use_testnet_rules;
+ jv["is_valid"] = is_valid;
+ jv["message"] = message;
+ }
return console_result::okay;
}
diff --git a/src/lib/explorer/json_helper.cpp b/src/lib/explorer/json_helper.cpp
index 79b601774..5767f6cf2 100644
--- a/src/lib/explorer/json_helper.cpp
+++ b/src/lib/explorer/json_helper.cpp
@@ -78,8 +78,14 @@ Json::Value json_helper::prop_list(const header& header)
tree["version"] += block_header.version;
tree["number"] += block_header.number;
tree["transaction_count"] += block_header.transaction_count;
- } else {
- tree["time_stamp"] = block_header.timestamp;
+ }
+ else {
+ if (version_ <= 2) {
+ tree["time_stamp"] = block_header.timestamp;
+ }
+ else {
+ tree["timestamp"] = block_header.timestamp;
+ }
tree["version"] = block_header.version;
tree["number"] = block_header.number;
tree["transaction_count"] = block_header.transaction_count;
@@ -87,17 +93,29 @@ Json::Value json_helper::prop_list(const header& header)
return tree;
}
+
Json::Value json_helper::prop_tree(const header& header)
{
- Json::Value tree;
- tree["result"] = prop_list(header);
- return tree;
+ if (version_ <= 2) {
+ Json::Value tree;
+ tree["result"] = prop_list(header);
+ return tree;
+ }
+ else {
+ return prop_list(header);
+ }
}
+
Json::Value json_helper::prop_tree(const std::vector& headers, bool json)
{
- Json::Value tree;
- tree["headers"] = prop_tree_list("header", headers, json);
- return tree;
+ if (version_ <= 2) {
+ Json::Value tree;
+ tree["headers"] = prop_tree_list("header", headers, json);
+ return tree;
+ }
+ else {
+ return prop_tree_list("header", headers, json);
+ }
}
// transfers
@@ -199,7 +217,12 @@ Json::Value json_helper::prop_tree(const chain::history::list& rows,
const payment_address& balance_address)
{
Json::Value tree;
- tree["balance"] = prop_list(rows, balance_address);
+ if (version_ <= 2) {
+ tree["balance"] = prop_list(rows, balance_address);
+ }
+ else {
+ tree = prop_list(rows, balance_address);
+ }
return tree;
}
@@ -488,9 +511,14 @@ Json::Value json_helper::prop_list(const bc::chain::asset_mit_info& mit_info, bo
Json::Value tree;
tree["height"] = mit_info.output_height;
- tree["time_stamp"] = mit_info.timestamp;
- tree["to_did"] = mit_info.to_did;
+ if (version_ <= 2) {
+ tree["time_stamp"] = mit_info.timestamp;
+ }
+ else {
+ tree["timestamp"] = mit_info.timestamp;
+ }
+ tree["to_did"] = mit_info.to_did;
tree["symbol"] = mit_info.mit.get_symbol();
tree["address"] = mit_info.mit.get_address();
tree["status"] = mit_info.mit.get_status_name();
@@ -523,14 +551,25 @@ Json::Value json_helper::prop_list(const bc::chain::account_multisig& acc_multis
if (version_ == 1 && pubkeys.isNull()) { //compatible for v1
tree["public-keys"] = "";
}
- else {
+ else if (version_ <= 2) {
tree["public-keys"] = pubkeys;
}
+ else {
+ tree["public_keys"] = pubkeys;
+ }
tree["address"] = acc_multisig.get_address();
- tree["self-publickey"] = acc_multisig.get_pub_key();
- tree["multisig-script"] = acc_multisig.get_multisig_script();
tree["description"] = acc_multisig.get_description();
+
+ if (version_ <= 2) {
+ tree["self-publickey"] = acc_multisig.get_pub_key();
+ tree["multisig-script"] = acc_multisig.get_multisig_script();
+ }
+ else {
+ tree["self_publickey"] = acc_multisig.get_pub_key();
+ tree["multisig_script"] = acc_multisig.get_multisig_script();
+ }
+
return tree;
}
@@ -655,6 +694,31 @@ Json::Value json_helper::prop_tree(const chain::points_info& points_info, bool j
// transactions
+Json::Value json_helper::prop_list_of_rawtx(const transaction& transaction, bool with_hash, bool ignore_compatibility)
+{
+ const tx_type& tx = transaction;
+ std::ostringstream sout;
+ sout << base16(tx.to_data());
+
+ Json::Value tree;
+ if (!ignore_compatibility && version_ <= 2) {
+ if (with_hash) {
+ tree["hash"] += hash256(tx.hash());
+ }
+ tree["hex"] = sout.str();
+ }
+ else {
+ if (with_hash) {
+ tree["hash"] += hash256(tx.hash());
+ tree["rawtx"] = sout.str();
+ }
+ else {
+ tree = sout.str();
+ }
+ }
+ return tree;
+}
+
Json::Value json_helper::prop_list(const transaction& transaction, bool json)
{
const tx_type& tx = transaction;
@@ -667,13 +731,20 @@ Json::Value json_helper::prop_list(const transaction& transaction, bool json)
tree["outputs"] = prop_tree(tx.outputs, json); // only used for output to add new field "index"
tree["version"] += tx.version;
return tree;
- }else {
+ }
+ else {
std::ostringstream sout;
sout << base16(tx.to_data());
- tree["raw"] = sout.str();
+ if (version_ <= 2) {
+ tree["raw"] = sout.str();
+ }
+ else {
+ tree = sout.str();
+ }
}
return tree;
}
+
Json::Value json_helper::prop_list(const transaction& transaction, uint64_t tx_height, bool json)
{
const tx_type& tx = transaction;
@@ -694,16 +765,26 @@ Json::Value json_helper::prop_list(const transaction& transaction, uint64_t tx_h
Json::Value json_helper::prop_tree(const transaction& transaction, bool json)
{
- Json::Value tree;
- tree["transaction"] = prop_list(transaction, json);
- return tree;
+ if (version_ <= 2) {
+ Json::Value tree;
+ tree["transaction"] = prop_list(transaction, json);
+ return tree;
+ }
+ else {
+ return prop_list(transaction, json);
+ }
}
+
Json::Value json_helper::prop_tree(const std::vector& transactions, bool json)
{
- Json::Value tree;
- tree["transactions"] =
- prop_tree_list_of_lists("transaction", transactions, json);
- return tree;
+ if (version_ <= 2) {
+ Json::Value tree;
+ tree["transactions"] = prop_tree_list_of_lists("transaction", transactions, json);
+ return tree;
+ }
+ else {
+ return prop_tree_list_of_lists("transaction", transactions, json);
+ }
}
// wrapper
@@ -864,20 +945,42 @@ Json::Value json_helper::prop_tree(const block& block, bool json, bool tx_json)
Json::Value tree;
if (json) {
- tree["header"] = prop_tree(block.header);
std::vector txs;
txs.resize(block.transactions.size());
std::copy(block.transactions.begin(), block.transactions.end(), txs.begin());
- tree["txs"] = prop_tree(txs, tx_json);
- } else {
+ if (version_ <= 2) {
+ tree["header"] = prop_tree(block.header);
+ tree["txs"] = prop_tree(txs, tx_json);
+ }
+ else {
+ tree = prop_tree(block.header);
+ tree["transactions"] = prop_tree(txs, tx_json);
+ }
+ }
+ else {
std::ostringstream sout;
sout << encode_base16(block.to_data());
- tree["raw"] = sout.str();
+ if (version_ <= 2) {
+ tree["raw"] = sout.str();
+ }
+ else {
+ tree = sout.str();
+ }
}
return tree;
}
+Json::Value json_helper::prop_list(const account_info& acc)
+{
+ Json::Value tree;
+ tree["name"] = std::get<0>(acc);
+ if (std::get<1>(acc).size() > 0) tree["mnemonic"] = std::get<1>(acc);
+ tree["addresses"] = std::get<2>(acc);
+
+ return tree;
+}
+
} // namespace config
} // namespace explorer
} // namespace libbitcoin
diff --git a/src/lib/network/hosts.cpp b/src/lib/network/hosts.cpp
index 72c9efe3d..697663f09 100644
--- a/src/lib/network/hosts.cpp
+++ b/src/lib/network/hosts.cpp
@@ -297,7 +297,14 @@ code hosts::clear()
mutex_.unlock_upgrade_and_lock();
- backup_ = std::move( buffer_ );
+
+ // if the buffer is already moved to backup, call this function again will lead to the loss of backup.
+ // backup_ = std::move( buffer_ );
+ for (auto &host : buffer_) {
+ backup_.insert(host);
+ }
+ buffer_.clear();
+
mutex_.unlock();
///////////////////////////////////////////////////////////////////////////
@@ -322,6 +329,17 @@ code hosts::after_reseeding()
log::warning(LOG_NETWORK) << "Reseeding finished, but got address list: " << buffer_.size() << ", less than seed count: "
<< seed_count << ", roll back the hosts cache.";
buffer_ = std::move(backup_);
+ } else {
+ // filter inactive hosts
+ for (auto &host : inactive_) {
+ auto iter = buffer_.find(host);
+ if (iter != buffer_.end()) {
+ buffer_.erase(iter);
+ }
+ }
+
+ // clear the backup
+ backup_.clear();
}
log::debug(LOG_NETWORK) << "Reseeding finished, and got addresses of count: " << buffer_.size();
diff --git a/src/lib/network/message_subscriber.cpp b/src/lib/network/message_subscriber.cpp
index acdf9958b..f0f98d06e 100644
--- a/src/lib/network/message_subscriber.cpp
+++ b/src/lib/network/message_subscriber.cpp
@@ -53,7 +53,6 @@ using namespace message;
message_subscriber::message_subscriber(threadpool& pool)
: INITIALIZE_SUBSCRIBER(pool, address),
- INITIALIZE_SUBSCRIBER(pool, alert),
INITIALIZE_SUBSCRIBER(pool, block_message),
INITIALIZE_SUBSCRIBER(pool, block_transactions),
INITIALIZE_SUBSCRIBER(pool, compact_block),
@@ -85,7 +84,6 @@ message_subscriber::message_subscriber(threadpool& pool)
void message_subscriber::broadcast(const code& ec)
{
RELAY_CODE(ec, address);
- RELAY_CODE(ec, alert);
RELAY_CODE(ec, block_message);
RELAY_CODE(ec, block_transactions);
RELAY_CODE(ec, compact_block);
@@ -119,7 +117,6 @@ code message_subscriber::load(message_type type, uint32_t version,
switch (type)
{
CASE_RELAY_MESSAGE(stream, version, address);
- CASE_RELAY_MESSAGE(stream, version, alert);
CASE_HANDLE_MESSAGE(stream, version, block_message);
CASE_RELAY_MESSAGE(stream, version, block_transactions);
CASE_RELAY_MESSAGE(stream, version, compact_block);
@@ -154,7 +151,6 @@ code message_subscriber::load(message_type type, uint32_t version,
void message_subscriber::start()
{
START_SUBSCRIBER(address);
- START_SUBSCRIBER(alert);
START_SUBSCRIBER(block_message);
START_SUBSCRIBER(block_transactions);
START_SUBSCRIBER(compact_block);
@@ -185,7 +181,6 @@ void message_subscriber::start()
void message_subscriber::stop()
{
STOP_SUBSCRIBER(address);
- STOP_SUBSCRIBER(alert);
STOP_SUBSCRIBER(block_message);
STOP_SUBSCRIBER(block_transactions);
STOP_SUBSCRIBER(compact_block);
diff --git a/src/lib/network/sessions/session_outbound.cpp b/src/lib/network/sessions/session_outbound.cpp
index e1d1ce171..603e105c1 100644
--- a/src/lib/network/sessions/session_outbound.cpp
+++ b/src/lib/network/sessions/session_outbound.cpp
@@ -136,13 +136,14 @@ void session_outbound::delay_reseeding()
auto pThis = shared_from_this();
auto action = [this, pThis](){
const int counter = outbound_counter;
- in_reseeding = false;
if (counter > 1) {
log::debug(LOG_NETWORK) << "outbound channel counter recovered to [" << counter << "], re-seeding is canceled!";
+ in_reseeding = false;
return;
}
log::debug(LOG_NETWORK) << "start re-seeding!";
network__.restart_seeding();
+ in_reseeding = false;
};
pool_.service().post(action);
});
diff --git a/src/mvs-cli/main.cpp b/src/mvs-cli/main.cpp
index 5e32e63d7..273a309b8 100644
--- a/src/mvs-cli/main.cpp
+++ b/src/mvs-cli/main.cpp
@@ -66,7 +66,7 @@ int bc::main(int argc, char* argv[])
bc::set_utf8_stdout();
auto work_path = bc::default_data_path();
auto&& config_file = work_path / "mvs.conf";
- std::string url{"127.0.0.1:8820/rpc/v2"};
+ std::string url{"127.0.0.1:8820/rpc/v3"};
if (boost::filesystem::exists(config_file)) {
const auto& path = config_file.string();
@@ -91,7 +91,7 @@ int bc::main(int argc, char* argv[])
if (tmp.find("0.0.0.0") == 0) {
tmp.replace(0, 7, "127.0.0.1");
}
- url = tmp + "/rpc/v2";
+ url = tmp + "/rpc/v3";
}
}
}
diff --git a/src/mvsd/mgbubble/HttpServ.cpp b/src/mvsd/mgbubble/HttpServ.cpp
index 70f1590ac..3d909226c 100644
--- a/src/mvsd/mgbubble/HttpServ.cpp
+++ b/src/mvsd/mgbubble/HttpServ.cpp
@@ -25,7 +25,7 @@
#include
#include
-namespace mgbubble{
+namespace mgbubble {
thread_local OStream HttpServ::out_;
thread_local Tokeniser<'/'> HttpServ::uri_;
@@ -37,19 +37,19 @@ void HttpServ::reset(HttpMessage& data) noexcept
const auto method = data.method();
if (method == "GET") {
- state_ |= MethodGet;
+ state_ |= MethodGet;
} else if (method == "POST") {
- state_ |= MethodPost;
+ state_ |= MethodPost;
} else if (method == "PUT") {
- state_ |= MethodPut;
+ state_ |= MethodPut;
} else if (method == "DELETE") {
- state_ |= MethodDelete;
+ state_ |= MethodDelete;
}
auto uri = data.uri();
// Remove leading slash.
if (uri.front() == '/') {
- uri.remove_prefix(1);
+ uri.remove_prefix(1);
}
uri_.reset(uri);
}
@@ -62,7 +62,7 @@ void HttpServ::rpc_request(mg_connection& nc, HttpMessage data, uint8_t rpc_vers
out_.reset(200, "OK");
const vector api20_ver_list = {2, 3};
- auto checkAPIVer = [](const vector &api_ver_list, const uint8_t &rpc_version){
+ auto checkAPIVer = [](const vector &api_ver_list, const uint8_t &rpc_version) {
return find(api_ver_list.begin(), api_ver_list.end(), rpc_version) != api_ver_list.end();
};
try {
@@ -71,7 +71,7 @@ void HttpServ::rpc_request(mg_connection& nc, HttpMessage data, uint8_t rpc_vers
Json::Value jv_output;
auto retcode = explorer::dispatch_command(data.argc(), const_cast(data.argv()),
- jv_output, node_, rpc_version);
+ jv_output, node_, rpc_version);
if (retcode == console_result::failure) { // only orignal command
if (rpc_version == 1 && !jv_output.isObject() && !jv_output.isArray()) {
@@ -133,7 +133,7 @@ void HttpServ::ws_request(mg_connection& nc, WebsocketMessage ws)
{
Json::Value jv_output;
- try{
+ try {
ws.data_to_arg();
console_result retcode = explorer::dispatch_command(ws.argc(), const_cast(ws.argv()), jv_output, node_);
@@ -171,7 +171,7 @@ void HttpServ::spawn_to_mongoose(const std::function&& handler)
void HttpServ::run() {
log::info(LOG_HTTP) << "Http Service listen on " << node_.server_settings().mongoose_listen;
- node_.subscribe_stop([this](const libbitcoin::code& ec) { stop(); });
+ node_.subscribe_stop([this](const libbitcoin::code & ec) { stop(); });
base::run();
@@ -188,8 +188,9 @@ void HttpServ::on_http_req_handler(struct mg_connection& nc, http_message& msg)
}
else if ((mg_ncasecmp(msg.uri.p, "/rpc", 4) == 0) || (mg_ncasecmp(msg.uri.p, "/rpc/", 5) == 0)) {
rpc_request(nc, HttpMessage(&msg), 1); //v1 rpc
- } else {
- std::shared_ptr con(&nc, [](struct mg_connection* ptr) { (void)(ptr); });
+ }
+ else {
+ std::shared_ptr con(&nc, [](struct mg_connection * ptr) { (void)(ptr); });
serve_http_static(nc, msg);
}
}
@@ -207,7 +208,7 @@ void HttpServ::on_notify_handler(struct mg_connection& nc, struct mg_event& ev)
void HttpServ::on_ws_handshake_done_handler(struct mg_connection& nc)
{
- std::shared_ptr con(&nc, [](struct mg_connection* ptr) { (void)(ptr); });
+ std::shared_ptr con(&nc, [](struct mg_connection * ptr) { (void)(ptr); });
send_frame(nc, "connected", 9);
}
diff --git a/src/mvsd/mgbubble/Mongoose.cpp b/src/mvsd/mgbubble/Mongoose.cpp
index 80ac14398..78eaa63cb 100644
--- a/src/mvsd/mgbubble/Mongoose.cpp
+++ b/src/mvsd/mgbubble/Mongoose.cpp
@@ -35,7 +35,7 @@ void HttpMessage::data_to_arg(uint8_t rpc_version) {
}
argc_ = i;
};
-
+
Json::Reader reader;
Json::Value root;
const char* begin = body().data();
@@ -62,10 +62,10 @@ void HttpMessage::data_to_arg(uint8_t rpc_version) {
vargv_.emplace_back(param.asString());
}
} else {
- /* ***************** /rpc/v2 **********************
+ /* ***************** /rpc/v2 or /rpc/v3 **********************
* application/json
* {
- * "method":"xxx",
+ * "method":"xxx",
* "params":[
* {
* k1:v1, ==> Command Option
@@ -77,7 +77,12 @@ void HttpMessage::data_to_arg(uint8_t rpc_version) {
* }
* ******************************************/
- if (root["jsonrpc"].asString() != "2.0") {
+ const vector api20_ver_list = {"2.0", "3.0"};
+ auto checkAPIVer = [](const vector &api_ver_list, const std::string &rpc_version){
+ return find(api_ver_list.begin(), api_ver_list.end(), rpc_version) != api_ver_list.end();
+ };
+
+ if (!checkAPIVer(api20_ver_list, root["jsonrpc"].asString())) {
throw libbitcoin::explorer::jsonrpc_invalid_request();
}
@@ -158,8 +163,8 @@ void WebsocketMessage::data_to_arg(uint8_t api_version) {
void ToCommandArg::add_arg(std::string&& outside)
{
- vargv_.push_back(outside);
- argc_++;
+ vargv_.push_back(outside);
+ argc_++;
}
} // mgbubble
diff --git a/src/mvsd/mgbubble/utility/Stream_buf.cpp b/src/mvsd/mgbubble/utility/Stream_buf.cpp
index 29df1c984..bea3e53aa 100644
--- a/src/mvsd/mgbubble/utility/Stream_buf.cpp
+++ b/src/mvsd/mgbubble/utility/Stream_buf.cpp
@@ -23,7 +23,7 @@ using namespace std;
namespace mgbubble {
-StreamBuf::StreamBuf(mbuf& buf) throw(bad_alloc) : buf_(buf)
+StreamBuf::StreamBuf(mbuf& buf) : buf_(buf)
{
if (!buf_.buf) {
// Pre-allocate buffer.
diff --git a/test/test-rpc-v3/HTMLTestRunner.py b/test/test-rpc-v3/HTMLTestRunner.py
new file mode 100644
index 000000000..0439bf488
--- /dev/null
+++ b/test/test-rpc-v3/HTMLTestRunner.py
@@ -0,0 +1,824 @@
+"""
+A TestRunner for use with the Python unit testing framework. It
+generates a HTML report to show the result at a glance.
+
+The simplest way to use this is to invoke its main method. E.g.
+
+ import unittest
+ import HTMLTestRunner
+
+ ... define your tests ...
+
+ if __name__ == '__main__':
+ HTMLTestRunner.main()
+
+
+For more customization options, instantiates a HTMLTestRunner object.
+HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.
+
+ # output to a file
+ fp = file('my_report.html', 'wb')
+ runner = HTMLTestRunner.HTMLTestRunner(
+ stream=fp,
+ title='My unit test',
+ description='This demonstrates the report output by HTMLTestRunner.'
+ )
+
+ # Use an external stylesheet.
+ # See the Template_mixin class for more customizable options
+ runner.STYLESHEET_TMPL = ''
+
+ # run the test
+ runner.run(my_test_suite)
+
+
+------------------------------------------------------------------------
+Copyright (c) 2004-2007, Wai Yip Tung
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name Wai Yip Tung nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+
+# URL: http://tungwaiyip.info/software/HTMLTestRunner.html
+
+__author__ = "Wai Yip Tung"
+__version__ = "0.8.2"
+
+
+"""
+Change History
+
+Version 0.8.2
+* Show output inline instead of popup window (Viorel Lupu).
+
+Version in 0.8.1
+* Validated XHTML (Wolfgang Borgert).
+* Added description of test classes and test cases.
+
+Version in 0.8.0
+* Define Template_mixin class for customization.
+* Workaround a IE 6 bug that it does not treat
+
+%(heading)s
+%(report)s
+%(ending)s
+
+