diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index e04a246e..ac758eaa 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -282,6 +282,10 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } + void operator()( const withdraw_pbtc_operation& op ) + { + _impacted.insert( op.payer ); + } void operator()( const bitcoin_address_create_operation& op ) { _impacted.insert( op.payer ); diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 4e9b719f..0a82e51f 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -111,6 +111,7 @@ add_library( graphene_chain betting_market_group_object.cpp affiliate_payout.cpp + withdraw_pbtc_evaluator.cpp ${HEADERS} ${PROTOCOL_HEADERS} diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index ac2f05d5..3a5ebf1f 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -241,6 +242,7 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); register_evaluator(); } diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 6bcee4bd..b63ba6c2 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -36,7 +36,7 @@ namespace graphene { namespace chain { database::database() : - _random_number_generator(fc::ripemd160().data()) + i_w_info(*this), _random_number_generator(fc::ripemd160().data()) { initialize_indexes(); initialize_evaluators(); diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 951af36f..a8175c0d 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -269,6 +269,10 @@ struct get_impacted_account_visitor _impacted.insert( op.affiliate ); } void operator()( const affiliate_referral_payout_operation& op ) { } + void operator()( const withdraw_pbtc_operation& op ) + { + _impacted.insert( op.payer ); + } void operator()( const bitcoin_address_create_operation& op ) { _impacted.insert( op.payer ); diff --git a/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp b/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp index b919223e..f4f7b11c 100644 --- a/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp +++ b/libraries/chain/include/graphene/chain/bitcoin_address_object.hpp @@ -3,12 +3,10 @@ #include #include -#include +#include namespace graphene { namespace chain { -using namespace sidechain; - class bitcoin_address_object : public abstract_object { public: @@ -19,14 +17,14 @@ class bitcoin_address_object : public abstract_object // multisig m-of-n (m = 5). Address is valid before count of changed witnesses < 5 bool valid() { return count_invalid_pub_key < 5; } // TODO: move to global_properties - std::string get_address() const { return address.base58_address; } + std::string get_address() const { return address.get_address(); } - void update_count_invalid_pub_key(const accounts_keys& incoming_wit_keys) { - count_invalid_pub_key = incoming_wit_keys.size() - address.count_intersection(incoming_wit_keys); + void update_count_invalid_pub_key( const sidechain::accounts_keys& incoming_wit_keys ) { + count_invalid_pub_key = incoming_wit_keys.size() - address.count_intersection( incoming_wit_keys ); } account_id_type owner; - btc_multisig_segwit_address address; + sidechain::btc_multisig_segwit_address address; uint8_t count_invalid_pub_key; }; diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index af50a94b..2d31421d 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -39,6 +39,7 @@ #include #include +#include #include @@ -504,6 +505,13 @@ namespace graphene { namespace chain { ///@} ///@} + //////////////////// sidechain //////////////////// + public: + + sidechain::input_withdrawal_info i_w_info; + + private: + vector< processed_transaction > _pending_tx; fork_database _fork_db; diff --git a/libraries/chain/include/graphene/chain/info_for_vout_object.hpp b/libraries/chain/include/graphene/chain/info_for_vout_object.hpp index 7bee1ca8..8f0c8ab1 100644 --- a/libraries/chain/include/graphene/chain/info_for_vout_object.hpp +++ b/libraries/chain/include/graphene/chain/info_for_vout_object.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace graphene { namespace chain { @@ -21,10 +22,10 @@ class info_for_vout_object : public abstract_object info_for_vout_id_type get_id()const { return id; } - account_id_type payer; - // btc::payment_type addr_type; - std::string data; - uint64_t amount; + account_id_type payer; + sidechain::payment_type addr_type; + std::string data; + uint64_t amount; bool created = false; }; @@ -44,5 +45,5 @@ typedef generic_index } } // graphene::chain -FC_REFLECT_DERIVED( graphene::chain::info_for_vout_object, (graphene::chain::object), (payer)(data)(amount)(created) ) +FC_REFLECT_DERIVED( graphene::chain::info_for_vout_object, (graphene::chain::object), (payer)(addr_type)(data)(amount)(created) ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 38e73d9c..d256258c 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include namespace graphene { namespace chain { @@ -131,6 +132,7 @@ namespace graphene { namespace chain { event_group_delete_operation, affiliate_payout_operation, // VIRTUAL affiliate_referral_payout_operation, // VIRTUAL + withdraw_pbtc_operation, bitcoin_address_create_operation > operation; diff --git a/libraries/chain/include/graphene/chain/protocol/withdraw_pbtc.hpp b/libraries/chain/include/graphene/chain/protocol/withdraw_pbtc.hpp new file mode 100644 index 00000000..567b2aac --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/withdraw_pbtc.hpp @@ -0,0 +1,33 @@ +#pragma once +#include + +namespace graphene { namespace chain { + + struct withdraw_pbtc_operation : public base_operation + { + struct fee_parameters_type { + uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; + uint32_t price_per_kbyte = 10; + }; + + asset fee; + account_id_type payer; + + std::string data; // address or script + uint64_t amount; + + // object_id_type tx_obj_id; + + account_id_type fee_payer() const { return payer; } + void validate() const {} + share_type calculate_fee( const fee_parameters_type& k )const { + share_type fee_required = k.fee; + fee_required += calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte ); + return fee_required; + } + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::withdraw_pbtc_operation::fee_parameters_type, (fee)(price_per_kbyte) ) +FC_REFLECT( graphene::chain::withdraw_pbtc_operation, (fee)(payer)(data)(amount) ) diff --git a/libraries/chain/include/graphene/chain/withdraw_pbtc_evaluator.hpp b/libraries/chain/include/graphene/chain/withdraw_pbtc_evaluator.hpp new file mode 100644 index 00000000..bd9e48fa --- /dev/null +++ b/libraries/chain/include/graphene/chain/withdraw_pbtc_evaluator.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +using namespace sidechain; + +namespace graphene { namespace chain { + +class withdraw_pbtc_evaluator : public evaluator +{ +public: + typedef withdraw_pbtc_operation operation_type; + + void_result do_evaluate(const withdraw_pbtc_operation& op); + + object_id_type do_apply(const withdraw_pbtc_operation& op); + + void reserve_issue( const withdraw_pbtc_operation& op ); + + bool check_amount( const withdraw_pbtc_operation& op ); + + payment_type type; +}; + +} } // graphene::chain diff --git a/libraries/chain/withdraw_pbtc_evaluator.cpp b/libraries/chain/withdraw_pbtc_evaluator.cpp new file mode 100644 index 00000000..0ba3a8e5 --- /dev/null +++ b/libraries/chain/withdraw_pbtc_evaluator.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include +#include + +namespace graphene { namespace chain { + +void_result withdraw_pbtc_evaluator::do_evaluate(const withdraw_pbtc_operation& op) +{ + database& d = db(); + + // FC_ASSERT( !d.is_sidechain_fork_needed() ); + FC_ASSERT( op.data.size() > 0 ); + type = bitcoin_address( op.data ).get_type(); + FC_ASSERT( type != payment_type::NULLDATA , "Invalid address type." ); + FC_ASSERT( check_amount( op ) ); + // asset acc_balance = db().get_balance( op.payer, d.get_sidechain_asset_id() ); + // FC_ASSERT( acc_balance.amount.value >= op.amount ); + + return void_result(); +} + +object_id_type withdraw_pbtc_evaluator::do_apply(const withdraw_pbtc_operation& op) +{ + database& d = db(); + + auto id = d.create( [&]( info_for_vout_object& obj ) { + obj.payer = op.payer; + obj.addr_type = type; + obj.data = op.data; + obj.amount = op.amount; + } ).get_id(); + + reserve_issue( op ); + + return id; +} + +void withdraw_pbtc_evaluator::reserve_issue( const withdraw_pbtc_operation& op ) +{ + +} + +bool withdraw_pbtc_evaluator::check_amount( const withdraw_pbtc_operation& op ) { + return true; +} + +} } // namespace graphene::chain diff --git a/libraries/sidechain/bech32.cpp b/libraries/sidechain/bech32.cpp new file mode 100644 index 00000000..c861169d --- /dev/null +++ b/libraries/sidechain/bech32.cpp @@ -0,0 +1,192 @@ +// Copyright (c) 2017 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +// #include + +namespace +{ + +typedef std::vector data; + +/** The Bech32 character set for encoding. */ +const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +/** The Bech32 character set for decoding. */ +const int8_t CHARSET_REV[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + +/** Concatenate two byte arrays. */ +data Cat(data x, const data& y) +{ + x.insert(x.end(), y.begin(), y.end()); + return x; +} + +/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to + * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher + * bits correspond to earlier values. */ +uint32_t PolyMod(const data& v) +{ + // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an + // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) = + // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that + // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...]. + + // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of + // v(x) mod g(x), where g(x) is the Bech32 generator, + // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way + // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a + // window of 1023 characters. Among the various possible BCH codes, one was selected to in + // fact guarantee detection of up to 4 errors within a window of 89 characters. + + // Note that the coefficients are elements of GF(32), here represented as decimal numbers + // between {}. In this finite field, addition is just XOR of the corresponding numbers. For + // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires + // treating the bits of values themselves as coefficients of a polynomial over a smaller field, + // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} = + // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a + // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}. + + // During the course of the loop below, `c` contains the bitpacked coefficients of the + // polynomial constructed from just the values of v that were processed so far, mod g(x). In + // the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of + // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value + // for `c`. + uint32_t c = 1; + for (auto v_i : v) { + // We want to update `c` to correspond to a polynomial with one extra term. If the initial + // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to + // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to + // process. Simplifying: + // c'(x) = (f(x) * x + v_i) mod g(x) + // ((f(x) mod g(x)) * x + v_i) mod g(x) + // (c(x) * x + v_i) mod g(x) + // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute + // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x) + // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x) + // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i + // If we call (x^6 mod g(x)) = k(x), this can be written as + // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x) + + // First, determine the value of c0: + uint8_t c0 = c >> 25; + + // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i: + c = ((c & 0x1ffffff) << 5) ^ v_i; + + // Finally, for each set bit n in c0, conditionally add {2^n}k(x): + if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18} + if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13} + if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26} + if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29} + if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19} + } + return c; +} + +/** Convert to lower case. */ +inline unsigned char LowerCase(unsigned char c) +{ + return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c; +} + +/** Expand a HRP for use in checksum computation. */ +data ExpandHRP(const std::string& hrp) +{ + data ret; + ret.reserve(hrp.size() + 90); + ret.resize(hrp.size() * 2 + 1); + for (size_t i = 0; i < hrp.size(); ++i) { + unsigned char c = hrp[i]; + ret[i] = c >> 5; + ret[i + hrp.size() + 1] = c & 0x1f; + } + ret[hrp.size()] = 0; + return ret; +} + +/** Verify a checksum. */ +bool VerifyChecksum(const std::string& hrp, const data& values) +{ + // PolyMod computes what value to xor into the final values to make the checksum 0. However, + // if we required that the checksum was 0, it would be the case that appending a 0 to a valid + // list of values would result in a new valid list. For that reason, Bech32 requires the + // resulting checksum to be 1 instead. + return PolyMod(Cat(ExpandHRP(hrp), values)) == 1; +} + +/** Create a checksum. */ +data CreateChecksum(const std::string& hrp, const data& values) +{ + data enc = Cat(ExpandHRP(hrp), values); + enc.resize(enc.size() + 6); // Append 6 zeroes + uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes. + data ret(6); + for (size_t i = 0; i < 6; ++i) { + // Convert the 5-bit groups in mod to checksum values. + ret[i] = (mod >> (5 * (5 - i))) & 31; + } + return ret; +} + +} // namespace + +namespace sidechain { namespace bech32 { + +/** Encode a Bech32 string. */ +std::string Encode(const std::string& hrp, const data& values) { + data checksum = CreateChecksum(hrp, values); + data combined = Cat(values, checksum); + std::string ret = hrp + '1'; + ret.reserve(ret.size() + combined.size()); + for (auto c : combined) { + ret += CHARSET[c]; + } + return ret; +} + +/** Decode a Bech32 string. */ +std::pair Decode(const std::string& str) { + bool lower = false, upper = false; + for (size_t i = 0; i < str.size(); ++i) { + unsigned char c = str[i]; + if (c < 33 || c > 126) return {}; + if (c >= 'a' && c <= 'z') lower = true; + if (c >= 'A' && c <= 'Z') upper = true; + } + if (lower && upper) return {}; + size_t pos = str.rfind('1'); + if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) { + return {}; + } + data values(str.size() - 1 - pos); + for (size_t i = 0; i < str.size() - 1 - pos; ++i) { + unsigned char c = str[i + pos + 1]; + int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c]; + if (rev == -1) { + return {}; + } + values[i] = rev; + } + std::string hrp; + for (size_t i = 0; i < pos; ++i) { + hrp += LowerCase(str[i]); + } + if (!VerifyChecksum(hrp, values)) { + return {}; + } + return {hrp, data(values.begin(), values.end() - 6)}; +} + +} } // namespace sidechain::bech32 diff --git a/libraries/sidechain/bitcoin_address.cpp b/libraries/sidechain/bitcoin_address.cpp new file mode 100644 index 00000000..c9f46317 --- /dev/null +++ b/libraries/sidechain/bitcoin_address.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include + +namespace sidechain { + +payment_type bitcoin_address::determine_type() +{ + if( is_p2pk() ) { + return payment_type::P2PK; + } else if( is_p2wpkh() ) { + return payment_type::P2WPKH; + } else if( is_p2wsh() ) { + return payment_type::P2WSH; + } else if( is_p2pkh() ) { + return payment_type::P2PKH; + } else if( is_p2sh() ) { + return payment_type::P2SH; + } else { + return payment_type::NULLDATA; + } +} + +bytes bitcoin_address::determine_raw_address( const payment_type& type ) +{ + bytes result; + switch( type ) { + case payment_type::P2PK : { + result = parse_hex( address ); + break; + } + case payment_type::P2WPKH : + case payment_type::P2WSH : { + std::string prefix( address.compare(0,4,"bcrt") == 0 ? std::string( address.begin(), address.begin() + 4 ) : + std::string( address.begin(), address.begin() + 2 ) ); + const auto& decode_bech32 = segwit_addr::decode( prefix, address ); + result = bytes( decode_bech32.second.begin(), decode_bech32.second.end() ); + break; + } + case payment_type::P2SH_WPKH : + case payment_type::P2SH_WSH : + case payment_type::P2PKH : + case payment_type::P2SH : { + bytes hex_addr = fc::from_base58( address ); + result = bytes( hex_addr.begin() + 1, hex_addr.begin() + 21 ); + break; + } + case payment_type::NULLDATA : return result; + } + return result; +} + +bool bitcoin_address::check_segwit_address( const size_segwit_address& size ) const { + if( !address.compare(0,4,"bcrt") || !address.compare(0,2,"bc") || !address.compare(0,2,"tb") ) { + std::string prefix( !address.compare(0,4,"bcrt") ? std::string(address.begin(), address.begin() + 4) : + std::string(address.begin(), address.begin() + 2) ); + + const auto& decode_bech32 = segwit_addr::decode( prefix, address ); + + if( decode_bech32.first == -1 || decode_bech32.second.size() != size ) { + return false; + } + + return true; + } + return false; +} + +bool bitcoin_address::is_p2pk() const +{ + try { + bool prefix = !address.compare(0,2,"02") || !address.compare(0,2,"03"); + if( address.size() == 66 && prefix ) { + parse_hex( address ); + return true; + } + } catch( fc::exception e ) { + return false; + } + return false; +} + +bool bitcoin_address::is_p2wpkh() const +{ + return check_segwit_address( size_segwit_address::P2WPKH ); +} + +bool bitcoin_address::is_p2wsh() const +{ + return check_segwit_address( size_segwit_address::P2WSH ); +} + +bool bitcoin_address::is_p2pkh() const +{ + try { + bytes hex_addr = fc::from_base58( address ); + if( hex_addr.size() == 25 && ( static_cast( hex_addr[0] ) == 0x00 || + static_cast( hex_addr[0] ) == 0x6f ) ) { + return true; + } + return false; + } catch( fc::exception e ) { + return false; + } +} + +bool bitcoin_address::is_p2sh() const +{ + try { + bytes hex_addr = fc::from_base58( address ); + if( hex_addr.size() == 25 && ( static_cast( hex_addr[0] ) == 0x05 || + static_cast( hex_addr[0] ) == 0xc4 ) ) { + return true; + } + return false; + } catch( fc::exception e ) { + return false; + } +} + +btc_multisig_address::btc_multisig_address( const size_t n_required, const accounts_keys& keys ) : + keys_required ( n_required ), witnesses_keys( keys ) +{ + create_redeem_script(); + create_address(); + type = payment_type::P2SH; +} + +size_t btc_multisig_address::count_intersection( const accounts_keys& keys ) const +{ + FC_ASSERT( keys.size() > 0 ); + + int intersections_count = 0; + for( auto& key : keys ) { + auto witness_key = witnesses_keys.find( key.first ); + if( witness_key == witnesses_keys.end() ) continue; + if( key.second == witness_key->second ) + intersections_count++; + } + return intersections_count; +} + +void btc_multisig_address::create_redeem_script() +{ + FC_ASSERT( keys_required > 0 ); + FC_ASSERT( keys_required < witnesses_keys.size() ); + redeem_script.clear(); + redeem_script.push_back( op[keys_required - 1] ); + for( const auto& key : witnesses_keys ) { + std::stringstream ss; + ss << std::hex << key.second.key_data.size(); + auto key_size_hex = sidechain::parse_hex( ss.str() ); + redeem_script.insert( redeem_script.end(), key_size_hex.begin(), key_size_hex.end() ); + redeem_script.insert( redeem_script.end(), key.second.key_data.begin(), key.second.key_data.end() ); + } + redeem_script.push_back( op[witnesses_keys.size() - 1] ); + redeem_script.push_back( OP_CHECKMULTISIG ); +} + +void btc_multisig_address::create_address() +{ + FC_ASSERT( redeem_script.size() > 0 ); + raw_address.clear(); + fc::sha256 hash256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() ); + fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); + bytes temp_addr_hash( sidechain::parse_hex( hash160.str() ) ); + + raw_address.push_back( OP_HASH160 ); + std::stringstream ss; + ss << std::hex << temp_addr_hash.size(); + auto address_size_hex = sidechain::parse_hex( ss.str() ); + raw_address.insert( raw_address.end(), address_size_hex.begin(), address_size_hex.end() ); + raw_address.insert( raw_address.end(), temp_addr_hash.begin(), temp_addr_hash.end() ); + raw_address.push_back( OP_EQUAL ); +} + +btc_multisig_segwit_address::btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ) : + btc_multisig_address( n_required, keys ) +{ + create_witness_script(); + create_segwit_address(); + type = payment_type::P2SH; +} + +bool btc_multisig_segwit_address::operator==( const btc_multisig_segwit_address& addr ) const +{ + if( address != addr.address || redeem_script != addr.redeem_script || + witnesses_keys != addr.witnesses_keys || witness_script != addr.witness_script || + raw_address != addr.raw_address ) + return false; + return true; +} + +void btc_multisig_segwit_address::create_witness_script() +{ + const auto redeem_sha256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() ); + witness_script.push_back( OP_0 ); + witness_script.push_back( 0x20 ); // PUSH_32 + witness_script.insert( witness_script.end(), redeem_sha256.data(), redeem_sha256.data() + redeem_sha256.data_size() ); +} + +void btc_multisig_segwit_address::create_segwit_address() +{ + fc::sha256 hash256 = fc::sha256::hash( witness_script.data(), witness_script.size() ); + fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); + + raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size() ); + address = fc::to_base58( get_address_bytes( raw_address ) ); +} + +bytes btc_multisig_segwit_address::get_address_bytes( const bytes& script_hash ) +{ + bytes address_bytes( 1, TESTNET_SCRIPT ); // 1 byte version + address_bytes.insert( address_bytes.end(), script_hash.begin(), script_hash.end() ); + fc::sha256 hash256 = fc::sha256::hash( fc::sha256::hash( address_bytes.data(), address_bytes.size() ) ); + address_bytes.insert( address_bytes.end(), hash256.data(), hash256.data() + 4 ); // 4 byte checksum + + return address_bytes; +} + +} diff --git a/libraries/sidechain/btc_multisig_address.cpp b/libraries/sidechain/btc_multisig_address.cpp deleted file mode 100644 index 90f2ff95..00000000 --- a/libraries/sidechain/btc_multisig_address.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include - -namespace sidechain { - -btc_multisig_address::btc_multisig_address( const size_t n_required, const accounts_keys& keys ) : - keys_required ( n_required ), witnesses_keys( keys ) -{ - create_redeem_script(); - create_address(); -} - -size_t btc_multisig_address::count_intersection( const accounts_keys& keys ) const -{ - FC_ASSERT( keys.size() > 0 ); - - int intersections_count = 0; - for( auto& key : keys ) { - auto witness_key = witnesses_keys.find( key.first ); - if( witness_key == witnesses_keys.end() ) continue; - if( key.second == witness_key->second ) - intersections_count++; - } - return intersections_count; -} - -void btc_multisig_address::create_redeem_script() -{ - FC_ASSERT( keys_required > 0 ); - FC_ASSERT( keys_required < witnesses_keys.size() ); - redeem_script.clear(); - redeem_script.push_back( op[keys_required - 1] ); - for( const auto& key : witnesses_keys ) { - std::stringstream ss; - ss << std::hex << key.second.key_data.size(); - auto key_size_hex = sidechain::parse_hex( ss.str() ); - redeem_script.insert( redeem_script.end(), key_size_hex.begin(), key_size_hex.end() ); - redeem_script.insert( redeem_script.end(), key.second.key_data.begin(), key.second.key_data.end() ); - } - redeem_script.push_back( op[witnesses_keys.size() - 1] ); - redeem_script.push_back( OP_CHECKMULTISIG ); -} - -void btc_multisig_address::create_address() -{ - FC_ASSERT( redeem_script.size() > 0 ); - address.clear(); - fc::sha256 hash256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() ); - fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); - std::vector temp_addr_hash( sidechain::parse_hex( hash160.str() ) ); - - address.push_back( OP_HASH160 ); - std::stringstream ss; - ss << std::hex << temp_addr_hash.size(); - auto address_size_hex = sidechain::parse_hex( ss.str() ); - address.insert( address.end(), address_size_hex.begin(), address_size_hex.end() ); - address.insert( address.end(), temp_addr_hash.begin(), temp_addr_hash.end() ); - address.push_back( OP_EQUAL ); -} - -btc_multisig_segwit_address::btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ) : - btc_multisig_address( n_required, keys ) -{ - create_witness_script(); - create_segwit_address(); -} - -bool btc_multisig_segwit_address::operator==( const btc_multisig_segwit_address& addr ) const -{ - if( address != addr.address || redeem_script != addr.redeem_script || - witnesses_keys != addr.witnesses_keys || witness_script != addr.witness_script || - segwit_address != addr.segwit_address || base58_address != addr.base58_address ) - return false; - return true; -} - -void btc_multisig_segwit_address::create_witness_script() -{ - const auto redeem_sha256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() ); - witness_script.push_back( OP_0 ); - witness_script.push_back( 0x20 ); // PUSH_32 - witness_script.insert( witness_script.end(), redeem_sha256.data(), redeem_sha256.data() + redeem_sha256.data_size() ); -} - -void btc_multisig_segwit_address::create_segwit_address() -{ - fc::sha256 hash256 = fc::sha256::hash( witness_script.data(), witness_script.size() ); - fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); - - segwit_address = std::vector(hash160.data(), hash160.data() + hash160.data_size() ); - base58_address = fc::to_base58( get_address_bytes( segwit_address ) ); -} - -std::vector btc_multisig_segwit_address::get_address_bytes( const std::vector& script_hash ) -{ - std::vector address_bytes( 1, TESTNET_SCRIPT ); // 1 byte version - address_bytes.insert( address_bytes.end(), script_hash.begin(), script_hash.end() ); - fc::sha256 hash256 = fc::sha256::hash( fc::sha256::hash( address_bytes.data(), address_bytes.size() ) ); - address_bytes.insert( address_bytes.end(), hash256.data(), hash256.data() + 4 ); // 4 byte checksum - - return address_bytes; -} - -} diff --git a/libraries/sidechain/include/sidechain/bech32.hpp b/libraries/sidechain/include/sidechain/bech32.hpp new file mode 100644 index 00000000..d5361312 --- /dev/null +++ b/libraries/sidechain/include/sidechain/bech32.hpp @@ -0,0 +1,24 @@ +// Copyright (c) 2017 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Bech32 is a string encoding format used in newer address types. +// The output consists of a human-readable part (alphanumeric), a +// separator character (1), and a base32 data section, the last +// 6 characters of which are a checksum. +// +// For more information, see BIP 173. + +#include +#include +#include + +namespace sidechain { namespace bech32 { + +/** Encode a Bech32 string. Returns the empty string in case of failure. */ +std::string Encode(const std::string& hrp, const std::vector& values); + +/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */ +std::pair> Decode(const std::string& str); + +} } // namespace sidechain::bech32 diff --git a/libraries/sidechain/include/sidechain/bitcoin_address.hpp b/libraries/sidechain/include/sidechain/bitcoin_address.hpp new file mode 100644 index 00000000..a6536201 --- /dev/null +++ b/libraries/sidechain/include/sidechain/bitcoin_address.hpp @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +using namespace graphene::chain; + +namespace sidechain { + +const bytes op = {0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f}; // OP_1 - OP_15 + +class bitcoin_address +{ + +public: + + bitcoin_address() = default; + + bitcoin_address( const std::string& addr ) : address( addr ), type( determine_type() ), + raw_address( determine_raw_address( type ) ) {} + + payment_type get_type() const { return type; } + + std::string get_address() const { return address; } + + bytes get_raw_address() const { return raw_address; } + +private: + + enum size_segwit_address { P2WSH = 32, P2WPKH = 20 }; + + payment_type determine_type(); + + bytes determine_raw_address( const payment_type& type ); + + bool check_segwit_address( const size_segwit_address& size ) const; + + bool is_p2pk() const; + + bool is_p2wpkh() const; + + bool is_p2wsh() const; + + bool is_p2pkh() const; + + bool is_p2sh() const; + +public: + + std::string address; + + payment_type type; + + bytes raw_address; + +}; + +class btc_multisig_address : public bitcoin_address +{ + +public: + + btc_multisig_address() = default; + + btc_multisig_address( const size_t n_required, const accounts_keys& keys ); + + size_t count_intersection( const accounts_keys& keys ) const; + + bytes get_redeem_script() const { return redeem_script; } + +private: + + void create_redeem_script(); + + void create_address(); + +public: + + enum address_types { MAINNET_SCRIPT = 5, TESTNET_SCRIPT = 196 }; + + enum { OP_0 = 0x00, OP_EQUAL = 0x87, OP_HASH160 = 0xa9, OP_CHECKMULTISIG = 0xae }; + + bytes redeem_script; + + size_t keys_required = 0; + + accounts_keys witnesses_keys; + +}; + +// multisig segwit address (P2WSH) +// https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa +class btc_multisig_segwit_address : public btc_multisig_address +{ + +public: + + btc_multisig_segwit_address() = default; + + btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ); + + bool operator==( const btc_multisig_segwit_address& addr ) const; + + bytes get_witness_script() const { return witness_script; } + +private: + + void create_witness_script(); + + void create_segwit_address(); + + bytes get_address_bytes( const bytes& script_hash ); + +public: + + bytes witness_script; + +}; + +} + +FC_REFLECT( sidechain::bitcoin_address, (address)(type)(raw_address) ); + +FC_REFLECT_DERIVED( sidechain::btc_multisig_address, (sidechain::bitcoin_address), + (redeem_script)(keys_required)(witnesses_keys) ); + +FC_REFLECT_DERIVED( sidechain::btc_multisig_segwit_address, (sidechain::btc_multisig_address), (witness_script) ); diff --git a/libraries/sidechain/include/sidechain/btc_multisig_address.hpp b/libraries/sidechain/include/sidechain/btc_multisig_address.hpp deleted file mode 100644 index e25594eb..00000000 --- a/libraries/sidechain/include/sidechain/btc_multisig_address.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -using namespace graphene::chain; - -namespace sidechain { - -const std::vector op = {0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f}; // OP_1 - OP_15 -typedef std::map< account_id_type, public_key_type > accounts_keys; - -class btc_multisig_address -{ - -public: - - btc_multisig_address() = default; - - btc_multisig_address( const size_t n_required, const accounts_keys& keys ); - - size_t count_intersection( const accounts_keys& keys ) const; - - virtual std::vector< char > get_hex_address() { return address; } - - std::vector< char > get_redeem_script() { return redeem_script; } - -private: - - void create_redeem_script(); - - void create_address(); - -public: - - enum address_types { MAINNET_SCRIPT = 5, TESTNET_SCRIPT = 196 }; - - enum { OP_0 = 0x00, OP_EQUAL = 0x87, OP_HASH160 = 0xa9, OP_CHECKMULTISIG = 0xae }; - - std::vector< char > address; - - std::vector< char > redeem_script; - - size_t keys_required = 0; - - accounts_keys witnesses_keys; - -}; - -// multisig segwit address (P2WSH) -// https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa -class btc_multisig_segwit_address : public btc_multisig_address -{ - -public: - - btc_multisig_segwit_address() = default; - - btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ); - - bool operator==( const btc_multisig_segwit_address& addr ) const; - - std::vector< char > get_hex_address() override { return segwit_address; } - - std::string get_base58_address() { return base58_address; } - - std::vector< char > get_witness_script() { return witness_script; } - -private: - - void create_witness_script(); - - void create_segwit_address(); - - std::vector get_address_bytes( const std::vector& script_hash ); - -public: - - std::vector< char > segwit_address; - - std::vector< char > witness_script; - - std::string base58_address; - -}; - -} - -FC_REFLECT( sidechain::btc_multisig_address, (address)(redeem_script)(keys_required)(witnesses_keys) ); - -FC_REFLECT_DERIVED( sidechain::btc_multisig_segwit_address, (sidechain::btc_multisig_address), - (segwit_address)(witness_script)(base58_address) ); diff --git a/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp b/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp index 19b4b8f3..bc36f123 100644 --- a/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp +++ b/libraries/sidechain/include/sidechain/input_withdrawal_info.hpp @@ -1,12 +1,10 @@ #pragma once -#include -#include - #include #include #include +#include #include #include @@ -32,7 +30,7 @@ struct info_for_vin { info_for_vin() = default; - info_for_vin( const prev_out& _out, const std::string& _address, std::vector _script = std::vector() ) : + info_for_vin( const prev_out& _out, const std::string& _address, bytes _script = bytes() ) : id( count_id_info_for_vin++ ), out( _out ), address( _address ), script( _script ) { identifier = fc::sha256::hash( out.hash_tx + std::to_string( out.n_vout ) ); } @@ -48,7 +46,7 @@ struct info_for_vin prev_out out; std::string address; - std::vector script; + bytes script; bool created = false; }; @@ -77,7 +75,7 @@ public: input_withdrawal_info( graphene::chain::database& _db ) : db( _db ) {} - void insert_info_for_vin( const prev_out& out, const std::string& address, std::vector script = std::vector() ); + void insert_info_for_vin( const prev_out& out, const std::string& address, bytes script = bytes() ); void modify_info_for_vin( const info_for_vin& obj, const std::function& func ); @@ -92,7 +90,7 @@ public: std::vector get_info_for_vins(); - void insert_info_for_vout( const graphene::chain::account_id_type& payer, /*ayment_type addr_type,*/ const std::string& data, const uint64_t& amount ); + void insert_info_for_vout( const graphene::chain::account_id_type& payer, const payment_type addr_type, const std::string& data, const uint64_t& amount ); void mark_as_used_vout( const graphene::chain::info_for_vout_object& obj ); diff --git a/libraries/sidechain/include/sidechain/segwit_addr.hpp b/libraries/sidechain/include/sidechain/segwit_addr.hpp new file mode 100644 index 00000000..d115e035 --- /dev/null +++ b/libraries/sidechain/include/sidechain/segwit_addr.hpp @@ -0,0 +1,34 @@ +/* Copyright (c) 2017 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +namespace sidechain { namespace segwit_addr { + +/** Decode a SegWit address. Returns (witver, witprog). witver = -1 means failure. */ +std::pair > decode(const std::string& hrp, const std::string& addr); + +/** Encode a SegWit address. Empty string means failure. */ +std::string encode(const std::string& hrp, int witver, const std::vector& witprog); + +} } diff --git a/libraries/sidechain/include/sidechain/types.hpp b/libraries/sidechain/include/sidechain/types.hpp new file mode 100644 index 00000000..fe7844be --- /dev/null +++ b/libraries/sidechain/include/sidechain/types.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace sidechain { + +using bytes = std::vector; +using accounts_keys = std::map< graphene::chain::account_id_type, graphene::chain::public_key_type >; + +enum class payment_type { + NULLDATA, + P2PK, + P2PKH, + P2SH, + P2WPKH, + P2WSH, + P2SH_WPKH, + P2SH_WSH +}; + +} + +FC_REFLECT_ENUM( sidechain::payment_type, (NULLDATA)(P2PK)(P2PKH)(P2SH)(P2WPKH)(P2WSH)(P2SH_WPKH)(P2SH_WSH) ); diff --git a/libraries/sidechain/include/sidechain/utils.hpp b/libraries/sidechain/include/sidechain/utils.hpp index fbcf75f6..e9b624fd 100644 --- a/libraries/sidechain/include/sidechain/utils.hpp +++ b/libraries/sidechain/include/sidechain/utils.hpp @@ -1,11 +1,10 @@ #pragma once -#include -#include +#include #include namespace sidechain { -std::vector parse_hex( const std::string& str ); +bytes parse_hex( const std::string& str ); } diff --git a/libraries/sidechain/input_withdrawal_info.cpp b/libraries/sidechain/input_withdrawal_info.cpp index 3871ac87..bd807d9e 100644 --- a/libraries/sidechain/input_withdrawal_info.cpp +++ b/libraries/sidechain/input_withdrawal_info.cpp @@ -13,7 +13,7 @@ bool info_for_vin::comparer::operator() ( const info_for_vin& lhs, const info_fo return lhs.id < rhs.id; } -void input_withdrawal_info::insert_info_for_vin( const prev_out& out, const std::string& address, std::vector script ) +void input_withdrawal_info::insert_info_for_vin( const prev_out& out, const std::string& address, bytes script ) { info_for_vins.insert( info_for_vin( out, address, script ) ); } @@ -49,6 +49,7 @@ std::vector input_withdrawal_info::get_info_for_vins() { for( size_t i = 0; itr_b != itr_e && i < 5 && !itr_b->created; i++ ) { // 5 amount vins to bitcoin transaction info_for_vin vin; + vin.id = itr_b->id; vin.identifier = itr_b->identifier; vin.out.hash_tx = itr_b->out.hash_tx; vin.out.n_vout = itr_b->out.n_vout; @@ -64,11 +65,11 @@ std::vector input_withdrawal_info::get_info_for_vins() return result; } -void input_withdrawal_info::insert_info_for_vout( const graphene::chain::account_id_type& payer, /*ayment_type addr_type,*/ const std::string& data, const uint64_t& amount ) +void input_withdrawal_info::insert_info_for_vout( const graphene::chain::account_id_type& payer, const payment_type addr_type, const std::string& data, const uint64_t& amount ) { db.create([&](graphene::chain::info_for_vout_object& obj) { obj.payer = payer; - // obj.addr_type = addr_type; + obj.addr_type = addr_type; obj.data = data; obj.amount = amount; }); @@ -108,7 +109,7 @@ std::vector input_withdrawal_info::get_info_for_vouts() for(size_t i = 0; i < 5 && itr != info_for_vout_idx.end() && !itr->created; i++) { info_for_vout vout; vout.payer = itr->payer; - // vout.addr_type = itr->addr_type; + vout.addr_type = itr->addr_type; vout.data = itr->data; vout.amount = itr->amount; diff --git a/libraries/sidechain/network/include/sidechain/network/sidechain_net_manager.hpp b/libraries/sidechain/network/include/sidechain/network/sidechain_net_manager.hpp index befff470..7be2cdd0 100644 --- a/libraries/sidechain/network/include/sidechain/network/sidechain_net_manager.hpp +++ b/libraries/sidechain/network/include/sidechain/network/sidechain_net_manager.hpp @@ -33,6 +33,10 @@ private: void handle_block( const std::string& block_hash ); + std::vector extract_info_from_block( const std::string& _block ); + + inline uint64_t parse_amount(std::string raw); + std::unique_ptr listener; std::unique_ptr bitcoin_client; std::unique_ptr db; diff --git a/libraries/sidechain/network/sidechain_net_manager.cpp b/libraries/sidechain/network/sidechain_net_manager.cpp index 1ecd20f6..220a30c0 100644 --- a/libraries/sidechain/network/sidechain_net_manager.cpp +++ b/libraries/sidechain/network/sidechain_net_manager.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include + namespace sidechain { sidechain_net_manager::sidechain_net_manager( graphene::chain::database* _db, std::string _ip, @@ -24,12 +27,55 @@ void sidechain_net_manager::initialize_manager( graphene::chain::database* _db, } ); } +std::vector sidechain_net_manager::extract_info_from_block( const std::string& _block ) +{ + +// std::map test = { {"2MsmG481n4W4AC1QcPgBUJQrVRTrLNM2GpB", false}, +// {"2N2LkZG2Zp9eXGjSJzP9taR1gYdZBPzH7S7", false}, +// {"2N4MCW3XggAxs9C8Dh2vNcx7uH8zUqoLMjA", false}, +// {"2NEkNoDyQ9tyREFDAPehi9Jr2m6EFiTDxAS", false}, +// {"2N1rQcKr4F14L8dfnNiUVpc4LzcZTWN9Kpd", false} }; + + std::stringstream ss( _block ); + boost::property_tree::ptree block; + boost::property_tree::read_json( ss, block ); + + std::vector result; + + for (const auto& tx_child : block.get_child("tx")) { + const auto& tx = tx_child.second; + + for ( const auto& o : tx.get_child("vout") ) { + const auto script = o.second.get_child("scriptPubKey"); + + if( !script.count("addresses") ) continue; + + for (const auto& addr : script.get_child("addresses")) { // in which cases there can be more addresses? + const auto address_base58 = addr.second.get_value(); + + // if( !test.count( address_base58 ) ) continue; // there is such an address in graphene + + info_for_vin vin; + vin.out.hash_tx = tx.get_child("txid").get_value(); + vin.out.amount = parse_amount( o.second.get_child( "value" ).get_value() ); + vin.out.n_vout = o.second.get_child( "n" ).get_value(); + vin.address = address_base58; + result.push_back( vin ); + } + } + } + + return result; +} void sidechain_net_manager::update_tx_infos( const std::string& block_hash ) { std::string block = bitcoin_client->receive_full_block( block_hash ); if( block != "" ) { - + const auto& vins = extract_info_from_block( block ); + for( const auto& v : vins ) { + db->i_w_info.insert_info_for_vin( prev_out{ v.out.hash_tx, v.out.n_vout, v.out.amount }, v.address ); + } } } @@ -60,4 +106,10 @@ void sidechain_net_manager::handle_block( const std::string& block_hash ) update_tx_infos( block_hash ); } +// Removes dot from amount output: "50.00000000" +inline uint64_t sidechain_net_manager::parse_amount(std::string raw) { + raw.erase(std::remove(raw.begin(), raw.end(), '.'), raw.end()); + return std::stoll(raw); +} + } \ No newline at end of file diff --git a/libraries/sidechain/segwit_addr.cpp b/libraries/sidechain/segwit_addr.cpp new file mode 100644 index 00000000..ce7b33ad --- /dev/null +++ b/libraries/sidechain/segwit_addr.cpp @@ -0,0 +1,81 @@ +/* Copyright (c) 2017 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +namespace +{ + +typedef std::vector data; + +/** Convert from one power-of-2 number base to another. */ +template +bool convertbits(data& out, const data& in) { + int acc = 0; + int bits = 0; + const int maxv = (1 << tobits) - 1; + const int max_acc = (1 << (frombits + tobits - 1)) - 1; + for (size_t i = 0; i < in.size(); ++i) { + int value = in[i]; + acc = ((acc << frombits) | value) & max_acc; + bits += frombits; + while (bits >= tobits) { + bits -= tobits; + out.push_back((acc >> bits) & maxv); + } + } + if (pad) { + if (bits) out.push_back((acc << (tobits - bits)) & maxv); + } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { + return false; + } + return true; +} + +} + +namespace sidechain { namespace segwit_addr { + +/** Decode a SegWit address. */ +std::pair decode(const std::string& hrp, const std::string& addr) { + std::pair dec = sidechain::bech32::Decode(addr); + if (dec.first != hrp || dec.second.size() < 1) return std::make_pair(-1, data()); + data conv; + if (!convertbits<5, 8, false>(conv, data(dec.second.begin() + 1, dec.second.end())) || + conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 || (dec.second[0] == 0 && + conv.size() != 20 && conv.size() != 32)) { + return std::make_pair(-1, data()); + } + return std::make_pair(dec.second[0], conv); +} + +/** Encode a SegWit address. */ +std::string encode(const std::string& hrp, int witver, const data& witprog) { + data enc; + enc.push_back(witver); + convertbits<8, 5, true>(enc, witprog); + std::string ret = sidechain::bech32::Encode(hrp, enc); + if (decode(hrp, ret).first == -1) return ""; + return ret; +} + +} } diff --git a/libraries/sidechain/utils.cpp b/libraries/sidechain/utils.cpp index 55b47eaf..ce4c329a 100644 --- a/libraries/sidechain/utils.cpp +++ b/libraries/sidechain/utils.cpp @@ -2,9 +2,9 @@ namespace sidechain { -std::vector parse_hex( const std::string& str ) +bytes parse_hex( const std::string& str ) { - std::vector vec( str.size() / 2 ); + bytes vec( str.size() / 2 ); fc::from_hex( str, vec.data(), vec.size() ); return vec; } diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 40f24034..81ccac98 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -767,6 +767,8 @@ class wallet_api string memo, bool broadcast = false); + signed_transaction withdraw_pBTC(account_id_type payer, string to, uint64_t amount, bool broadcast = false); + /** * This method works just like transfer, except it always broadcasts and * returns the transaction ID along with the signed transaction. @@ -2057,4 +2059,5 @@ FC_API( graphene::wallet::wallet_api, (get_binned_order_book) (get_matched_bets_for_bettor) (get_all_matched_bets_for_bettor) + (withdraw_pBTC) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 1d81a6bb..993c043e 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2392,6 +2392,23 @@ public: return sign_transaction(tx, broadcast); } FC_CAPTURE_AND_RETHROW( (from)(to)(amount)(asset_symbol)(memo)(broadcast) ) } + signed_transaction withdraw_pBTC(account_id_type payer, string to, uint64_t amount, bool broadcast) + { try { + FC_ASSERT( !is_locked() ); + + withdraw_pbtc_operation withdraw_pbtc_op; + withdraw_pbtc_op.payer = payer; + withdraw_pbtc_op.data = to; + withdraw_pbtc_op.amount = amount; + + signed_transaction tx; + tx.operations.push_back(withdraw_pbtc_op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); + tx.validate(); + + return sign_transaction(tx, broadcast); + } FC_CAPTURE_AND_RETHROW( (payer)(to)(amount)(broadcast) ) } + signed_transaction issue_asset(string to_account, string amount, string symbol, string memo, bool broadcast = false) { @@ -3870,6 +3887,12 @@ signed_transaction wallet_api::transfer(string from, string to, string amount, { return my->transfer(from, to, amount, asset_symbol, memo, broadcast); } + +signed_transaction wallet_api::withdraw_pBTC(account_id_type payer, string to, uint64_t amount, bool broadcast) +{ + return my->withdraw_pBTC(payer, to, amount, broadcast); +} + signed_transaction wallet_api::create_asset(string issuer, string symbol, uint8_t precision, diff --git a/tests/tests/bitcoin_address_obj_tests.cpp b/tests/tests/bitcoin_address_obj_tests.cpp new file mode 100644 index 00000000..81bc0bb1 --- /dev/null +++ b/tests/tests/bitcoin_address_obj_tests.cpp @@ -0,0 +1,29 @@ +#include +#include "../common/database_fixture.hpp" + +#include + +#include + +using namespace graphene::chain; + +BOOST_FIXTURE_TEST_SUITE( bitcoin_addresses_obj_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE( create_bitcoin_address_test ) { + transaction_evaluation_state context(&db); + + bitcoin_address_create_operation op; + op.payer = account_id_type(); + op.owner = account_id_type(); + + const auto& idx = db.get_index_type().indices().get< by_id >(); + + BOOST_CHECK( idx.size() == 0 ); + + db.apply_operation( context, op ); + + auto btc_address = idx.begin(); + BOOST_CHECK(btc_address->count_invalid_pub_key == 1); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/tests/tests/bitcoin_address_tests.cpp b/tests/tests/bitcoin_address_tests.cpp new file mode 100644 index 00000000..a98fa5f7 --- /dev/null +++ b/tests/tests/bitcoin_address_tests.cpp @@ -0,0 +1,132 @@ +#include +#include + +using namespace sidechain; + +BOOST_AUTO_TEST_SUITE( bitcoin_address_tests ) + +fc::ecc::public_key_data create_public_key_data( const std::vector& public_key ) +{ + FC_ASSERT( public_key.size() == 33 ); + fc::ecc::public_key_data key; + for(size_t i = 0; i < 33; i++) { + key.at(i) = public_key[i]; + } + return key; +} + +BOOST_AUTO_TEST_CASE( addresses_type_test ) +{ + // public_key + std::string compressed( "03df51984d6b8b8b1cc693e239491f77a36c9e9dfe4a486e9972a18e03610a0d22" ); + BOOST_CHECK( bitcoin_address( compressed ).get_type() == payment_type::P2PK ); + + std::string uncompressed( "04fe53c78e36b86aae8082484a4007b706d5678cabb92d178fc95020d4d8dc41ef44cfbb8dfa7a593c7910a5b6f94d079061a7766cbeed73e24ee4f654f1e51904" ); + BOOST_CHECK( bitcoin_address( uncompressed ).get_type() == payment_type::NULLDATA ); + + + // segwit_address + std::string p2wpkh_mainnet( "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" ); + BOOST_CHECK( bitcoin_address( p2wpkh_mainnet ).get_type() == payment_type::P2WPKH ); + + std::string p2wpkh_testnet( "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" ); + BOOST_CHECK( bitcoin_address( p2wpkh_testnet ).get_type() == payment_type::P2WPKH ); + + std::string p2wsh( "bc1qc7slrfxkknqcq2jevvvkdgvrt8080852dfjewde450xdlk4ugp7szw5tk9" ); + BOOST_CHECK( bitcoin_address( p2wsh ).get_type() == payment_type::P2WSH ); + + + // base58 + std::string p2pkh_mainnet( "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem" ); + BOOST_CHECK( bitcoin_address( p2pkh_mainnet ).get_type() == payment_type::P2PKH ); + + std::string p2pkh_testnet( "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn" ); + BOOST_CHECK( bitcoin_address( p2pkh_testnet ).get_type() == payment_type::P2PKH ); + + std::string p2sh_mainnet( "3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX" ); + BOOST_CHECK( bitcoin_address( p2sh_mainnet ).get_type() == payment_type::P2SH ); + + std::string p2sh_testnet( "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc" ); + BOOST_CHECK( bitcoin_address( p2sh_testnet ).get_type() == payment_type::P2SH ); +} + +BOOST_AUTO_TEST_CASE( addresses_raw_test ) +{ + // public_key + std::string compressed( "03df51984d6b8b8b1cc693e239491f77a36c9e9dfe4a486e9972a18e03610a0d22" ); + bytes standard_compressed( parse_hex( compressed ) ); + BOOST_CHECK( bitcoin_address( compressed ).get_raw_address() == standard_compressed ); + + std::string uncompressed( "04fe53c78e36b86aae8082484a4007b706d5678cabb92d178fc95020d4d8dc41ef44cfbb8dfa7a593c7910a5b6f94d079061a7766cbeed73e24ee4f654f1e51904" ); + BOOST_CHECK( bitcoin_address( uncompressed ).get_raw_address() == bytes() ); + + + // segwit_address + std::string p2wpkh_mainnet( "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" ); + bytes standard_p2wpkh_mainnet( parse_hex( "751e76e8199196d454941c45d1b3a323f1433bd6" ) ); + BOOST_CHECK( bitcoin_address( p2wpkh_mainnet ).get_raw_address() == standard_p2wpkh_mainnet ); + + std::string p2wpkh_testnet( "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" ); + bytes standard_p2wpkh_testnet( parse_hex( "751e76e8199196d454941c45d1b3a323f1433bd6" ) ); + BOOST_CHECK( bitcoin_address( p2wpkh_testnet ).get_raw_address() == standard_p2wpkh_testnet ); + + std::string p2wsh( "bc1qc7slrfxkknqcq2jevvvkdgvrt8080852dfjewde450xdlk4ugp7szw5tk9" ); + bytes standard_p2wsh( parse_hex( "c7a1f1a4d6b4c1802a59631966a18359de779e8a6a65973735a3ccdfdabc407d" ) ); + BOOST_CHECK( bitcoin_address( p2wsh ).get_raw_address() == standard_p2wsh ); + + + // base58 + std::string p2pkh_mainnet( "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem" ); + bytes standard_p2pkh_mainnet( parse_hex( "47376c6f537d62177a2c41c4ca9b45829ab99083" ) ); + BOOST_CHECK( bitcoin_address( p2pkh_mainnet ).get_raw_address() == standard_p2pkh_mainnet ); + + std::string p2pkh_testnet( "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn" ); + bytes standard_p2pkh_testnet( parse_hex( "243f1394f44554f4ce3fd68649c19adc483ce924" ) ); + BOOST_CHECK( bitcoin_address( p2pkh_testnet ).get_raw_address() == standard_p2pkh_testnet ); + + std::string p2sh_mainnet( "3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX" ); + bytes standard_p2sh_mainnet( parse_hex( "8f55563b9a19f321c211e9b9f38cdf686ea07845" ) ); + BOOST_CHECK( bitcoin_address( p2sh_mainnet ).get_raw_address() == standard_p2sh_mainnet ); + + std::string p2sh_testnet( "2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc" ); + bytes standard_p2sh_testnet( parse_hex( "4e9f39ca4688ff102128ea4ccda34105324305b0" ) ); + BOOST_CHECK( bitcoin_address( p2sh_testnet ).get_raw_address() == standard_p2sh_testnet ); +} + +BOOST_AUTO_TEST_CASE( create_multisig_address_test ) { + + std::vector public_key1 = parse_hex( "03db643710666b862e0a97f7edbe8ef40ec2c4a29ef995c431c21ca85e35000010" ); + std::vector public_key2 = parse_hex( "0320000d982c156a6f09df8c7674abddc2bb326533268ed03572916221b4417983" ); + std::vector public_key3 = parse_hex( "033619e682149aef0c3e2dee3dc5107dd78cb2c14bf0bd25b59056259fbb37ec3f" ); + + std::vector address = parse_hex( "a91460cb986f0926e7c4ca1984ca9f56767da2af031e87" ); + std::vector redeem_script = parse_hex( "522103db643710666b862e0a97f7edbe8ef40ec2c4a29ef995c431c21ca85e35000010210320000d982c156a6f09df8c7674abddc2bb326533268ed03572916221b441798321033619e682149aef0c3e2dee3dc5107dd78cb2c14bf0bd25b59056259fbb37ec3f53ae" ); + + fc::ecc::public_key_data key1 = create_public_key_data( public_key1 ); + fc::ecc::public_key_data key2 = create_public_key_data( public_key2 ); + fc::ecc::public_key_data key3 = create_public_key_data( public_key3 ); + + sidechain::btc_multisig_address cma(2, { { account_id_type(1), public_key_type(key1) }, { account_id_type(2), public_key_type(key2) }, { account_id_type(3), public_key_type(key3) } }); + + BOOST_CHECK( address == cma.raw_address ); + BOOST_CHECK( redeem_script == cma.redeem_script ); +} + +BOOST_AUTO_TEST_CASE( create_segwit_address_test ) { + // https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa + std::vector public_key1 = parse_hex( "03b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb" ); + std::vector public_key2 = parse_hex( "03dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba6" ); + std::vector public_key3 = parse_hex( "033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be1" ); + + std::vector witness_script = parse_hex("0020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1"); + + fc::ecc::public_key_data key1 = create_public_key_data( public_key1 ); + fc::ecc::public_key_data key2 = create_public_key_data( public_key2 ); + fc::ecc::public_key_data key3 = create_public_key_data( public_key3 ); + + sidechain::btc_multisig_segwit_address address(2, { { account_id_type(1), public_key_type(key1) }, { account_id_type(2), public_key_type(key2) }, { account_id_type(3), public_key_type(key3) } }); + BOOST_CHECK( address.get_witness_script() == witness_script ); + BOOST_CHECK( address.get_address() == "2NGU4ogScHEHEpReUzi9RB2ha58KAFnkFyk" ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/btc_multisig_address_tests.cpp b/tests/tests/btc_multisig_address_tests.cpp deleted file mode 100644 index 2d19b1e7..00000000 --- a/tests/tests/btc_multisig_address_tests.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include - -using namespace sidechain; - -fc::ecc::public_key_data create_public_key_data( const std::vector& public_key ) -{ - FC_ASSERT( public_key.size() == 33 ); - fc::ecc::public_key_data key; - for(size_t i = 0; i < 33; i++) { - key.at(i) = public_key[i]; - } - return key; -} - -BOOST_AUTO_TEST_SUITE( btc_multisig_address_tests ) - -BOOST_AUTO_TEST_CASE( create_multisig_address_test ) { - - std::vector public_key1 = parse_hex( "03db643710666b862e0a97f7edbe8ef40ec2c4a29ef995c431c21ca85e35000010" ); - std::vector public_key2 = parse_hex( "0320000d982c156a6f09df8c7674abddc2bb326533268ed03572916221b4417983" ); - std::vector public_key3 = parse_hex( "033619e682149aef0c3e2dee3dc5107dd78cb2c14bf0bd25b59056259fbb37ec3f" ); - - std::vector address = parse_hex( "a91460cb986f0926e7c4ca1984ca9f56767da2af031e87" ); - std::vector redeem_script = parse_hex( "522103db643710666b862e0a97f7edbe8ef40ec2c4a29ef995c431c21ca85e35000010210320000d982c156a6f09df8c7674abddc2bb326533268ed03572916221b441798321033619e682149aef0c3e2dee3dc5107dd78cb2c14bf0bd25b59056259fbb37ec3f53ae" ); - - fc::ecc::public_key_data key1 = create_public_key_data( public_key1 ); - fc::ecc::public_key_data key2 = create_public_key_data( public_key2 ); - fc::ecc::public_key_data key3 = create_public_key_data( public_key3 ); - - sidechain::btc_multisig_segwit_address cma(2, { { account_id_type(1), public_key_type(key1) }, { account_id_type(2), public_key_type(key2) }, { account_id_type(3), public_key_type(key3) } }); - - BOOST_CHECK( address == cma.address ); - BOOST_CHECK( redeem_script == cma.redeem_script ); -} - -BOOST_AUTO_TEST_CASE( create_segwit_address_test ) { - // https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa - std::vector public_key1 = parse_hex( "03b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb" ); - std::vector public_key2 = parse_hex( "03dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba6" ); - std::vector public_key3 = parse_hex( "033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be1" ); - - std::vector witness_script = parse_hex("0020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1"); - - fc::ecc::public_key_data key1 = create_public_key_data( public_key1 ); - fc::ecc::public_key_data key2 = create_public_key_data( public_key2 ); - fc::ecc::public_key_data key3 = create_public_key_data( public_key3 ); - - sidechain::btc_multisig_segwit_address address(2, { { account_id_type(1), public_key_type(key1) }, { account_id_type(2), public_key_type(key2) }, { account_id_type(3), public_key_type(key3) } }); - BOOST_CHECK( address.get_witness_script() == witness_script ); - BOOST_CHECK( address.get_base58_address() == "2NGU4ogScHEHEpReUzi9RB2ha58KAFnkFyk" ); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/input_withdrawal_info_tests.cpp b/tests/tests/input_withdrawal_info_tests.cpp index 724790f6..03e00dae 100644 --- a/tests/tests/input_withdrawal_info_tests.cpp +++ b/tests/tests/input_withdrawal_info_tests.cpp @@ -1,47 +1,49 @@ #include #include #include "../common/database_fixture.hpp" +#include using namespace graphene::chain; +using namespace sidechain; BOOST_FIXTURE_TEST_SUITE( input_withdrawal_info_tests, database_fixture ) BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vin_test ) { - sidechain::input_withdrawal_info infos( db ); - sidechain::prev_out out = { "1", 1, 13 }; + input_withdrawal_info infos( db ); + prev_out out = { "1", 1, 13 }; infos.insert_info_for_vin( out, "addr1", { 0x01, 0x02, 0x03 } ); BOOST_CHECK( infos.size_info_for_vins() == 1 ); - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vin_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 1; i <= 10; i++ ) { - sidechain::prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; + prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } ); } BOOST_CHECK( infos.size_info_for_vins() == 10 ); - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_id_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - sidechain::prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; + prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } ); BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).first ); BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->id == i ); } - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_check_data_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - sidechain::prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; + prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } ); } @@ -56,13 +58,13 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_check_data_test ) { BOOST_CHECK( infos.find_info_for_vin( static_cast< uint64_t >( i ) ).second->script == script ); } - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - sidechain::prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; + prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } ); } @@ -70,7 +72,7 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) { if( i % 2 == 0 ) { auto iter = infos.find_info_for_vin( static_cast< uint64_t >( i ) ); BOOST_CHECK( iter.first ); - infos.modify_info_for_vin( *iter.second, [&]( sidechain::info_for_vin& obj ) { + infos.modify_info_for_vin( *iter.second, [&]( info_for_vin& obj ) { obj.out.hash_tx = std::to_string( i + 1 ); obj.out.n_vout = i + 1; obj.out.amount = i + 1; @@ -92,13 +94,13 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_modify_test ) { } } - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vin_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - sidechain::prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; + prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } ); } @@ -118,13 +120,13 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vin_test ) { } } - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vins_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - sidechain::prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; + prev_out out = { std::to_string( i ), static_cast( i ), static_cast< uint64_t >( i ) }; infos.insert_info_for_vin( out, "addr" + std::to_string( i ), { 0x01, 0x02, 0x03 } ); } @@ -139,27 +141,27 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vins_test ) { const auto& vins2 = infos.get_info_for_vins(); BOOST_CHECK( vins2.size() == 3 ); - sidechain::info_for_vin::count_id_info_for_vin = 0; + info_for_vin::count_id_info_for_vin = 0; } BOOST_AUTO_TEST_CASE( input_withdrawal_info_insert_vout_test ) { - sidechain::input_withdrawal_info infos( db ); - infos.insert_info_for_vout( account_id_type(), "1", 1 ); + input_withdrawal_info infos( db ); + infos.insert_info_for_vout( account_id_type(), payment_type::NULLDATA, "1", 1 ); BOOST_CHECK( infos.size_info_for_vouts() == 1 ); } BOOST_AUTO_TEST_CASE( input_withdrawal_info_many_insert_vout_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 1; i <= 10; i++ ) { - infos.insert_info_for_vout( account_id_type(i), std::to_string( i ), static_cast( i ) ); + infos.insert_info_for_vout( account_id_type(i), payment_type::NULLDATA, std::to_string( i ), static_cast( i ) ); } BOOST_CHECK( infos.size_info_for_vouts() == 10 ); } BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vout_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - infos.insert_info_for_vout( account_id_type(i), std::to_string( i ), static_cast( i ) ); + infos.insert_info_for_vout( account_id_type(i), payment_type::NULLDATA, std::to_string( i ), static_cast( i ) ); } for( size_t i = 0; i < 10; i++ ) { @@ -180,9 +182,9 @@ BOOST_AUTO_TEST_CASE( input_withdrawal_info_remove_vout_test ) { } BOOST_AUTO_TEST_CASE( input_withdrawal_info_get_info_for_vouts_test ) { - sidechain::input_withdrawal_info infos( db ); + input_withdrawal_info infos( db ); for( size_t i = 0; i < 10; i++ ) { - infos.insert_info_for_vout( account_id_type(i), std::to_string( i ), static_cast( i ) ); + infos.insert_info_for_vout( account_id_type(i), payment_type::NULLDATA, std::to_string( i ), static_cast( i ) ); } const auto& vouts = infos.get_info_for_vouts();