From 09f23dade8431f2deee919669e7f6a1716e3cd03 Mon Sep 17 00:00:00 2001 From: serkixenos Date: Mon, 26 Apr 2021 13:05:27 +0200 Subject: [PATCH] Withdrawal object creation --- .../peerplays_sidechain/CMakeLists.txt | 1 + .../peerplays_sidechain/hive/asset.cpp | 263 +++++++++++++++ .../peerplays_sidechain/hive/asset_symbol.cpp | 300 ++++++++++++++++++ .../peerplays_sidechain/hive/transaction.cpp | 10 +- .../peerplays_sidechain/hive/asset.hpp | 20 ++ .../peerplays_sidechain/hive/asset_symbol.hpp | 245 ++++++++++++++ .../hive/hive_operations.hpp | 11 +- .../peerplays_sidechain/hive/types.hpp | 2 +- .../peerplays_sidechain/hive/types_fwd.hpp | 90 ++++++ .../sidechain_net_handler.cpp | 53 +++- .../sidechain_net_handler_hive.cpp | 108 +++++++ 11 files changed, 1085 insertions(+), 18 deletions(-) create mode 100644 libraries/plugins/peerplays_sidechain/hive/asset.cpp create mode 100644 libraries/plugins/peerplays_sidechain/hive/asset_symbol.cpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset_symbol.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types_fwd.hpp diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 60eb03c8..48dd44f1 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -16,6 +16,7 @@ add_library( peerplays_sidechain bitcoin/sign_bitcoin_transaction.cpp common/rpc_client.cpp common/utils.cpp + hive/asset.cpp hive/operations.cpp hive/transaction.cpp hive/types.cpp diff --git a/libraries/plugins/peerplays_sidechain/hive/asset.cpp b/libraries/plugins/peerplays_sidechain/hive/asset.cpp new file mode 100644 index 00000000..e27c0494 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/hive/asset.cpp @@ -0,0 +1,263 @@ +#include + +#include + +#include +#include + +#define ASSET_AMOUNT_KEY "amount" +#define ASSET_PRECISION_KEY "precision" +#define ASSET_NAI_KEY "nai" + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +std::string asset_symbol_type::to_string() const { + return fc::json::to_string(fc::variant(*this, 5)); +} + +asset_symbol_type asset_symbol_type::from_string(const std::string &str) { + return fc::json::from_string(str).as(5); +} + +void asset_symbol_type::to_nai_string(char *buf) const { + static_assert(HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH >= 12, "This code will overflow a short buffer"); + uint32_t x = to_nai(); + buf[11] = '\0'; + buf[10] = ((x % 10) + '0'); + x /= 10; + buf[9] = ((x % 10) + '0'); + x /= 10; + buf[8] = ((x % 10) + '0'); + x /= 10; + buf[7] = ((x % 10) + '0'); + x /= 10; + buf[6] = ((x % 10) + '0'); + x /= 10; + buf[5] = ((x % 10) + '0'); + x /= 10; + buf[4] = ((x % 10) + '0'); + x /= 10; + buf[3] = ((x % 10) + '0'); + x /= 10; + buf[2] = ((x) + '0'); + buf[1] = '@'; + buf[0] = '@'; +} + +asset_symbol_type asset_symbol_type::from_nai_string(const char *p, uint8_t decimal_places) { + try { + FC_ASSERT(p != nullptr, "NAI string cannot be a null"); + FC_ASSERT(std::strlen(p) == HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH - 1, "Incorrect NAI string length"); + FC_ASSERT(p[0] == '@' && p[1] == '@', "Invalid NAI string prefix"); + uint32_t nai = boost::lexical_cast(p + 2); + return asset_symbol_type::from_nai(nai, decimal_places); + } + FC_CAPTURE_AND_RETHROW(); +} + +// Highly optimized implementation of Damm algorithm +// https://en.wikipedia.org/wiki/Damm_algorithm +uint8_t asset_symbol_type::damm_checksum_8digit(uint32_t value) { + FC_ASSERT(value < 100000000); + + const uint8_t t[] = { + 0, 30, 10, 70, 50, 90, 80, 60, 40, 20, + 70, 0, 90, 20, 10, 50, 40, 80, 60, 30, + 40, 20, 0, 60, 80, 70, 10, 30, 50, 90, + 10, 70, 50, 0, 90, 80, 30, 40, 20, 60, + 60, 10, 20, 30, 0, 40, 50, 90, 70, 80, + 30, 60, 70, 40, 20, 0, 90, 50, 80, 10, + 50, 80, 60, 90, 70, 20, 0, 10, 30, 40, + 80, 90, 40, 50, 30, 60, 20, 0, 10, 70, + 90, 40, 30, 80, 60, 10, 70, 20, 0, 50, + 20, 50, 80, 10, 40, 30, 60, 70, 90, 0}; + + uint32_t q0 = value / 10; + uint32_t d0 = value % 10; + uint32_t q1 = q0 / 10; + uint32_t d1 = q0 % 10; + uint32_t q2 = q1 / 10; + uint32_t d2 = q1 % 10; + uint32_t q3 = q2 / 10; + uint32_t d3 = q2 % 10; + uint32_t q4 = q3 / 10; + uint32_t d4 = q3 % 10; + uint32_t q5 = q4 / 10; + uint32_t d5 = q4 % 10; + uint32_t d6 = q5 % 10; + uint32_t d7 = q5 / 10; + + uint8_t x = t[d7]; + x = t[x + d6]; + x = t[x + d5]; + x = t[x + d4]; + x = t[x + d3]; + x = t[x + d2]; + x = t[x + d1]; + x = t[x + d0]; + return x / 10; +} + +uint32_t asset_symbol_type::asset_num_from_nai(uint32_t nai, uint8_t decimal_places) { + // Can be replaced with some clever bitshifting + uint32_t nai_check_digit = nai % 10; + uint32_t nai_data_digits = nai / 10; + + FC_ASSERT((nai_data_digits >= SMT_MIN_NAI) & (nai_data_digits <= SMT_MAX_NAI), "NAI out of range"); + FC_ASSERT(nai_check_digit == damm_checksum_8digit(nai_data_digits), "Invalid check digit"); + + switch (nai_data_digits) { + case HIVE_NAI_HIVE: + FC_ASSERT(decimal_places == HIVE_PRECISION_HIVE); + return HIVE_ASSET_NUM_HIVE; + case HIVE_NAI_HBD: + FC_ASSERT(decimal_places == HIVE_PRECISION_HBD); + return HIVE_ASSET_NUM_HBD; + case HIVE_NAI_VESTS: + FC_ASSERT(decimal_places == HIVE_PRECISION_VESTS); + return HIVE_ASSET_NUM_VESTS; + default: + FC_ASSERT(decimal_places <= HIVE_ASSET_MAX_DECIMALS, "Invalid decimal_places"); + return (nai_data_digits << HIVE_NAI_SHIFT) | SMT_ASSET_NUM_CONTROL_MASK | decimal_places; + } +} + +uint32_t asset_symbol_type::to_nai() const { + uint32_t nai_data_digits = 0; + + // Can be replaced with some clever bitshifting + switch (asset_num) { + case HIVE_ASSET_NUM_HIVE: + nai_data_digits = HIVE_NAI_HIVE; + break; + case HIVE_ASSET_NUM_HBD: + nai_data_digits = HIVE_NAI_HBD; + break; + case HIVE_ASSET_NUM_VESTS: + nai_data_digits = HIVE_NAI_VESTS; + break; + default: + FC_ASSERT(space() == smt_nai_space); + nai_data_digits = (asset_num >> HIVE_NAI_SHIFT); + } + + uint32_t nai_check_digit = damm_checksum_8digit(nai_data_digits); + return nai_data_digits * 10 + nai_check_digit; +} + +bool asset_symbol_type::is_vesting() const { + switch (space()) { + case legacy_space: { + switch (asset_num) { + case HIVE_ASSET_NUM_HIVE: + return false; + case HIVE_ASSET_NUM_HBD: + // HBD is certainly liquid. + return false; + case HIVE_ASSET_NUM_VESTS: + return true; + default: + FC_ASSERT(false, "Unknown asset symbol"); + } + } + case smt_nai_space: + // 6th bit of asset_num is used as vesting/liquid variant indicator. + return asset_num & SMT_ASSET_NUM_VESTING_MASK; + default: + FC_ASSERT(false, "Unknown asset symbol"); + } +} + +asset_symbol_type asset_symbol_type::get_paired_symbol() const { + switch (space()) { + case legacy_space: { + switch (asset_num) { + case HIVE_ASSET_NUM_HIVE: + return from_asset_num(HIVE_ASSET_NUM_VESTS); + case HIVE_ASSET_NUM_HBD: + return *this; + case HIVE_ASSET_NUM_VESTS: + return from_asset_num(HIVE_ASSET_NUM_HIVE); + default: + FC_ASSERT(false, "Unknown asset symbol"); + } + } + case smt_nai_space: { + // Toggle 6th bit of this asset_num. + auto paired_asset_num = asset_num ^ (SMT_ASSET_NUM_VESTING_MASK); + return from_asset_num(paired_asset_num); + } + default: + FC_ASSERT(false, "Unknown asset symbol"); + } +} + +asset_symbol_type::asset_symbol_space asset_symbol_type::space() const { + asset_symbol_type::asset_symbol_space s = legacy_space; + switch (asset_num) { + case HIVE_ASSET_NUM_HIVE: + case HIVE_ASSET_NUM_HBD: + case HIVE_ASSET_NUM_VESTS: + s = legacy_space; + break; + default: + s = smt_nai_space; + } + return s; +} + +void asset_symbol_type::validate() const { + switch (asset_num) { + case HIVE_ASSET_NUM_HIVE: + case HIVE_ASSET_NUM_HBD: + case HIVE_ASSET_NUM_VESTS: + break; + default: { + uint32_t nai_data_digits = (asset_num >> HIVE_NAI_SHIFT); + uint32_t nai_1bit = (asset_num & SMT_ASSET_NUM_CONTROL_MASK); + uint32_t nai_decimal_places = (asset_num & SMT_ASSET_NUM_PRECISION_MASK); + FC_ASSERT((nai_data_digits >= SMT_MIN_NAI) & + (nai_data_digits <= SMT_MAX_NAI) & + (nai_1bit == SMT_ASSET_NUM_CONTROL_MASK) & + (nai_decimal_places <= HIVE_ASSET_MAX_DECIMALS), + "Cannot determine space for asset ${n}", ("n", asset_num)); + } + } + // this assert is duplicated by above code in all cases + // FC_ASSERT( decimals() <= HIVE_ASSET_MAX_DECIMALS ); +} + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { + +void to_variant(const graphene::peerplays_sidechain::hive::asset &var, fc::variant &vo, uint32_t max_depth) { + try { + variant v = mutable_variant_object(ASSET_AMOUNT_KEY, boost::lexical_cast(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(var.symbol.decimals()))(ASSET_NAI_KEY, var.symbol.to_nai_string()); + vo = v; + } + FC_CAPTURE_AND_RETHROW() +} + +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::asset &vo, uint32_t max_depth) { + try { + FC_ASSERT(var.is_object(), "Asset has to be treated as object."); + + const auto &v_object = var.get_object(); + + FC_ASSERT(v_object.contains(ASSET_AMOUNT_KEY), "Amount field doesn't exist."); + FC_ASSERT(v_object[ASSET_AMOUNT_KEY].is_string(), "Expected a string type for value '${key}'.", ("key", ASSET_AMOUNT_KEY)); + vo.amount = boost::lexical_cast(v_object[ASSET_AMOUNT_KEY].as(max_depth)); + FC_ASSERT(vo.amount >= 0, "Asset amount cannot be negative"); + + FC_ASSERT(v_object.contains(ASSET_PRECISION_KEY), "Precision field doesn't exist."); + FC_ASSERT(v_object[ASSET_PRECISION_KEY].is_uint64(), "Expected an unsigned integer type for value '${key}'.", ("key", ASSET_PRECISION_KEY)); + + FC_ASSERT(v_object.contains(ASSET_NAI_KEY), "NAI field doesn't exist."); + FC_ASSERT(v_object[ASSET_NAI_KEY].is_string(), "Expected a string type for value '${key}'.", ("key", ASSET_NAI_KEY)); + + vo.symbol = graphene::peerplays_sidechain::hive::asset_symbol_type::from_nai_string(v_object[ASSET_NAI_KEY].as(max_depth).c_str(), v_object[ASSET_PRECISION_KEY].as(max_depth)); + } + FC_CAPTURE_AND_RETHROW() +} +} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/hive/asset_symbol.cpp b/libraries/plugins/peerplays_sidechain/hive/asset_symbol.cpp new file mode 100644 index 00000000..a44b9138 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/hive/asset_symbol.cpp @@ -0,0 +1,300 @@ +//#include +// +//#include +// +//namespace graphene { namespace peerplays_sidechain { namespace hive { +// +//std::string asset_symbol_type::to_string() const { +// return fc::json::to_string(fc::variant(*this, 5)); +//} +// +//asset_symbol_type asset_symbol_type::from_string(const std::string &str) { +// return fc::json::from_string(str).as(5); +//} +// +//void asset_symbol_type::to_nai_string(char *buf) const { +// static_assert(HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH >= 12, "This code will overflow a short buffer"); +// uint32_t x = to_nai(); +// buf[11] = '\0'; +// buf[10] = ((x % 10) + '0'); +// x /= 10; +// buf[9] = ((x % 10) + '0'); +// x /= 10; +// buf[8] = ((x % 10) + '0'); +// x /= 10; +// buf[7] = ((x % 10) + '0'); +// x /= 10; +// buf[6] = ((x % 10) + '0'); +// x /= 10; +// buf[5] = ((x % 10) + '0'); +// x /= 10; +// buf[4] = ((x % 10) + '0'); +// x /= 10; +// buf[3] = ((x % 10) + '0'); +// x /= 10; +// buf[2] = ((x) + '0'); +// buf[1] = '@'; +// buf[0] = '@'; +//} +// +//asset_symbol_type asset_symbol_type::from_nai_string(const char *p, uint8_t decimal_places) { +// try { +// FC_ASSERT(p != nullptr, "NAI string cannot be a null"); +// FC_ASSERT(std::strlen(p) == HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH - 1, "Incorrect NAI string length"); +// FC_ASSERT(p[0] == '@' && p[1] == '@', "Invalid NAI string prefix"); +// uint32_t nai = boost::lexical_cast(p + 2); +// return asset_symbol_type::from_nai(nai, decimal_places); +// } +// FC_CAPTURE_AND_RETHROW(); +//} +// +//// Highly optimized implementation of Damm algorithm +//// https://en.wikipedia.org/wiki/Damm_algorithm +//uint8_t asset_symbol_type::damm_checksum_8digit(uint32_t value) { +// FC_ASSERT(value < 100000000); +// +// const uint8_t t[] = { +// 0, 30, 10, 70, 50, 90, 80, 60, 40, 20, +// 70, 0, 90, 20, 10, 50, 40, 80, 60, 30, +// 40, 20, 0, 60, 80, 70, 10, 30, 50, 90, +// 10, 70, 50, 0, 90, 80, 30, 40, 20, 60, +// 60, 10, 20, 30, 0, 40, 50, 90, 70, 80, +// 30, 60, 70, 40, 20, 0, 90, 50, 80, 10, +// 50, 80, 60, 90, 70, 20, 0, 10, 30, 40, +// 80, 90, 40, 50, 30, 60, 20, 0, 10, 70, +// 90, 40, 30, 80, 60, 10, 70, 20, 0, 50, +// 20, 50, 80, 10, 40, 30, 60, 70, 90, 0}; +// +// uint32_t q0 = value / 10; +// uint32_t d0 = value % 10; +// uint32_t q1 = q0 / 10; +// uint32_t d1 = q0 % 10; +// uint32_t q2 = q1 / 10; +// uint32_t d2 = q1 % 10; +// uint32_t q3 = q2 / 10; +// uint32_t d3 = q2 % 10; +// uint32_t q4 = q3 / 10; +// uint32_t d4 = q3 % 10; +// uint32_t q5 = q4 / 10; +// uint32_t d5 = q4 % 10; +// uint32_t d6 = q5 % 10; +// uint32_t d7 = q5 / 10; +// +// uint8_t x = t[d7]; +// x = t[x + d6]; +// x = t[x + d5]; +// x = t[x + d4]; +// x = t[x + d3]; +// x = t[x + d2]; +// x = t[x + d1]; +// x = t[x + d0]; +// return x / 10; +//} +// +//uint32_t asset_symbol_type::asset_num_from_nai(uint32_t nai, uint8_t decimal_places) { +// // Can be replaced with some clever bitshifting +// uint32_t nai_check_digit = nai % 10; +// uint32_t nai_data_digits = nai / 10; +// +// FC_ASSERT((nai_data_digits >= SMT_MIN_NAI) & (nai_data_digits <= SMT_MAX_NAI), "NAI out of range"); +// FC_ASSERT(nai_check_digit == damm_checksum_8digit(nai_data_digits), "Invalid check digit"); +// +// switch (nai_data_digits) { +// case HIVE_NAI_HIVE: +// FC_ASSERT(decimal_places == HIVE_PRECISION_HIVE); +// return HIVE_ASSET_NUM_HIVE; +// case HIVE_NAI_HBD: +// FC_ASSERT(decimal_places == HIVE_PRECISION_HBD); +// return HIVE_ASSET_NUM_HBD; +// case HIVE_NAI_VESTS: +// FC_ASSERT(decimal_places == HIVE_PRECISION_VESTS); +// return HIVE_ASSET_NUM_VESTS; +// default: +// FC_ASSERT(decimal_places <= HIVE_ASSET_MAX_DECIMALS, "Invalid decimal_places"); +// return (nai_data_digits << HIVE_NAI_SHIFT) | SMT_ASSET_NUM_CONTROL_MASK | decimal_places; +// } +//} +// +//uint32_t asset_symbol_type::to_nai() const { +// uint32_t nai_data_digits = 0; +// +// // Can be replaced with some clever bitshifting +// switch (asset_num) { +// case HIVE_ASSET_NUM_HIVE: +// nai_data_digits = HIVE_NAI_HIVE; +// break; +// case HIVE_ASSET_NUM_HBD: +// nai_data_digits = HIVE_NAI_HBD; +// break; +// case HIVE_ASSET_NUM_VESTS: +// nai_data_digits = HIVE_NAI_VESTS; +// break; +// default: +// FC_ASSERT(space() == smt_nai_space); +// nai_data_digits = (asset_num >> HIVE_NAI_SHIFT); +// } +// +// uint32_t nai_check_digit = damm_checksum_8digit(nai_data_digits); +// return nai_data_digits * 10 + nai_check_digit; +//} +// +//bool asset_symbol_type::is_vesting() const { +// switch (space()) { +// case legacy_space: { +// switch (asset_num) { +// case HIVE_ASSET_NUM_HIVE: +// return false; +// case HIVE_ASSET_NUM_HBD: +// // HBD is certainly liquid. +// return false; +// case HIVE_ASSET_NUM_VESTS: +// return true; +// default: +// FC_ASSERT(false, "Unknown asset symbol"); +// } +// } +// case smt_nai_space: +// // 6th bit of asset_num is used as vesting/liquid variant indicator. +// return asset_num & SMT_ASSET_NUM_VESTING_MASK; +// default: +// FC_ASSERT(false, "Unknown asset symbol"); +// } +//} +// +//asset_symbol_type asset_symbol_type::get_paired_symbol() const { +// switch (space()) { +// case legacy_space: { +// switch (asset_num) { +// case HIVE_ASSET_NUM_HIVE: +// return from_asset_num(HIVE_ASSET_NUM_VESTS); +// case HIVE_ASSET_NUM_HBD: +// return *this; +// case HIVE_ASSET_NUM_VESTS: +// return from_asset_num(HIVE_ASSET_NUM_HIVE); +// default: +// FC_ASSERT(false, "Unknown asset symbol"); +// } +// } +// case smt_nai_space: { +// // Toggle 6th bit of this asset_num. +// auto paired_asset_num = asset_num ^ (SMT_ASSET_NUM_VESTING_MASK); +// return from_asset_num(paired_asset_num); +// } +// default: +// FC_ASSERT(false, "Unknown asset symbol"); +// } +//} +// +//asset_symbol_type::asset_symbol_space asset_symbol_type::space() const { +// asset_symbol_type::asset_symbol_space s = legacy_space; +// switch (asset_num) { +// case HIVE_ASSET_NUM_HIVE: +// case HIVE_ASSET_NUM_HBD: +// case HIVE_ASSET_NUM_VESTS: +// s = legacy_space; +// break; +// default: +// s = smt_nai_space; +// } +// return s; +//} +// +//void asset_symbol_type::validate() const { +// switch (asset_num) { +// case HIVE_ASSET_NUM_HIVE: +// case HIVE_ASSET_NUM_HBD: +// case HIVE_ASSET_NUM_VESTS: +// break; +// default: { +// uint32_t nai_data_digits = (asset_num >> HIVE_NAI_SHIFT); +// uint32_t nai_1bit = (asset_num & SMT_ASSET_NUM_CONTROL_MASK); +// uint32_t nai_decimal_places = (asset_num & SMT_ASSET_NUM_PRECISION_MASK); +// FC_ASSERT((nai_data_digits >= SMT_MIN_NAI) & +// (nai_data_digits <= SMT_MAX_NAI) & +// (nai_1bit == SMT_ASSET_NUM_CONTROL_MASK) & +// (nai_decimal_places <= HIVE_ASSET_MAX_DECIMALS), +// "Cannot determine space for asset ${n}", ("n", asset_num)); +// } +// } +// // this assert is duplicated by above code in all cases +// // FC_ASSERT( decimals() <= HIVE_ASSET_MAX_DECIMALS ); +//} +// +//}}} // namespace graphene::peerplays_sidechain::hive +// +//namespace fc { +// +//namespace raw { +// +//// Legacy serialization of assets +//// 0000pppp aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff 00000000 +//// Symbol = abcdef +//// +//// NAI serialization of assets +//// aaa1pppp bbbbbbbb cccccccc dddddddd +//// NAI = (MSB to LSB) dddddddd cccccccc bbbbbbbb aaa +//// +//// NAI internal storage of legacy assets +// +////template +////void unpack(Stream &s, graphene::peerplays_sidechain::hive::asset_symbol_type &sym, uint32_t, uint32_t max_depth) { +//// uint64_t ser = 0; +//// s.read((char *)&ser, 4); +//// +//// switch (ser) { +//// case OBSOLETE_SYMBOL_SER & 0xFFFFFFFF: +//// s.read(((char *)&ser) + 4, 4); +//// FC_ASSERT(ser == OBSOLETE_SYMBOL_SER, "invalid asset bits"); +//// sym.asset_num = HIVE_ASSET_NUM_HIVE; +//// break; +//// case OBD_SYMBOL_SER & 0xFFFFFFFF: +//// s.read(((char *)&ser) + 4, 4); +//// FC_ASSERT(ser == OBD_SYMBOL_SER, "invalid asset bits"); +//// sym.asset_num = HIVE_ASSET_NUM_HBD; +//// break; +//// case VESTS_SYMBOL_SER & 0xFFFFFFFF: +//// s.read(((char *)&ser) + 4, 4); +//// FC_ASSERT(ser == VESTS_SYMBOL_SER, "invalid asset bits"); +//// sym.asset_num = HIVE_ASSET_NUM_VESTS; +//// break; +//// default: +//// sym.asset_num = uint32_t(ser); +//// } +//// sym.validate(); +////} +// +//} // namespace raw +//// +////void to_variant(const graphene::peerplays_sidechain::hive::asset_symbol_type &sym, fc::variant &var, uint32_t max_depth) { +//// try { +//// mutable_variant_object o; +//// o(ASSET_SYMBOL_NAI_KEY, sym.to_nai_string())(ASSET_SYMBOL_DECIMALS_KEY, sym.decimals()); +//// var = std::move(o); +//// } +//// FC_CAPTURE_AND_RETHROW() +////} +//// +////void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::asset_symbol_type &sym, uint32_t max_depth) { +//// using graphene::peerplays_sidechain::hive::asset_symbol_type; +//// +//// try { +//// FC_ASSERT(var.is_object(), "Asset symbol is expected to be an object."); +//// +//// auto &o = var.get_object(); +//// +//// auto nai = o.find(ASSET_SYMBOL_NAI_KEY); +//// FC_ASSERT(nai != o.end(), "Expected key '${key}'.", ("key", ASSET_SYMBOL_NAI_KEY)); +//// FC_ASSERT(nai->value().is_string(), "Expected a string type for value '${key}'.", ("key", ASSET_SYMBOL_NAI_KEY)); +//// +//// auto decimals = o.find(ASSET_SYMBOL_DECIMALS_KEY); +//// FC_ASSERT(decimals != o.end(), "Expected key '${key}'.", ("key", ASSET_SYMBOL_DECIMALS_KEY)); +//// FC_ASSERT(decimals->value().is_uint64(), "Expected an unsigned integer type for value '${key}'.", ("key", ASSET_SYMBOL_DECIMALS_KEY)); +//// FC_ASSERT(decimals->value().as_uint64() <= HIVE_ASSET_MAX_DECIMALS, +//// "Expected decimals to be less than or equal to ${num}", ("num", HIVE_ASSET_MAX_DECIMALS)); +//// +//// sym = asset_symbol_type::from_nai_string(nai->value().as_string().c_str(), decimals->value().as(max_depth)); +//// } +//// FC_CAPTURE_AND_RETHROW() +////} +// +//} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/hive/transaction.cpp b/libraries/plugins/peerplays_sidechain/hive/transaction.cpp index a5c8bcfd..0e0ff8ed 100644 --- a/libraries/plugins/peerplays_sidechain/hive/transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/hive/transaction.cpp @@ -67,7 +67,15 @@ signature_type signed_transaction::sign(const hive::private_key_type &key, const digest_type::encoder enc; fc::raw::pack(enc, chain_id); fc::raw::pack(enc, *this); - return key.sign_compact(enc.result(), true); + auto sig = key.sign_compact(enc.result(), true); + + ilog("Signing2: chain_id = ${chain_id}", ("chain_id", chain_id)); + ilog("Signing2: key = ${key}", ("key", key)); + ilog("Signing2: this = ${this}", ("this", *this)); + ilog("Signing2: h = ${h}", ("h", enc.result())); + ilog("Signing2: signature = ${sig}", ("sig", sig)); + + return sig; } }}} // namespace graphene::peerplays_sidechain::hive diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp new file mode 100644 index 00000000..aaab642f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +struct asset { + share_type amount; + asset_symbol_type symbol; +}; + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { +void to_variant(const graphene::peerplays_sidechain::hive::asset &var, fc::variant &vo, uint32_t max_depth); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::asset &vo, uint32_t max_depth); +} // namespace fc + +FC_REFLECT(graphene::peerplays_sidechain::hive::asset, (amount)(symbol)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset_symbol.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset_symbol.hpp new file mode 100644 index 00000000..4eb1d9b0 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset_symbol.hpp @@ -0,0 +1,245 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define HIVE_ASSET_SYMBOL_PRECISION_BITS 4 +#define HIVE_ASSET_CONTROL_BITS 1 +#define HIVE_NAI_SHIFT (HIVE_ASSET_SYMBOL_PRECISION_BITS + HIVE_ASSET_CONTROL_BITS) +#define SMT_MAX_NAI 99999999 +#define SMT_MIN_NAI 1 +#define SMT_MIN_NON_RESERVED_NAI 10000000 +#define HIVE_ASSET_SYMBOL_NAI_LENGTH 10 +#define HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH (HIVE_ASSET_SYMBOL_NAI_LENGTH + 2) +#define SMT_MAX_NAI_POOL_COUNT 10 +#define SMT_MAX_NAI_GENERATION_TRIES 100 + +#define HIVE_PRECISION_HBD (3) +#define HIVE_PRECISION_HIVE (3) +#define HIVE_PRECISION_VESTS (6) + +// One's place is used for check digit, which means NAI 0-9 all have NAI data of 0 which is invalid +// This space is safe to use because it would alwasys result in failure to convert from NAI +#define HIVE_NAI_HBD (1) +#define HIVE_NAI_HIVE (2) +#define HIVE_NAI_VESTS (3) + +#define HIVE_ASSET_NUM_HBD (uint32_t(((SMT_MAX_NAI + HIVE_NAI_HBD) << HIVE_NAI_SHIFT) | HIVE_PRECISION_HBD)) +#define HIVE_ASSET_NUM_HIVE (uint32_t(((SMT_MAX_NAI + HIVE_NAI_HIVE) << HIVE_NAI_SHIFT) | HIVE_PRECISION_HIVE)) +#define HIVE_ASSET_NUM_VESTS (uint32_t(((SMT_MAX_NAI + HIVE_NAI_VESTS) << HIVE_NAI_SHIFT) | HIVE_PRECISION_VESTS)) + +#ifdef IS_TEST_NET + +#define VESTS_SYMBOL_U64 (uint64_t('V') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32)) +my #define HIVE_SYMBOL_U64 OBSOLETE_SYMBOL_U64 +#define OBD_SYMBOL_U64 (uint64_t('T') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) +#define HBD_SYMBOL_U64 OBD_SYMBOL_U64 +#else + +#define VESTS_SYMBOL_U64 (uint64_t('V') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32)) +#define OBSOLETE_SYMBOL_U64 (uint64_t('S') | (uint64_t('T') << 8) | (uint64_t('E') << 16) | (uint64_t('E') << 24) | (uint64_t('M') << 32)) +#define HIVE_SYMBOL_U64 (uint64_t('H') | (uint64_t('I') << 8) | (uint64_t('V') << 16) | (uint64_t('E') << 24)) +#define OBD_SYMBOL_U64 (uint64_t('S') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) +#define HBD_SYMBOL_U64 (uint64_t('H') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) + +#endif + +#define VESTS_SYMBOL_SER (uint64_t(6) | (VESTS_SYMBOL_U64 << 8)) ///< VESTS|VESTS with 6 digits of precision +#define OBSOLETE_SYMBOL_SER (uint64_t(3) | (OBSOLETE_SYMBOL_U64 << 8)) ///< STEEM|TESTS with 3 digits of precision +#define OBD_SYMBOL_SER (uint64_t(3) | (OBD_SYMBOL_U64 << 8)) ///< SBD|TBD with 3 digits of precision + +#define HIVE_ASSET_MAX_DECIMALS 12 + +#define SMT_ASSET_NUM_PRECISION_MASK 0xF +#define SMT_ASSET_NUM_CONTROL_MASK 0x10 +#define SMT_ASSET_NUM_VESTING_MASK 0x20 + +#define ASSET_SYMBOL_NAI_KEY "nai" +#define ASSET_SYMBOL_DECIMALS_KEY "decimals" + + namespace graphene { + namespace peerplays_sidechain { namespace hive { + + class asset_symbol_type { + public: + enum asset_symbol_space { + legacy_space = 1, + smt_nai_space = 2 + }; + + explicit operator uint32_t() { + return to_nai(); + } + + static asset_symbol_type from_string(const std::string &str); + // buf must have space for HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH + static asset_symbol_type from_nai_string(const char *buf, uint8_t decimal_places); + static asset_symbol_type from_asset_num(uint32_t asset_num) { + asset_symbol_type result; + result.asset_num = asset_num; + return result; + } + static uint32_t asset_num_from_nai(uint32_t nai, uint8_t decimal_places); + static asset_symbol_type from_nai(uint32_t nai, uint8_t decimal_places) { + return from_asset_num(asset_num_from_nai(nai, decimal_places)); + } + static uint8_t damm_checksum_8digit(uint32_t value); + + std::string to_string() const; + + void to_nai_string(char *buf) const; + std::string to_nai_string() const { + char buf[HIVE_ASSET_SYMBOL_NAI_STRING_LENGTH]; + to_nai_string(buf); + return std::string(buf); + } + + uint32_t to_nai() const; + + /**Returns true when symbol represents vesting variant of the token, + * false for liquid one. + */ + bool is_vesting() const; + /**Returns vesting symbol when called from liquid one + * and liquid symbol when called from vesting one. + * Returns back the HBD symbol if represents HBD. + */ + asset_symbol_type get_paired_symbol() const; + /**Returns asset_num stripped of precision holding bits. + * \warning checking that it's SMT symbol is caller responsibility. + */ + uint32_t get_stripped_precision_smt_num() const { + return asset_num & ~(SMT_ASSET_NUM_PRECISION_MASK); + } + + asset_symbol_space space() const; + uint8_t decimals() const { + return uint8_t(asset_num & SMT_ASSET_NUM_PRECISION_MASK); + } + + void validate() const; + + uint32_t asset_num = 0; + uint64_t ser = OBSOLETE_SYMBOL_SER; + }; + + }} // namespace peerplays_sidechain::hive +} // namespace graphene + +FC_REFLECT(graphene::peerplays_sidechain::hive::asset_symbol_type, (asset_num)) + +namespace fc { + +namespace raw { + +// Legacy serialization of assets +// 0000pppp aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff 00000000 +// Symbol = abcdef +// +// NAI serialization of assets +// aaa1pppp bbbbbbbb cccccccc dddddddd +// NAI = (MSB to LSB) dddddddd cccccccc bbbbbbbb aaa +// +// NAI internal storage of legacy assets + +template +void pack(Stream &s, const graphene::peerplays_sidechain::hive::asset_symbol_type &sym) { + std::cout << "##### PACK ###" << std::endl; + switch (sym.space()) { + case graphene::peerplays_sidechain::hive::asset_symbol_type::legacy_space: { + uint64_t ser = 0; + switch (sym.asset_num) { + case HIVE_ASSET_NUM_HIVE: + ser = OBSOLETE_SYMBOL_SER; + break; + case HIVE_ASSET_NUM_HBD: + ser = OBD_SYMBOL_SER; + break; + case HIVE_ASSET_NUM_VESTS: + ser = VESTS_SYMBOL_SER; + break; + default: + FC_ASSERT(false, "Cannot serialize unknown asset symbol"); + } + pack(s, ser); + break; + } + case graphene::peerplays_sidechain::hive::asset_symbol_type::smt_nai_space: + pack(s, sym.asset_num); + break; + default: + FC_ASSERT(false, "Cannot serialize unknown asset symbol"); + } +} + +template +void unpack(Stream &s, graphene::peerplays_sidechain::hive::asset_symbol_type &sym) { + std::cout << "##### UNPACK ###" << std::endl; + uint64_t ser = 0; + s.read((char *)&ser, 4); + + switch (ser) { + case OBSOLETE_SYMBOL_SER & 0xFFFFFFFF: + s.read(((char *)&ser) + 4, 4); + FC_ASSERT(ser == OBSOLETE_SYMBOL_SER, "invalid asset bits"); + sym.asset_num = HIVE_ASSET_NUM_HIVE; + break; + case OBD_SYMBOL_SER & 0xFFFFFFFF: + s.read(((char *)&ser) + 4, 4); + FC_ASSERT(ser == OBD_SYMBOL_SER, "invalid asset bits"); + sym.asset_num = HIVE_ASSET_NUM_HBD; + break; + case VESTS_SYMBOL_SER & 0xFFFFFFFF: + s.read(((char *)&ser) + 4, 4); + FC_ASSERT(ser == VESTS_SYMBOL_SER, "invalid asset bits"); + sym.asset_num = HIVE_ASSET_NUM_VESTS; + break; + default: + sym.asset_num = uint32_t(ser); + } + sym.validate(); +} + +} // namespace raw + +inline void to_variant(const graphene::peerplays_sidechain::hive::asset_symbol_type &sym, fc::variant &var, uint32_t max_depth) { + try { + mutable_variant_object o; + o(ASSET_SYMBOL_NAI_KEY, sym.to_nai_string())(ASSET_SYMBOL_DECIMALS_KEY, sym.decimals()); + var = std::move(o); + } + FC_CAPTURE_AND_RETHROW() +} + +inline void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::asset_symbol_type &sym, uint32_t max_depth) { + using graphene::peerplays_sidechain::hive::asset_symbol_type; + + try { + FC_ASSERT(var.is_object(), "Asset symbol is expected to be an object."); + + auto &o = var.get_object(); + + auto nai = o.find(ASSET_SYMBOL_NAI_KEY); + FC_ASSERT(nai != o.end(), "Expected key '${key}'.", ("key", ASSET_SYMBOL_NAI_KEY)); + FC_ASSERT(nai->value().is_string(), "Expected a string type for value '${key}'.", ("key", ASSET_SYMBOL_NAI_KEY)); + + auto decimals = o.find(ASSET_SYMBOL_DECIMALS_KEY); + FC_ASSERT(decimals != o.end(), "Expected key '${key}'.", ("key", ASSET_SYMBOL_DECIMALS_KEY)); + FC_ASSERT(decimals->value().is_uint64(), "Expected an unsigned integer type for value '${key}'.", ("key", ASSET_SYMBOL_DECIMALS_KEY)); + FC_ASSERT(decimals->value().as_uint64() <= HIVE_ASSET_MAX_DECIMALS, + "Expected decimals to be less than or equal to ${num}", ("num", HIVE_ASSET_MAX_DECIMALS)); + + sym = asset_symbol_type::from_nai_string(nai->value().as_string().c_str(), decimals->value().as(max_depth)); + } + FC_CAPTURE_AND_RETHROW() +} + +} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp index cac3b03f..e19060f8 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -15,7 +16,12 @@ struct vote_operation {}; struct comment_operation {}; -struct transfer_operation {}; +struct transfer_operation { + hive::account_name_type from; + hive::account_name_type to; + hive::asset amount; + std::string memo; +}; struct transfer_to_vesting_operation {}; @@ -44,7 +50,8 @@ struct account_update_operation { FC_REFLECT(graphene::peerplays_sidechain::hive::vote_operation, ) FC_REFLECT(graphene::peerplays_sidechain::hive::comment_operation, ) -FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_operation, + (from)(to)(amount)(memo)) FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_to_vesting_operation, ) FC_REFLECT(graphene::peerplays_sidechain::hive::withdraw_vesting_operation, ) FC_REFLECT(graphene::peerplays_sidechain::hive::limit_order_create_operation, ) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp index e49556d3..724373e5 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp @@ -18,7 +18,7 @@ typedef fc::ripemd160 block_id_type; typedef fc::ripemd160 transaction_id_type; typedef fc::sha256 digest_type; typedef fc::ecc::compact_signature signature_type; -//typedef safe share_type; +typedef fc::safe share_type; //typedef safe ushare_type; //typedef uint16_t weight_type; //typedef uint32_t contribution_id_type; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types_fwd.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types_fwd.hpp new file mode 100644 index 00000000..7276f297 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types_fwd.hpp @@ -0,0 +1,90 @@ +//#pragma once +//#include +//#include +//#include +// +//#include "asset_symbol.hpp" +// +//namespace fc { +//class variant; +//} // namespace fc +// +//namespace graphene { namespace peerplays_sidechain { namespace hive { +////template< typename Storage = fc::uint128 > +////class fixed_string_impl; +// +//class asset_symbol_type; +////class legacy_hive_asset_symbol_type; +////struct legacy_hive_asset; +//}}} // namespace graphene::peerplays_sidechain::hive +// +////using boost::container::flat_set; +//// +////template< class Key > +////class flat_set_ex: public flat_set< Key > +////{ +//// public: +//// +//// flat_set_ex& operator=( const flat_set< Key >& obj ) +//// { +//// flat_set< Key >::operator=( obj ); +//// return *this; +//// } +//// +//// flat_set_ex& operator=( const flat_set_ex& obj ) +//// { +//// flat_set< Key >::operator=( obj ); +//// return *this; +//// } +////}; +// +//namespace fc { +//namespace raw { +// +////template +////void pack( Stream& s, const flat_set_ex& value ); +////template +////void unpack( Stream& s, flat_set_ex& value, uint32_t depth = 0 ); +// +////template< typename Stream, typename Storage > +////inline void pack( Stream& s, const hive::protocol::fixed_string_impl< Storage >& u ); +////template< typename Stream, typename Storage > +////inline void unpack( Stream& s, hive::protocol::fixed_string_impl< Storage >& u, uint32_t depth = 0 ); +// +//template +//inline void pack(Stream &s, const graphene::peerplays_sidechain::hive::asset_symbol_type &sym, uint32_t depth = 0); +//template +//inline void unpack(Stream &s, graphene::peerplays_sidechain::hive::asset_symbol_type &sym, uint32_t depth = 0); +// +////template< typename Stream > +////inline void pack( Stream& s, const hive::protocol::legacy_hive_asset_symbol_type& sym ); +////template< typename Stream > +////inline void unpack( Stream& s, hive::protocol::legacy_hive_asset_symbol_type& sym, uint32_t depth = 0 ); +// +//} // namespace raw +// +////template +////void to_variant( const flat_set_ex& var, variant& vo ); +// +////template +////void from_variant( const variant& var, flat_set_ex& vo ); +// +////template< typename Storage > +////inline void to_variant( const hive::protocol::fixed_string_impl< Storage >& s, fc::variant& v ); +////template< typename Storage > +////inline void from_variant( const variant& v, hive::protocol::fixed_string_impl< Storage >& s ); +// +//inline void to_variant(const graphene::peerplays_sidechain::hive::asset_symbol_type &sym, fc::variant &v, uint32_t max_depth); +// +////inline void from_variant( const fc::variant& v, hive::protocol::legacy_hive_asset& leg ); +////inline void to_variant( const hive::protocol::legacy_hive_asset& leg, fc::variant& v ); +// +////template struct get_typename> +////{ +//// static const char* name() { +//// static std::string n = std::string("flat_set<") + get_typename< fc::flat_set >::name() + ">"; +//// return n.c_str(); +//// } +////}; +// +//} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index ca0e6df7..7790faee 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -168,10 +168,10 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ bool enable_peerplays_asset_deposits = false; #ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS - enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) && - (sed.sidechain_currency.compare("BTC") != 0) && - (sed.sidechain_currency.compare("HBD") != 0) && - (sed.sidechain_currency.compare("HIVE") != 0); + //enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) && + // (sed.sidechain_currency.compare("BTC") != 0) && + // (sed.sidechain_currency.compare("HBD") != 0) && + // (sed.sidechain_currency.compare("HIVE") != 0); #endif bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) && @@ -180,10 +180,19 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) || enable_peerplays_asset_deposits); + bool is_tracked_asset = false; + if (sed.sidechain == sidechain_type::peerplays) { + for (const auto &asset_id : tracked_assets) { + std::string asset_id_str = asset_id_to_string(asset_id); + if (sed.sidechain_currency == asset_id_str) { + is_tracked_asset = true; + break; + } + } + } + bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain_type::peerplays) && - ((sed.sidechain_currency.compare("BTC") == 0) || - (sed.sidechain_currency.compare("HBD") == 0) || - (sed.sidechain_currency.compare("HIVE") == 0)); + is_tracked_asset; // Deposit request if (deposit_condition) { @@ -223,12 +232,29 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ // Withdrawal request if (withdraw_condition) { - // BTC Payout only (for now) const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); - const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sed.peerplays_from, sidechain_type::bitcoin, time_point_sec::maximum())); + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sed.peerplays_from, sidechain, time_point_sec::maximum())); if (addr_itr == sidechain_addresses_idx.end()) return; + std::string withdraw_currency = ""; + price withdraw_currency_price = {}; + if (sed.sidechain_currency == asset_id_to_string(gpo.parameters.btc_asset())) { + withdraw_currency = "BTC"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; + } + if (sed.sidechain_currency == asset_id_to_string(gpo.parameters.hbd_asset())) { + withdraw_currency = "HBD"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate; + } + if (sed.sidechain_currency == asset_id_to_string(gpo.parameters.hive_asset())) { + withdraw_currency = "HIVE"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate; + } + if (withdraw_currency.empty()) { + return; + } + for (son_id_type son_id : plugin.get_sons()) { if (plugin.is_active_son(son_id)) { @@ -242,12 +268,10 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ op.peerplays_transaction_id = sed.sidechain_transaction_id; op.peerplays_from = sed.peerplays_from; op.peerplays_asset = sed.peerplays_asset; - // BTC payout only (for now) - op.withdraw_sidechain = sidechain_type::bitcoin; + op.withdraw_sidechain = sidechain; op.withdraw_address = addr_itr->withdraw_address; - op.withdraw_currency = "BTC"; - price btc_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; - op.withdraw_amount = sed.peerplays_asset.amount * btc_price.quote.amount / btc_price.base.amount; + op.withdraw_currency = withdraw_currency; + op.withdraw_amount = sed.peerplays_asset.amount * withdraw_currency_price.quote.amount / withdraw_currency_price.base.amount; signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(son_id), op); try { @@ -593,6 +617,7 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) { operation_index = operation_index + 1; if (op.which() == operation::tag::value) { transfer_operation transfer_op = op.get(); + if (transfer_op.to != plugin.database().get_global_properties().parameters.son_account()) { continue; } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp index 1698ef8b..e669491a 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -472,6 +472,78 @@ bool sidechain_net_handler_hive::process_deposit(const son_wallet_deposit_object } bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_object &swwo) { + + const chain::global_property_object &gpo = database.get_global_properties(); + + //===== + + uint32_t asset_num = 0; + if (swwo.withdraw_currency == "HBD") { + asset_num = HIVE_ASSET_NUM_HBD; + } + if (swwo.withdraw_currency == "HIVE") { + asset_num = HIVE_ASSET_NUM_HIVE; + } + + hive::transfer_operation t_op; + t_op.from = "son-account"; + t_op.to = swwo.withdraw_address; + t_op.amount.amount = swwo.withdraw_amount; + t_op.amount.symbol = hive::asset_symbol_type::from_asset_num(asset_num); + t_op.memo = ""; + + std::string block_id_str = node_rpc_client->get_head_block_id(); + hive::block_id_type head_block_id(block_id_str); + + std::string head_block_time_str = node_rpc_client->get_head_block_time(); + time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); + + hive::signed_transaction htrx; + htrx.set_reference_block(head_block_id); + htrx.set_expiration(head_block_time + fc::seconds(90)); + + htrx.operations.push_back(t_op); + ilog("TRX: ${htrx}", ("htrx", htrx)); + + std::stringstream ss; + fc::raw::pack(ss, htrx, 1000); + std::string tx_str = boost::algorithm::hex(ss.str()); + if (tx_str.empty()) { + return false; + } + + //===== + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_withdraw_process_operation swwp_op; + swwp_op.payer = gpo.parameters.son_account(); + swwp_op.son_wallet_withdraw_id = swwo.id; + proposal_op.proposed_ops.emplace_back(swwp_op); + + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swwo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + return false; } @@ -635,6 +707,42 @@ void sidechain_net_handler_hive::handle_event(const std::string &event_data) { } } } + + //========== + { + hive::transfer_operation t_op; + t_op.from = "sonaccount01"; + t_op.to = "account05"; + t_op.amount.amount = 1000; + t_op.amount.symbol = hive::asset_symbol_type::from_asset_num(HIVE_ASSET_NUM_HIVE); + t_op.memo = ""; + + std::string block_id_str = node_rpc_client->get_head_block_id(); + hive::block_id_type head_block_id(block_id_str); + //hive::block_id_type head_block_id("000087723a5513e7cc0f03a71bf05a5b7b36102f"); + + std::string head_block_time_str = node_rpc_client->get_head_block_time(); + time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); + //time_point head_block_time = fc::time_point_sec::from_iso_string("2021-04-23T10:38:03"); + + hive::signed_transaction htrx; + htrx.set_reference_block(head_block_id); + htrx.set_expiration(head_block_time + fc::seconds(30)); + + htrx.operations.push_back(t_op); + ilog("TRX: ${htrx}", ("htrx", htrx)); + + std::string chain_id_str = node_rpc_client->get_chain_id(); + const hive::chain_id_type chain_id(chain_id_str); + + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key("sonaccount01")); + htrx.sign(*privkey, chain_id); + + std::string params = fc::json::to_string(htrx); + ilog("HTRX: ${htrx}", ("htrx", params)); + node_rpc_client->network_broadcast_api_broadcast_transaction(params); + } + //========== } }} // namespace graphene::peerplays_sidechain