Fix Hive transaction serialization

This commit is contained in:
serkixenos 2021-05-19 19:43:19 +02:00
parent 09f23dade8
commit c6a7ab2057
7 changed files with 31 additions and 813 deletions

View file

@ -44,7 +44,6 @@ make -j$(nproc)
make install # this can install the executable files under /usr/local
```
docker build -t peerplays .
## Docker image

View file

@ -9,231 +9,11 @@
#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<hive::asset_symbol_type>(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<uint32_t>(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<std::string>(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(var.symbol.decimals()))(ASSET_NAI_KEY, var.symbol.to_nai_string());
variant v = mutable_variant_object(ASSET_AMOUNT_KEY, boost::lexical_cast<std::string>(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(TESTS_PRECISION))(ASSET_NAI_KEY, TESTS_NAI);
vo = v;
}
FC_CAPTURE_AND_RETHROW()
@ -256,7 +36,7 @@ void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::a
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<std::string>(max_depth).c_str(), v_object[ASSET_PRECISION_KEY].as<uint8_t>(max_depth));
vo.symbol = TESTS_SYMBOL_SER;
}
FC_CAPTURE_AND_RETHROW()
}

View file

@ -1,300 +0,0 @@
//#include <graphene/peerplays_sidechain/hive/asset_symbol.hpp>
//
//#include <fc/io/json.hpp>
//
//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<hive::asset_symbol_type>(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<uint32_t>(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 <typename Stream>
////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<uint8_t>(max_depth));
//// }
//// FC_CAPTURE_AND_RETHROW()
////}
//
//} // namespace fc

View file

@ -1,13 +1,32 @@
#pragma once
#include <graphene/peerplays_sidechain/hive/asset_symbol.hpp>
#include <graphene/peerplays_sidechain/hive/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace hive {
#define HBD_NAI "@@000000013"
#define HBD_PRECISION 3
#define HBD_SYMBOL_U64 (uint64_t('H') | (uint64_t('B') << 8) | (uint64_t('D') << 16))
#define HBD_SYMBOL_SER (uint64_t(3) | (HBD_SYMBOL_U64 << 8))
#define HIVE_NAI "@@000000021"
#define HIVE_PRECISION 3
#define HIVE_SYMBOL_U64 (uint64_t('H') | (uint64_t('I') << 8) | (uint64_t('V') << 16) | (uint64_t('E') << 24))
#define HIVE_SYMBOL_SER (uint64_t(3) | (HIVE_SYMBOL_U64 << 8))
#define TBD_NAI "@@000000013"
#define TBD_PRECISION 3
#define TBD_SYMBOL_U64 (uint64_t('T') | (uint64_t('B') << 8) | (uint64_t('D') << 16))
#define TBD_SYMBOL_SER (uint64_t(3) | (TBD_SYMBOL_U64 << 8))
#define TESTS_NAI "@@000000021"
#define TESTS_PRECISION 3
#define TESTS_SYMBOL_U64 (uint64_t('T') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32))
#define TESTS_SYMBOL_SER (uint64_t(3) | (TESTS_SYMBOL_U64 << 8))
struct asset {
share_type amount;
asset_symbol_type symbol;
uint64_t symbol;
};
}}} // namespace graphene::peerplays_sidechain::hive

View file

@ -1,245 +0,0 @@
#pragma once
#include <cstdint>
#include <iostream>
#include <string>
#include <fc/exception/exception.hpp>
#include <fc/io/raw.hpp>
#include <fc/reflect/reflect.hpp>
#include <fc/variant.hpp>
#include <graphene/peerplays_sidechain/hive/types_fwd.hpp>
#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 <typename Stream>
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 <typename Stream>
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<uint8_t>(max_depth));
}
FC_CAPTURE_AND_RETHROW()
}
} // namespace fc

View file

@ -21,6 +21,7 @@
#include <graphene/chain/protocol/son_wallet.hpp>
#include <graphene/chain/son_info.hpp>
#include <graphene/chain/son_wallet_object.hpp>
#include <graphene/peerplays_sidechain/hive/asset.hpp>
#include <graphene/peerplays_sidechain/hive/operations.hpp>
#include <graphene/peerplays_sidechain/hive/transaction.hpp>
#include <graphene/utilities/key_conversion.hpp>
@ -477,19 +478,19 @@ bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_ob
//=====
uint32_t asset_num = 0;
uint64_t symbol = 0;
if (swwo.withdraw_currency == "HBD") {
asset_num = HIVE_ASSET_NUM_HBD;
symbol = TBD_SYMBOL_SER;
}
if (swwo.withdraw_currency == "HIVE") {
asset_num = HIVE_ASSET_NUM_HIVE;
symbol = TESTS_SYMBOL_SER;
}
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.amount.symbol = symbol;
t_op.memo = "";
std::string block_id_str = node_rpc_client->get_head_block_id();
@ -707,42 +708,6 @@ 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<fc::ecc::private_key> 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

View file

@ -12,9 +12,9 @@ sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin
plugin(_plugin),
database(_plugin.database()) {
database.applied_block.connect([&](const signed_block &b) {
on_applied_block(b);
});
//database.applied_block.connect([&](const signed_block &b) {
// on_applied_block(b);
//});
}
sidechain_net_manager::~sidechain_net_manager() {