From bb6aac3f231660e66eab95c01b330e340204b517 Mon Sep 17 00:00:00 2001 From: Srdjan Obucina Date: Sat, 18 Apr 2020 02:46:32 +0200 Subject: [PATCH] Deposit address creation, import deposit/withdraw addresses, some code cleanup --- libraries/chain/db_notify.cpp | 6 +- .../chain/protocol/sidechain_address.hpp | 18 +- .../peerplays_sidechain/CMakeLists.txt | 1 - .../peerplays_sidechain/bitcoin_utils.cpp | 681 ------------------ .../peerplays_sidechain/bitcoin_utils.hpp | 104 --- .../sidechain_net_handler.hpp | 1 + .../sidechain_net_handler_bitcoin.hpp | 7 +- .../sidechain_net_handler_peerplays.hpp | 1 + .../sidechain_net_handler.cpp | 33 +- .../sidechain_net_handler_bitcoin.cpp | 217 +++--- .../sidechain_net_handler_peerplays.cpp | 4 + .../wallet/include/graphene/wallet/wallet.hpp | 2 +- libraries/wallet/wallet.cpp | 3 + .../bitcoin_utils_test.cpp | 400 ---------- tests/tests/sidechain_addresses_test.cpp | 6 +- 15 files changed, 167 insertions(+), 1317 deletions(-) delete mode 100644 libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp delete mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp delete mode 100644 tests/peerplays_sidechain/bitcoin_utils_test.cpp diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 0a942a76..f38225e0 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -330,13 +330,13 @@ struct get_impacted_account_visitor _impacted.insert( op.payer ); } void operator()( const sidechain_address_add_operation& op ) { - _impacted.insert( op.sidechain_address_account ); + _impacted.insert( op.payer ); } void operator()( const sidechain_address_update_operation& op ) { - _impacted.insert( op.sidechain_address_account ); + _impacted.insert( op.payer ); } void operator()( const sidechain_address_delete_operation& op ) { - _impacted.insert( op.sidechain_address_account ); + _impacted.insert( op.payer ); } void operator()( const sidechain_transaction_create_operation& op ) { _impacted.insert( op.payer ); diff --git a/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp b/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp index a9cbcc73..4fb21ebd 100644 --- a/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp +++ b/libraries/chain/include/graphene/chain/protocol/sidechain_address.hpp @@ -10,6 +10,8 @@ namespace graphene { namespace chain { struct fee_parameters_type { uint64_t fee = 0; }; asset fee; + account_id_type payer; + account_id_type sidechain_address_account; sidechain_type sidechain; string deposit_public_key; @@ -17,7 +19,7 @@ namespace graphene { namespace chain { string withdraw_public_key; string withdraw_address; - account_id_type fee_payer()const { return sidechain_address_account; } + account_id_type fee_payer()const { return payer; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } }; @@ -26,6 +28,8 @@ namespace graphene { namespace chain { struct fee_parameters_type { uint64_t fee = 0; }; asset fee; + account_id_type payer; + sidechain_address_id_type sidechain_address_id; account_id_type sidechain_address_account; sidechain_type sidechain; @@ -34,7 +38,7 @@ namespace graphene { namespace chain { optional withdraw_public_key; optional withdraw_address; - account_id_type fee_payer()const { return sidechain_address_account; } + account_id_type fee_payer()const { return payer; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } }; @@ -43,26 +47,28 @@ namespace graphene { namespace chain { struct fee_parameters_type { uint64_t fee = 0; }; asset fee; + account_id_type payer; + sidechain_address_id_type sidechain_address_id; account_id_type sidechain_address_account; sidechain_type sidechain; - account_id_type fee_payer()const { return sidechain_address_account; } + account_id_type fee_payer()const { return payer; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } }; } } // namespace graphene::chain FC_REFLECT(graphene::chain::sidechain_address_add_operation::fee_parameters_type, (fee) ) -FC_REFLECT(graphene::chain::sidechain_address_add_operation, (fee) +FC_REFLECT(graphene::chain::sidechain_address_add_operation, (fee)(payer) (sidechain_address_account)(sidechain)(deposit_public_key)(deposit_address)(withdraw_public_key)(withdraw_address) ) FC_REFLECT(graphene::chain::sidechain_address_update_operation::fee_parameters_type, (fee) ) -FC_REFLECT(graphene::chain::sidechain_address_update_operation, (fee) +FC_REFLECT(graphene::chain::sidechain_address_update_operation, (fee)(payer) (sidechain_address_id) (sidechain_address_account)(sidechain)(deposit_public_key)(deposit_address)(withdraw_public_key)(withdraw_address) ) FC_REFLECT(graphene::chain::sidechain_address_delete_operation::fee_parameters_type, (fee) ) -FC_REFLECT(graphene::chain::sidechain_address_delete_operation, (fee) +FC_REFLECT(graphene::chain::sidechain_address_delete_operation, (fee)(payer) (sidechain_address_id) (sidechain_address_account)(sidechain) ) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 849a8024..61e27b94 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -6,7 +6,6 @@ add_library( peerplays_sidechain sidechain_net_handler.cpp sidechain_net_handler_bitcoin.cpp sidechain_net_handler_peerplays.cpp - bitcoin_utils.cpp bitcoin/bech32.cpp bitcoin/bitcoin_address.cpp bitcoin/bitcoin_script.cpp diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp deleted file mode 100644 index bcc3954c..00000000 --- a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp +++ /dev/null @@ -1,681 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace graphene { namespace peerplays_sidechain { - -static const unsigned char OP_0 = 0x00; -static const unsigned char OP_1 = 0x51; -static const unsigned char OP_2 = 0x52; -static const unsigned char OP_3 = 0x53; -static const unsigned char OP_4 = 0x54; -static const unsigned char OP_5 = 0x55; -static const unsigned char OP_6 = 0x56; -static const unsigned char OP_7 = 0x57; -static const unsigned char OP_8 = 0x58; -static const unsigned char OP_9 = 0x59; -static const unsigned char OP_10 = 0x5a; -static const unsigned char OP_11 = 0x5b; -static const unsigned char OP_12 = 0x5c; -static const unsigned char OP_13 = 0x5d; -static const unsigned char OP_14 = 0x5e; -static const unsigned char OP_15 = 0x5f; -static const unsigned char OP_16 = 0x60; - -static const unsigned char OP_IF = 0x63; -static const unsigned char OP_ENDIF = 0x68; -static const unsigned char OP_SWAP = 0x7c; -static const unsigned char OP_EQUAL = 0x87; -static const unsigned char OP_ADD = 0x93; -static const unsigned char OP_GREATERTHAN = 0xa0; -static const unsigned char OP_HASH160 = 0xa9; -static const unsigned char OP_CHECKSIG = 0xac; - -class WriteBytesStream { -public: - WriteBytesStream(bytes &buffer) : - storage_(buffer) { - } - - void write(const unsigned char *d, size_t s) { - storage_.insert(storage_.end(), d, d + s); - } - - bool put(unsigned char c) { - storage_.push_back(c); - return true; - } - - void writedata8(uint8_t obj) { - write((unsigned char *)&obj, 1); - } - - void writedata16(uint16_t obj) { - obj = htole16(obj); - write((unsigned char *)&obj, 2); - } - - void writedata32(uint32_t obj) { - obj = htole32(obj); - write((unsigned char *)&obj, 4); - } - - void writedata64(uint64_t obj) { - obj = htole64(obj); - write((unsigned char *)&obj, 8); - } - - void write_compact_int(uint64_t val) { - if (val < 253) { - writedata8(val); - } else if (val <= std::numeric_limits::max()) { - writedata8(253); - writedata16(val); - } else if (val <= std::numeric_limits::max()) { - writedata8(254); - writedata32(val); - } else { - writedata8(255); - writedata64(val); - } - } - - void writedata(const bytes &data) { - write_compact_int(data.size()); - write(&data[0], data.size()); - } - -private: - bytes &storage_; -}; - -class ReadBytesStream { -public: - ReadBytesStream(const bytes &buffer, size_t pos = 0) : - storage_(buffer), - pos_(pos), - end_(buffer.size()) { - } - - size_t current_pos() const { - return pos_; - } - void set_pos(size_t pos) { - if (pos > end_) - FC_THROW("Invalid position in BTC tx buffer"); - pos_ = pos; - } - - inline bool read(unsigned char *d, size_t s) { - if (end_ - pos_ >= s) { - memcpy(d, &storage_[pos_], s); - pos_ += s; - return true; - } - FC_THROW("invalid bitcoin tx buffer"); - } - - inline bool get(unsigned char &c) { - if (pos_ < end_) { - c = storage_[pos_++]; - return true; - } - FC_THROW("invalid bitcoin tx buffer"); - } - - uint8_t readdata8() { - uint8_t obj; - read((unsigned char *)&obj, 1); - return obj; - } - uint16_t readdata16() { - uint16_t obj; - read((unsigned char *)&obj, 2); - return le16toh(obj); - } - uint32_t readdata32() { - uint32_t obj; - read((unsigned char *)&obj, 4); - return le32toh(obj); - } - uint64_t readdata64() { - uint64_t obj; - read((unsigned char *)&obj, 8); - return le64toh(obj); - } - - uint64_t read_compact_int() { - uint8_t size = readdata8(); - uint64_t ret = 0; - if (size < 253) { - ret = size; - } else if (size == 253) { - ret = readdata16(); - if (ret < 253) - FC_THROW("non-canonical ReadCompactSize()"); - } else if (size == 254) { - ret = readdata32(); - if (ret < 0x10000u) - FC_THROW("non-canonical ReadCompactSize()"); - } else { - ret = readdata64(); - if (ret < 0x100000000ULL) - FC_THROW("non-canonical ReadCompactSize()"); - } - if (ret > (uint64_t)0x02000000) - FC_THROW("ReadCompactSize(): size too large"); - return ret; - } - - void readdata(bytes &data) { - size_t s = read_compact_int(); - data.clear(); - data.resize(s); - read(&data[0], s); - } - -private: - const bytes &storage_; - size_t pos_; - size_t end_; -}; - -void btc_outpoint::to_bytes(bytes &stream) const { - WriteBytesStream str(stream); - // TODO: write size? - str.write((unsigned char *)hash.data(), hash.data_size()); - str.writedata32(n); -} - -size_t btc_outpoint::fill_from_bytes(const bytes &data, size_t pos) { - ReadBytesStream str(data, pos); - // TODO: read size? - str.read((unsigned char *)hash.data(), hash.data_size()); - n = str.readdata32(); - return str.current_pos(); -} - -void btc_in::to_bytes(bytes &stream) const { - prevout.to_bytes(stream); - WriteBytesStream str(stream); - str.writedata(scriptSig); - str.writedata32(nSequence); -} - -size_t btc_in::fill_from_bytes(const bytes &data, size_t pos) { - pos = prevout.fill_from_bytes(data, pos); - ReadBytesStream str(data, pos); - str.readdata(scriptSig); - nSequence = str.readdata32(); - return str.current_pos(); -} - -void btc_out::to_bytes(bytes &stream) const { - WriteBytesStream str(stream); - str.writedata64(nValue); - str.writedata(scriptPubKey); -} - -size_t btc_out::fill_from_bytes(const bytes &data, size_t pos) { - ReadBytesStream str(data, pos); - nValue = str.readdata64(); - str.readdata(scriptPubKey); - return str.current_pos(); -} - -void btc_tx::to_bytes(bytes &stream) const { - WriteBytesStream str(stream); - str.writedata32(nVersion); - if (hasWitness) { - // write dummy inputs and flag - str.write_compact_int(0); - unsigned char flags = 1; - str.put(flags); - } - str.write_compact_int(vin.size()); - for (const auto &in : vin) - in.to_bytes(stream); - str.write_compact_int(vout.size()); - for (const auto &out : vout) - out.to_bytes(stream); - if (hasWitness) { - for (const auto &in : vin) { - str.write_compact_int(in.scriptWitness.size()); - for (const auto &stack_item : in.scriptWitness) - str.writedata(stack_item); - } - } - str.writedata32(nLockTime); -} - -size_t btc_tx::fill_from_bytes(const bytes &data, size_t pos) { - ReadBytesStream ds(data, pos); - nVersion = ds.readdata32(); - unsigned char flags = 0; - vin.clear(); - vout.clear(); - hasWitness = false; - /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */ - size_t vin_size = ds.read_compact_int(); - vin.resize(vin_size); - pos = ds.current_pos(); - for (auto &in : vin) - pos = in.fill_from_bytes(data, pos); - ds.set_pos(pos); - if (vin_size == 0) { - /* We read a dummy or an empty vin. */ - ds.get(flags); - if (flags != 0) { - size_t vin_size = ds.read_compact_int(); - vin.resize(vin_size); - pos = ds.current_pos(); - for (auto &in : vin) - pos = in.fill_from_bytes(data, pos); - ds.set_pos(pos); - size_t vout_size = ds.read_compact_int(); - vout.resize(vout_size); - pos = ds.current_pos(); - for (auto &out : vout) - pos = out.fill_from_bytes(data, pos); - ds.set_pos(pos); - hasWitness = true; - } - } else { - /* We read a non-empty vin. Assume a normal vout follows. */ - size_t vout_size = ds.read_compact_int(); - vout.resize(vout_size); - pos = ds.current_pos(); - for (auto &out : vout) - pos = out.fill_from_bytes(data, pos); - ds.set_pos(pos); - } - if (hasWitness) { - /* The witness flag is present, and we support witnesses. */ - for (auto &in : vin) { - unsigned int size = ds.read_compact_int(); - in.scriptWitness.resize(size); - for (auto &stack_item : in.scriptWitness) - ds.readdata(stack_item); - } - } - nLockTime = ds.readdata32(); - return ds.current_pos(); -} - -void add_data_to_script(bytes &script, const bytes &data) { - WriteBytesStream str(script); - str.writedata(data); -} - -void add_number_to_script(bytes &script, unsigned char data) { - WriteBytesStream str(script); - if (data == 0) - str.put(OP_0); - else if (data == 1) - str.put(OP_1); - else if (data == 2) - str.put(OP_2); - else if (data == 3) - str.put(OP_3); - else if (data == 4) - str.put(OP_4); - else if (data == 5) - str.put(OP_5); - else if (data == 6) - str.put(OP_6); - else if (data == 7) - str.put(OP_7); - else if (data == 8) - str.put(OP_8); - else if (data == 9) - str.put(OP_9); - else if (data == 10) - str.put(OP_10); - else if (data == 11) - str.put(OP_11); - else if (data == 12) - str.put(OP_12); - else if (data == 13) - str.put(OP_13); - else if (data == 14) - str.put(OP_14); - else if (data == 15) - str.put(OP_15); - else if (data == 16) - str.put(OP_16); - else - add_data_to_script(script, {data}); -} - -bytes generate_redeem_script(std::vector> key_data) { - int total_weight = 0; - bytes result; - add_number_to_script(result, 0); - for (auto &p : key_data) { - total_weight += p.second; - result.push_back(OP_SWAP); - auto raw_data = p.first.serialize(); - add_data_to_script(result, bytes(raw_data.begin(), raw_data.begin() + raw_data.size())); - result.push_back(OP_CHECKSIG); - result.push_back(OP_IF); - add_number_to_script(result, static_cast(p.second)); - result.push_back(OP_ADD); - result.push_back(OP_ENDIF); - } - int threshold_weight = 2 * total_weight / 3; - add_number_to_script(result, static_cast(threshold_weight)); - result.push_back(OP_GREATERTHAN); - return result; -} - -/** The Bech32 character set for encoding. */ -const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -/** Concatenate two byte arrays. */ -bytes cat(bytes x, const bytes &y) { - x.insert(x.end(), y.begin(), y.end()); - return x; -} - -/** Expand a HRP for use in checksum computation. */ -bytes expand_hrp(const std::string &hrp) { - bytes ret; - 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; -} - -/** Find the polynomial with value coefficients mod the generator as 30-bit. */ -uint32_t polymod(const bytes &values) { - uint32_t chk = 1; - for (size_t i = 0; i < values.size(); ++i) { - uint8_t top = chk >> 25; - chk = (chk & 0x1ffffff) << 5 ^ values[i] ^ - (-((top >> 0) & 1) & 0x3b6a57b2UL) ^ - (-((top >> 1) & 1) & 0x26508e6dUL) ^ - (-((top >> 2) & 1) & 0x1ea119faUL) ^ - (-((top >> 3) & 1) & 0x3d4233ddUL) ^ - (-((top >> 4) & 1) & 0x2a1462b3UL); - } - return chk; -} - -/** Create a checksum. */ -bytes bech32_checksum(const std::string &hrp, const bytes &values) { - bytes enc = cat(expand_hrp(hrp), values); - enc.resize(enc.size() + 6); - uint32_t mod = polymod(enc) ^ 1; - bytes ret; - ret.resize(6); - for (size_t i = 0; i < 6; ++i) { - ret[i] = (mod >> (5 * (5 - i))) & 31; - } - return ret; -} - -/** Encode a Bech32 string. */ -std::string bech32(const std::string &hrp, const bytes &values) { - bytes checksum = bech32_checksum(hrp, values); - bytes combined = cat(values, checksum); - std::string ret = hrp + '1'; - ret.reserve(ret.size() + combined.size()); - for (size_t i = 0; i < combined.size(); ++i) { - ret += charset[combined[i]]; - } - return ret; -} - -/** Convert from one power-of-2 number base to another. */ -template -bool convertbits(bytes &out, const bytes &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; -} - -/** Encode a SegWit address. */ -std::string segwit_addr_encode(const std::string &hrp, uint8_t witver, const bytes &witprog) { - bytes enc; - enc.push_back(witver); - convertbits<8, 5, true>(enc, witprog); - std::string ret = bech32(hrp, enc); - return ret; -} - -std::string p2wsh_address_from_redeem_script(const bytes &script, bitcoin_network network) { - // calc script hash - fc::sha256 sh = fc::sha256::hash(reinterpret_cast(&script[0]), script.size()); - bytes wp(sh.data(), sh.data() + sh.data_size()); - switch (network) { - case (mainnet): - return segwit_addr_encode("bc", 0, wp); - case (testnet): - case (regtest): - return segwit_addr_encode("tb", 0, wp); - default: - FC_THROW("Unknown bitcoin network type"); - } - FC_THROW("Unknown bitcoin network type"); -} - -bytes lock_script_for_redeem_script(const bytes &script) { - bytes result; - result.push_back(OP_0); - fc::sha256 h = fc::sha256::hash(reinterpret_cast(&script[0]), script.size()); - bytes shash(h.data(), h.data() + h.data_size()); - add_data_to_script(result, shash); - return result; -} - -bytes hash_prevouts(const btc_tx &unsigned_tx) { - fc::sha256::encoder hasher; - for (const auto &in : unsigned_tx.vin) { - bytes data; - in.prevout.to_bytes(data); - hasher.write(reinterpret_cast(&data[0]), data.size()); - } - fc::sha256 res = fc::sha256::hash(hasher.result()); - return bytes(res.data(), res.data() + res.data_size()); -} - -bytes hash_sequence(const btc_tx &unsigned_tx) { - fc::sha256::encoder hasher; - for (const auto &in : unsigned_tx.vin) { - hasher.write(reinterpret_cast(&in.nSequence), sizeof(in.nSequence)); - } - fc::sha256 res = fc::sha256::hash(hasher.result()); - return bytes(res.data(), res.data() + res.data_size()); -} - -bytes hash_outputs(const btc_tx &unsigned_tx) { - fc::sha256::encoder hasher; - for (const auto &out : unsigned_tx.vout) { - bytes data; - out.to_bytes(data); - hasher.write(reinterpret_cast(&data[0]), data.size()); - } - fc::sha256 res = fc::sha256::hash(hasher.result()); - return bytes(res.data(), res.data() + res.data_size()); -} - -const secp256k1_context_t *btc_get_context() { - static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); - return ctx; -} - -bytes der_sign(const fc::ecc::private_key &priv_key, const fc::sha256 &digest) { - fc::ecc::signature result; - int size = result.size(); - FC_ASSERT(secp256k1_ecdsa_sign(btc_get_context(), - (unsigned char *)digest.data(), - (unsigned char *)result.begin(), - &size, - (unsigned char *)priv_key.get_secret().data(), - secp256k1_nonce_function_rfc6979, - nullptr)); - return bytes(result.begin(), result.begin() + size); -} - -std::vector signatures_for_raw_transaction(const bytes &unsigned_tx, - std::vector in_amounts, - const bytes &redeem_script, - const fc::ecc::private_key &priv_key) { - btc_tx tx; - tx.fill_from_bytes(unsigned_tx); - - FC_ASSERT(tx.vin.size() == in_amounts.size(), "Incorrect input amounts data"); - - std::vector results; - auto cur_amount = in_amounts.begin(); - // pre-calc reused values - bytes hashPrevouts = hash_prevouts(tx); - bytes hashSequence = hash_sequence(tx); - bytes hashOutputs = hash_outputs(tx); - // calc digest for every input according to BIP143 - // implement SIGHASH_ALL scheme - for (const auto &in : tx.vin) { - fc::sha256::encoder hasher; - hasher.write(reinterpret_cast(&tx.nVersion), sizeof(tx.nVersion)); - hasher.write(reinterpret_cast(&hashPrevouts[0]), hashPrevouts.size()); - hasher.write(reinterpret_cast(&hashSequence[0]), hashSequence.size()); - bytes data; - in.prevout.to_bytes(data); - hasher.write(reinterpret_cast(&data[0]), data.size()); - bytes serializedScript; - WriteBytesStream stream(serializedScript); - stream.writedata(redeem_script); - hasher.write(reinterpret_cast(&serializedScript[0]), serializedScript.size()); - uint64_t amount = *cur_amount++; - hasher.write(reinterpret_cast(&amount), sizeof(amount)); - hasher.write(reinterpret_cast(&in.nSequence), sizeof(in.nSequence)); - hasher.write(reinterpret_cast(&hashOutputs[0]), hashOutputs.size()); - hasher.write(reinterpret_cast(&tx.nLockTime), sizeof(tx.nLockTime)); - // add sigtype SIGHASH_ALL - uint32_t sigtype = 1; - hasher.write(reinterpret_cast(&sigtype), sizeof(sigtype)); - - fc::sha256 digest = fc::sha256::hash(hasher.result()); - //std::vector res = priv_key.sign(digest); - //bytes s_data(res.begin(), res.end()); - bytes s_data = der_sign(priv_key, digest); - s_data.push_back(1); - results.push_back(s_data); - } - return results; -} - -bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, std::vector in_amounts, const bytes &redeem_script, const std::vector> &priv_keys) { - btc_tx tx; - tx.fill_from_bytes(unsigned_tx); - bytes dummy_data; - for (auto key : priv_keys) { - if (key) { - std::vector signatures = signatures_for_raw_transaction(unsigned_tx, in_amounts, redeem_script, *key); - FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number"); - // push signatures in reverse order because script starts to check the top signature on the stack first - for (unsigned int i = 0; i < tx.vin.size(); i++) - tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]); - } else { - for (unsigned int i = 0; i < tx.vin.size(); i++) - tx.vin[i].scriptWitness.push_back(dummy_data); - } - } - - for (auto &in : tx.vin) { - in.scriptWitness.push_back(redeem_script); - } - - tx.hasWitness = true; - bytes ret; - tx.to_bytes(ret); - return ret; -} - -bytes add_dummy_signatures_for_pw_transfer(const bytes &unsigned_tx, - const bytes &redeem_script, - unsigned int key_count) { - btc_tx tx; - tx.fill_from_bytes(unsigned_tx); - - bytes dummy_data; - for (auto &in : tx.vin) { - for (unsigned i = 0; i < key_count; i++) - in.scriptWitness.push_back(dummy_data); - in.scriptWitness.push_back(redeem_script); - } - - tx.hasWitness = true; - bytes ret; - tx.to_bytes(ret); - return ret; -} - -bytes partially_sign_pw_transfer_transaction(const bytes &partially_signed_tx, - std::vector in_amounts, - const fc::ecc::private_key &priv_key, - unsigned int key_idx) { - btc_tx tx; - tx.fill_from_bytes(partially_signed_tx); - FC_ASSERT(tx.vin.size() > 0); - bytes redeem_script = tx.vin[0].scriptWitness.back(); - std::vector signatures = signatures_for_raw_transaction(partially_signed_tx, in_amounts, redeem_script, priv_key); - FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number"); - // push signatures in reverse order because script starts to check the top signature on the stack first - unsigned witness_idx = tx.vin[0].scriptWitness.size() - 2 - key_idx; - for (unsigned int i = 0; i < tx.vin.size(); i++) - tx.vin[i].scriptWitness[witness_idx] = signatures[i]; - bytes ret; - tx.to_bytes(ret); - return ret; -} - -bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, const std::vector> &signature_set, const bytes &redeem_script) { - btc_tx tx; - tx.fill_from_bytes(unsigned_tx); - bytes dummy_data; - for (unsigned int i = 0; i < signature_set.size(); i++) { - std::vector signatures = signature_set[i]; - FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number"); - // push signatures in reverse order because script starts to check the top signature on the stack first - for (unsigned int i = 0; i < tx.vin.size(); i++) - tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]); - } - - for (auto &in : tx.vin) { - in.scriptWitness.push_back(redeem_script); - } - - tx.hasWitness = true; - bytes ret; - tx.to_bytes(ret); - return ret; -} - -}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp deleted file mode 100644 index 9b2dc0c1..00000000 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once -#include -#include - -namespace graphene { namespace peerplays_sidechain { - -enum bitcoin_network { - mainnet, - testnet, - regtest -}; - -bytes generate_redeem_script(std::vector> key_data); -std::string p2wsh_address_from_redeem_script(const bytes &script, bitcoin_network network = mainnet); -bytes lock_script_for_redeem_script(const bytes &script); - -std::vector signatures_for_raw_transaction(const bytes &unsigned_tx, - std::vector in_amounts, - const bytes &redeem_script, - const fc::ecc::private_key &priv_key); - -/* - * unsigned_tx - tx, all inputs of which are spends of the PW P2SH address - * returns signed transaction - */ -bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, - std::vector in_amounts, - const bytes &redeem_script, - const std::vector> &priv_keys); - -/// -////// \brief Adds dummy signatures instead of real signatures -////// \param unsigned_tx -////// \param redeem_script -////// \param key_count -////// \return can be used as partially signed tx -bytes add_dummy_signatures_for_pw_transfer(const bytes &unsigned_tx, - const bytes &redeem_script, - unsigned int key_count); - -/// -/// \brief replaces dummy sgnatures in partially signed tx with real tx -/// \param partially_signed_tx -/// \param in_amounts -/// \param priv_key -/// \param key_idx -/// \return -/// -bytes partially_sign_pw_transfer_transaction(const bytes &partially_signed_tx, - std::vector in_amounts, - const fc::ecc::private_key &priv_key, - unsigned int key_idx); - -/// -/// \brief Creates ready to publish bitcoin transaction from unsigned tx and -/// full set of the signatures. This is alternative way to create tx -/// with partially_sign_pw_transfer_transaction -/// \param unsigned_tx -/// \param signatures -/// \param redeem_script -/// \return -/// -bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, - const std::vector> &signatures, - const bytes &redeem_script); - -struct btc_outpoint { - fc::uint256 hash; - uint32_t n; - - void to_bytes(bytes &stream) const; - size_t fill_from_bytes(const bytes &data, size_t pos = 0); -}; - -struct btc_in { - btc_outpoint prevout; - bytes scriptSig; - uint32_t nSequence; - std::vector scriptWitness; - - void to_bytes(bytes &stream) const; - size_t fill_from_bytes(const bytes &data, size_t pos = 0); -}; - -struct btc_out { - int64_t nValue; - bytes scriptPubKey; - - void to_bytes(bytes &stream) const; - size_t fill_from_bytes(const bytes &data, size_t pos = 0); -}; - -struct btc_tx { - std::vector vin; - std::vector vout; - int32_t nVersion; - uint32_t nLockTime; - bool hasWitness; - - void to_bytes(bytes &stream) const; - size_t fill_from_bytes(const bytes &data, size_t pos = 0); -}; - -}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index ab1f4c39..28e2dff9 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -38,6 +38,7 @@ public: virtual bool process_proposal(const proposal_object &po) = 0; virtual void process_primary_wallet() = 0; + virtual void process_sidechain_addresses() = 0; virtual bool process_deposit(const son_wallet_deposit_object &swdo) = 0; virtual bool process_withdrawal(const son_wallet_withdraw_object &swwo) = 0; virtual std::string process_sidechain_transaction(const sidechain_transaction_object &sto) = 0; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index 67c208d1..03c6cb6c 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -35,16 +35,16 @@ public: std::string getaddressinfo(const std::string &address); std::string getblock(const std::string &block_hash, int32_t verbosity = 2); std::string gettransaction(const std::string &txid, const bool include_watch_only = false); - void importaddress(const std::string &address_or_script); + void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); std::vector listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999); std::vector listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999); std::string loadwallet(const std::string &filename); std::string sendrawtransaction(const std::string &tx_hex); std::string signrawtransactionwithwallet(const std::string &tx_hash); std::string unloadwallet(const std::string &filename); - std::string walletlock(); + //std::string walletlock(); std::string walletprocesspsbt(std::string const &tx_psbt); - bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); + //bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); private: fc::http::reply send_post_request(std::string body, bool show_log = false); @@ -87,6 +87,7 @@ public: bool process_proposal(const proposal_object &po); void process_primary_wallet(); + void process_sidechain_addresses(); bool process_deposit(const son_wallet_deposit_object &swdo); bool process_withdrawal(const son_wallet_withdraw_object &swwo); std::string process_sidechain_transaction(const sidechain_transaction_object &sto); diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp index 5c764fb8..342d5094 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp @@ -15,6 +15,7 @@ public: bool process_proposal(const proposal_object &po); void process_primary_wallet(); + void process_sidechain_addresses(); bool process_deposit(const son_wallet_deposit_object &swdo); bool process_withdrawal(const son_wallet_withdraw_object &swwo); std::string process_sidechain_transaction(const sidechain_transaction_object &sto); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 68ca01e3..b7f7ba5d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -315,6 +315,7 @@ void sidechain_net_handler::process_proposals() { void sidechain_net_handler::process_active_sons_change() { process_primary_wallet(); + process_sidechain_addresses(); } void sidechain_net_handler::process_deposits() { @@ -326,7 +327,7 @@ void sidechain_net_handler::process_deposits() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false)); std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_deposit_object &swdo) { - if(swdo.id == object_id_type(0, 0, 0)) + if (swdo.id == object_id_type(0, 0, 0)) return; ilog("Deposit to process: ${swdo}", ("swdo", swdo)); @@ -379,7 +380,7 @@ void sidechain_net_handler::process_withdrawals() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false)); std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_withdraw_object &swwo) { - if(swwo.id == object_id_type(0, 0, 0)) + if (swwo.id == object_id_type(0, 0, 0)) return; ilog("Withdraw to process: ${swwo}", ("swwo", swwo)); @@ -426,7 +427,7 @@ void sidechain_net_handler::process_sidechain_transactions() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false)); std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { - if(sto.id == object_id_type(0, 0, 0)) + if (sto.id == object_id_type(0, 0, 0)) return; ilog("Sidechain transaction to process: ${sto}", ("sto", sto.id)); @@ -461,7 +462,7 @@ void sidechain_net_handler::send_sidechain_transactions() { const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false)); std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { - if(sto.id == object_id_type(0, 0, 0)) + if (sto.id == object_id_type(0, 0, 0)) return; ilog("Sidechain transaction to send: ${sto}", ("sto", sto.id)); @@ -490,28 +491,4 @@ void sidechain_net_handler::send_sidechain_transactions() { }); } -bool sidechain_net_handler::process_proposal(const proposal_object &po) { - FC_ASSERT(false, "process_proposal not implemented"); -} - -void sidechain_net_handler::process_primary_wallet() { - FC_ASSERT(false, "process_primary_wallet not implemented"); -} - -bool sidechain_net_handler::process_deposit(const son_wallet_deposit_object &swdo) { - FC_ASSERT(false, "process_deposit not implemented"); -} - -bool sidechain_net_handler::process_withdrawal(const son_wallet_withdraw_object &swwo) { - FC_ASSERT(false, "process_withdrawal not implemented"); -} - -std::string sidechain_net_handler::process_sidechain_transaction(const sidechain_transaction_object &sto) { - FC_ASSERT(false, "process_sidechain_transaction not implemented"); -} - -std::string sidechain_net_handler::send_sidechain_transaction(const sidechain_transaction_object &sto) { - FC_ASSERT(false, "send_sidechain_transaction not implemented"); -} - }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 53e26f8d..ed410244 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -461,8 +462,10 @@ std::string bitcoin_rpc_client::getblock(const std::string &block_hash, int32_t std::string bitcoin_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"gettransaction\", \"method\": " - "\"gettransaction\", \"params\": [\"" + - txid + "\"] }"); + "\"gettransaction\", \"params\": ["); + + std::string params = "\"" + txid + "\", " + (include_watch_only ? "true" : "false"); + body = body + params + "] }"; const auto reply = send_post_request(body); @@ -485,10 +488,15 @@ std::string bitcoin_rpc_client::gettransaction(const std::string &txid, const bo return ""; } -void bitcoin_rpc_client::importaddress(const std::string &address_or_script) { - const auto body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"importaddress\", " - "\"method\": \"importaddress\", \"params\": [" + - std::string("\"") + address_or_script + std::string("\"") + std::string("] }")); +void bitcoin_rpc_client::importaddress(const std::string &address_or_script, const std::string &label, const bool rescan, const bool p2sh) { + std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"importaddress\", " + "\"method\": \"importaddress\", \"params\": ["); + + std::string params = "\"" + address_or_script + "\", " + + "\"" + label + "\", " + + (rescan ? "true" : "false") + ", " + + (p2sh ? "true" : "false"); + body = body + params + "] }"; const auto reply = send_post_request(body); @@ -693,32 +701,32 @@ std::string bitcoin_rpc_client::unloadwallet(const std::string &filename) { return ""; } -std::string bitcoin_rpc_client::walletlock() { - std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletlock\", \"method\": " - "\"walletlock\", \"params\": [] }"); - - const auto reply = send_post_request(body); - - if (reply.body.empty()) { - wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); - return ""; - } - - std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - - if (reply.status == 200) { - std::stringstream ss; - boost::property_tree::json_parser::write_json(ss, json.get_child("result")); - return ss.str(); - } - - if (json.count("error") && !json.get_child("error").empty()) { - wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str())); - } - return ""; -} +//std::string bitcoin_rpc_client::walletlock() { +// std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletlock\", \"method\": " +// "\"walletlock\", \"params\": [] }"); +// +// const auto reply = send_post_request(body); +// +// if (reply.body.empty()) { +// wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); +// return ""; +// } +// +// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); +// boost::property_tree::ptree json; +// boost::property_tree::read_json(ss, json); +// +// if (reply.status == 200) { +// std::stringstream ss; +// boost::property_tree::json_parser::write_json(ss, json.get_child("result")); +// return ss.str(); +// } +// +// if (json.count("error") && !json.get_child("error").empty()) { +// wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str())); +// } +// return ""; +//} std::string bitcoin_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletprocesspsbt\", \"method\": " @@ -746,31 +754,31 @@ std::string bitcoin_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { return ""; } -bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { - std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletpassphrase\", \"method\": " - "\"walletpassphrase\", \"params\": [\"" + - passphrase + "\", " + std::to_string(timeout) + "] }"); - - const auto reply = send_post_request(body); - - if (reply.body.empty()) { - wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); - return false; - } - - std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - - if (reply.status == 200) { - return true; - } - - if (json.count("error") && !json.get_child("error").empty()) { - wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str())); - } - return false; -} +//bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) { +// std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletpassphrase\", \"method\": " +// "\"walletpassphrase\", \"params\": [\"" + +// passphrase + "\", " + std::to_string(timeout) + "] }"); +// +// const auto reply = send_post_request(body); +// +// if (reply.body.empty()) { +// wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); +// return false; +// } +// +// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); +// boost::property_tree::ptree json; +// boost::property_tree::read_json(ss, json); +// +// if (reply.status == 200) { +// return true; +// } +// +// if (json.count("error") && !json.get_child("error").empty()) { +// wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str())); +// } +// return false; +//} fc::http::reply bitcoin_rpc_client::send_post_request(std::string body, bool show_log) { fc::http::connection conn; @@ -1017,7 +1025,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) uint64_t swdo_amount = swdo->sidechain_amount.value; uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1)); - std::string tx_str = bitcoin_client->gettransaction(swdo_txid); + std::string tx_str = bitcoin_client->gettransaction(swdo_txid, true); std::stringstream tx_ss(tx_str); boost::property_tree::ptree tx_json; boost::property_tree::read_json(tx_ss, tx_json); @@ -1032,12 +1040,14 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) for (auto &input : tx_json.get_child("result.details")) { tx_address = input.second.get("address"); - std::string tx_amount_s = input.second.get("amount"); - tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); - tx_amount = std::stoll(tx_amount_s); - std::string tx_vout_s = input.second.get("vout"); - tx_vout = std::stoll(tx_vout_s); - break; + if ((tx_address == swdo_address) && (input.second.get("category") == "receive")) { + std::string tx_amount_s = input.second.get("amount"); + tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); + tx_amount = std::stoll(tx_amount_s); + std::string tx_vout_s = input.second.get("vout"); + tx_vout = std::stoll(tx_vout_s); + break; + } } should_approve = (swdo_txid == tx_txid) && @@ -1111,14 +1121,6 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { const chain::global_property_object &gpo = database.get_global_properties(); auto active_sons = gpo.active_sons; - vector son_pubkeys_bitcoin; - for (const son_info &si : active_sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); - } - - if (!wallet_password.empty()) { - bitcoin_client->walletpassphrase(wallet_password, 5); - } string reply_str = create_primary_wallet_address(active_sons); std::stringstream active_pw_ss(reply_str); @@ -1171,6 +1173,50 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { } } +void sidechain_net_handler_bitcoin::process_sidechain_addresses() { + using namespace bitcoin; + + const chain::global_property_object &gpo = database.get_global_properties(); + std::vector> pubkeys; + for (auto &son : gpo.active_sons) { + std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); + auto pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + pubkeys.push_back(std::make_pair(pubkey, son.weight)); + } + + const auto &sidechain_addresses_idx = database.get_index_type(); + const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); + const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); + std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, + [&](const sidechain_address_object &sao) { + auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key))); + + btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys); + + sidechain_address_update_operation op; + op.payer = plugin.get_current_son_object().son_account; + op.sidechain_address_id = sao.id; + op.sidechain_address_account = sao.sidechain_address_account; + op.sidechain = sao.sidechain; + op.deposit_public_key = sao.deposit_public_key; + op.deposit_address = addr.get_address(); + op.withdraw_public_key = sao.withdraw_public_key; + op.withdraw_address = sao.withdraw_address; + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + trx.validate(); + try { + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + }); +} + bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_object &swdo) { if (proposal_exists(chain::operation::tag::value, swdo.id)) { @@ -1623,28 +1669,23 @@ void sidechain_net_handler_bitcoin::on_changed_objects_cb(const vectorwalletpassphrase(wallet_password, 5); - } - - std::string pw_address = ""; if (pw_pt.count("address")) { - pw_address = pw_pt.get("address"); + std::string pw_address = pw_pt.get("address"); bitcoin_client->importaddress(pw_address); } - std::string pw_redeem_script = ""; if (pw_pt.count("redeemScript")) { - pw_redeem_script = pw_pt.get("redeemScript"); - bitcoin_client->importaddress(pw_redeem_script); + std::string pw_redeem_script = pw_pt.get("redeemScript"); + bitcoin_client->importaddress(pw_redeem_script, "", true, true); } - - vector son_pubkeys_bitcoin; - for (const son_info &si : swo->sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); - } - uint32_t nrequired = son_pubkeys_bitcoin.size() * 2 / 3 + 1; - bitcoin_client->addmultisigaddress(nrequired, son_pubkeys_bitcoin); + } + } + if (id.is()) { + const auto &sai = database.get_index_type().indices().get(); + auto sao = sai.find(id); + if (sao != sai.end()) { + bitcoin_client->importaddress(sao->deposit_address); + bitcoin_client->importaddress(sao->withdraw_address); } } } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index b7cdb640..2f8bb932 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -133,6 +133,10 @@ void sidechain_net_handler_peerplays::process_primary_wallet() { return; } +void sidechain_net_handler_peerplays::process_sidechain_addresses() { + return; +} + bool sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_object &swdo) { return true; } diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 7d1a5e45..b3022719 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1361,7 +1361,7 @@ class wallet_api /** * Update a SON object owned by the given account. * - * @param witness The name of the SON's owner account. Also accepts the ID of the owner account or the ID of the SON. + * @param owner_account The name of the SON's owner account. Also accepts the ID of the owner account or the ID of the SON. * @param url Same as for create_son. The empty string makes it remain the same. * @param block_signing_key The new block signing public key. The empty string makes it remain the same. * @param sidechain_public_keys The new set of sidechain public keys. The empty string makes it remain the same. diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index cfbb2223..c00b08dc 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2106,6 +2106,7 @@ public: account_id_type sidechain_address_account_id = get_account_id(account); sidechain_address_add_operation op; + op.payer = sidechain_address_account_id; op.sidechain_address_account = sidechain_address_account_id; op.sidechain = sidechain; op.deposit_public_key = deposit_public_key; @@ -2135,6 +2136,7 @@ public: FC_THROW("No sidechain address for account ${account} and sidechain ${sidechain}", ("account", sidechain_address_account_id)("sidechain", sidechain)); sidechain_address_update_operation op; + op.payer = sidechain_address_account_id; op.sidechain_address_id = sao->id; op.sidechain_address_account = sidechain_address_account_id; op.sidechain = sidechain; @@ -2161,6 +2163,7 @@ public: FC_THROW("No sidechain address for account ${account} and sidechain ${sidechain}", ("account", sidechain_address_account_id)("sidechain", sidechain)); sidechain_address_delete_operation op; + op.payer = sidechain_address_account_id; op.sidechain_address_id = sao->id; op.sidechain_address_account = sidechain_address_account_id; op.sidechain = sidechain; diff --git a/tests/peerplays_sidechain/bitcoin_utils_test.cpp b/tests/peerplays_sidechain/bitcoin_utils_test.cpp deleted file mode 100644 index 316b25bf..00000000 --- a/tests/peerplays_sidechain/bitcoin_utils_test.cpp +++ /dev/null @@ -1,400 +0,0 @@ -#include -#include -#include -#include -#include -#include - -using namespace graphene::peerplays_sidechain; - -BOOST_AUTO_TEST_CASE(tx_serialization) { - // use real mainnet transaction - // txid: 6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315 - // json: {"txid":"6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315","hash":"6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315","version":1,"size":224,"vsize":224,"weight":896,"locktime":0,"vin":[{"txid":"55d079ca797fee81416b71b373abedd8722e33c9f73177be0166b5d5fdac478b","vout":0,"scriptSig":{"asm":"3045022100d82e57d4d11d3b811d07f2fa4ded2fb8a3b7bb1d3e9f293433de5c0d1093c3bd02206704ccd2ff437e2f7716b5e9f2502a9cbb41f1245a18b2b10296980f1ae38253[ALL] 02be9919a5ba373b1af58ad757db19e7c836116bb8138e0c6d99599e4db96568f4","hex":"483045022100d82e57d4d11d3b811d07f2fa4ded2fb8a3b7bb1d3e9f293433de5c0d1093c3bd02206704ccd2ff437e2f7716b5e9f2502a9cbb41f1245a18b2b10296980f1ae38253012102be9919a5ba373b1af58ad757db19e7c836116bb8138e0c6d99599e4db96568f4"},"sequence":4294967295}],"vout":[{"value":1.26491535,"n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 95783804d28e528fbc4b48c7700471e6845804eb OP_EQUALVERIFY OP_CHECKSIG","hex":"76a91495783804d28e528fbc4b48c7700471e6845804eb88ac","reqSigs":1,"type":"pubkeyhash","addresses":["1EdKhXv7zjGowPzgDQ4z1wa2ukVrXRXXkP"]}},{"value":0.0002,"n":1,"scriptPubKey":{"asm":"OP_HASH160 fb0670971091da8248b5c900c6515727a20e8662 OP_EQUAL","hex":"a914fb0670971091da8248b5c900c6515727a20e866287","reqSigs":1,"type":"scripthash","addresses":["3QaKF8zobqcqY8aS6nxCD5ZYdiRfL3RCmU"]}}]} - // hex: "01000000018b47acfdd5b56601be7731f7c9332e72d8edab73b3716b4181ee7f79ca79d055000000006b483045022100d82e57d4d11d3b811d07f2fa4ded2fb8a3b7bb1d3e9f293433de5c0d1093c3bd02206704ccd2ff437e2f7716b5e9f2502a9cbb41f1245a18b2b10296980f1ae38253012102be9919a5ba373b1af58ad757db19e7c836116bb8138e0c6d99599e4db96568f4ffffffff028f1b8a07000000001976a91495783804d28e528fbc4b48c7700471e6845804eb88ac204e00000000000017a914fb0670971091da8248b5c900c6515727a20e86628700000000" - fc::string strtx("01000000018b47acfdd5b56601be7731f7c9332e72d8edab73b3716b4181ee7f79ca79d055000000006b483045022100d82e57d4d11d3b811d07f2fa4ded2fb8a3b7bb1d3e9f293433de5c0d1093c3bd02206704ccd2ff437e2f7716b5e9f2502a9cbb41f1245a18b2b10296980f1ae38253012102be9919a5ba373b1af58ad757db19e7c836116bb8138e0c6d99599e4db96568f4ffffffff028f1b8a07000000001976a91495783804d28e528fbc4b48c7700471e6845804eb88ac204e00000000000017a914fb0670971091da8248b5c900c6515727a20e86628700000000"); - bytes bintx; - bintx.resize(strtx.length() / 2); - fc::from_hex(strtx, reinterpret_cast(&bintx[0]), bintx.size()); - btc_tx tx; - BOOST_CHECK_NO_THROW(tx.fill_from_bytes(bintx)); - BOOST_CHECK(tx.nVersion == 1); - BOOST_CHECK(tx.nLockTime == 0); - BOOST_CHECK(tx.vin.size() == 1); - BOOST_CHECK(tx.vout.size() == 2); - bytes buff; - tx.to_bytes(buff); - BOOST_CHECK(bintx == buff); -} - -BOOST_AUTO_TEST_CASE(pw_transfer) { - // key set for the old Primary Wallet - std::vector priv_old; - for (unsigned i = 0; i < 15; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_old.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - // print old keys - for (auto key : priv_old) { - fc::sha256 secret = key.get_secret(); - bytes data({239}); - data.insert(data.end(), secret.data(), secret.data() + secret.data_size()); - fc::sha256 cs = fc::sha256::hash(fc::sha256::hash((char *)&data[0], data.size())); - data.insert(data.end(), cs.data(), cs.data() + 4); - } - std::vector pub_old; - for (auto &key : priv_old) - pub_old.push_back(key.get_public_key()); - // old key weights - std::vector> weights_old; - for (unsigned i = 0; i < 15; ++i) - weights_old.push_back(std::make_pair(pub_old[i], i + 1)); - // redeem script for old PW - bytes redeem_old = generate_redeem_script(weights_old); - - // Old PW address - std::string old_pw = p2wsh_address_from_redeem_script(redeem_old, bitcoin_network::testnet); - // This address was filled with testnet transaction 508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766 - BOOST_REQUIRE(old_pw == "tb1qfhstznulf5cmjzahlkmnuuvs0tkjtwjlme3ugz8jzfjanf8h5rwsp45t7e"); - - bytes scriptPubKey = lock_script_for_redeem_script(redeem_old); - - // key set for the new Primary Wallet - std::vector priv_new; - for (unsigned i = 16; i < 31; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_new.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - std::vector pub_new; - for (auto &key : priv_new) - pub_new.push_back(key.get_public_key()); - // new key weights - std::vector> weights_new; - for (unsigned i = 0; i < 15; ++i) - weights_new.push_back(std::make_pair(pub_new[i], 16 - i)); - // redeem script for new PW - bytes redeem_new = generate_redeem_script(weights_new); - // New PW address - std::string new_pw = p2wsh_address_from_redeem_script(redeem_new, bitcoin_network::testnet); - BOOST_REQUIRE(new_pw == "tb1qzegrz8r8z8ddfkql8595d90czng6eyjmx4ur73ls4pq57jg99qhsh9fd2y"); - - // try to move funds from old wallet to new one - - // get unspent outputs for old wallet with list_uspent (address should be - // added to wallet with import_address before). It should return - // 1 UTXO: [508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766:0] - // with 20000 satoshis - // So, we creating a raw transaction with 1 input and one output that gets - // 20000 - fee satoshis with createrawtransaction call (bitcoin_rpc_client::prepare_tx) - // Here we just serialize the transaction without scriptSig in inputs then sign it. - btc_outpoint outpoint; - outpoint.hash = fc::uint256("508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766"); - // reverse hash due to the different from_hex algo - std::reverse(outpoint.hash.data(), outpoint.hash.data() + outpoint.hash.data_size()); - outpoint.n = 0; - btc_in input; - input.prevout = outpoint; - input.nSequence = 0xffffffff; - btc_out output; - output.nValue = 19000; - output.scriptPubKey = lock_script_for_redeem_script(redeem_new); - btc_tx tx; - tx.nVersion = 2; - tx.nLockTime = 0; - tx.hasWitness = false; - tx.vin.push_back(input); - tx.vout.push_back(output); - bytes unsigned_tx; - tx.to_bytes(unsigned_tx); - std::vector in_amounts({20000}); - std::vector> keys_to_sign; - for (auto key : priv_old) - keys_to_sign.push_back(fc::optional(key)); - bytes signed_tx = sign_pw_transfer_transaction(unsigned_tx, in_amounts, redeem_old, keys_to_sign); - // this is real testnet tx with id 1734a2f6192c3953c90f9fd7f69eba16eeb0922207f81f3af32d6534a6f8e850 - BOOST_CHECK(fc::to_hex((char *)&signed_tx[0], signed_tx.size()) == "020000000001016617ba8fec01d942ef23dfa26c99badceb682050c5e67ec5b76de65dd6368a500000000000ffffffff01384a0000000000002200201650311c6711dad4d81f3d0b4695f814d1ac925b35783f47f0a8414f4905282f10473044022028cf6df7ed5c2761d7aa2af20717c8b5ace168a7800d6a566f2c1ae28160cae502205e01a3d91f5b9870577e36fbc26ce0cecc3e628cc376c7016364ec3f370703140147304402205c9a88cbe41eb9c6a16ba1d747456222cbe951d04739d21309ef0c0cf00727f202202d06db830ee5823882c7b6f82b708111a8f37741878896cd3558fb91efe8076401473044022009c3184fc0385eb7ed8dc0374791cbdace0eff0dc27dd80ac68f8cb81110f700022042267e8a8788c314347234ea10db6c1ec21a2d423b784cbfbaadf3b2393c44630147304402202363ce306570dc0bbf6d18d41b67c6488a014a91d8e24c03670b4f65523aca12022029d04c114b8e93d982cadee89d80bb25c5c8bc437d6cd2bfce8e0d83a08d14410148304502210087b4742e5cf9c77ca9f99928e7c7087e7d786e09216485628509e4e0b2f29d7e02207daf2eaee9fe8bf117074be137b7ae4b8503a4f6d263424e8e6a16405d5b723c0147304402204f1c3ed8cf595bfaf79d90f4c55c04c17bb6d446e3b9beca7ee6ee7895c6b752022022ac032f219a81b2845d0a1abfb904e40036a3ad332e7dfada6fda21ef7080b501483045022100d020eca4ba1aa77de9caf98f3a29f74f55268276860b9fa35fa16cfc00219dd8022028237de6ad063116cf8182d2dd45a09cb90c2ec8104d793eb3635a1290027cd6014730440220322193b0feba7356651465b86463c7619cd3d96729df6242e9571c74ff1c3c2902206e1de8e77b71c7b6031a934b52321134b6a8d138e2124e90f6345decbd543efb01483045022100d70ade49b3f17812785a41711e107b27c3d4981f8e12253629c07ec46ee511af02203e1ea9059ed9165eeff827002c7399a30c478a9b6f2b958621bfbc6713ab4dd30147304402206f7f10d9993c7019360276bbe790ab587adadeab08088593a9a0c56524aca4df02207c147fe2e51484801a4e059e611e7514729d685a5df892dcf02ba59d455e678101483045022100d5071b8039364bfaa53ef5e22206f773539b082f28bd1fbaaea995fa28aae0f5022056edf7a7bdd8a9a54273a667be5bcd11191fc871798fb44f6e1e35c95d86a81201483045022100a39f8ffbcd9c3f0591fc731a9856c8e024041017cba20c9935f13e4abcf9e9dc0220786823b8cd55664ff9ad6277899aacfd56fa8e48c38881482418b7d50ca27211014730440220361d3b87fcc2b1c12a9e7c684c78192ccb7fe51b90c281b7058384b0b036927a0220434c9b403ee3802b4e5b53feb9bb37d2a9d8746c3688da993549dd9d9954c6800147304402206dc4c3a4407fe9cbffb724928aa0597148c14a20d0d7fbb36ad5d3e2a3abf85e022039ef7baebbf08494495a038b009c6d4ff4b91c38db840673b87f6c27c3b53e7e01483045022100cadac495ea78d0ce9678a4334b8c43f7fafeea5a59413cc2a0144addb63485f9022078ca133e020e3afd0e79936337afefc21d84d3839f5a225a0f3d3eebc15f959901fd5c02007c21030e88484f2bb5dcfc0b326e9eb565c27c8291efb064d060d226916857a2676e62ac635193687c2102151ad794a3aeb3cf9c190120da3d13d36cd8bdf21ca1ccb15debd61c601314b0ac635293687c2103b45a5955ea7847d121225c752edaeb4a5d731a056a951a876caaf6d1f69adb7dac635393687c2102def03a6ffade4ffb0017c8d93859a247badd60e2d76d00e2a3713f6621932ec1ac635493687c21035f17aa7d58b8c3ee0d87240fded52b27f3f12768a0a54ba2595e0a929dd87155ac635593687c2103c8582ac6b0bd20cc1b02c6a86bad2ea10cadb758fedd754ba0d97be85b63b5a7ac635693687c21028148a1f9669fc4471e76f7a371d7cc0563b26e0821d9633fd37649744ff54edaac635793687c2102f0313701b0035f0365a59ce1a3d7ae7045e1f2fb25c4656c08071e5baf51483dac635893687c21024c4c25d08173b3c4d4e1375f8107fd7040c2dc0691ae1bf6fe82b8c88a85185fac635993687c210360fe2daa8661a3d25d0df79875d70b1c3d443ade731caafda7488cb68b4071b0ac635a93687c210250e41a6a4abd7b0b3a49eaec24a6fafa99e5aa7b1e3a5aabe60664276df3d937ac635b93687c2103045a32125930ca103c7d7c79b6f379754796cd4ea7fb0059da926e415e3877d3ac635c93687c210344943249d7ca9b47316fef0c2a413dda3a75416a449a29f310ab7fc9d052ed70ac635d93687c2103c62967320b63df5136ff1ef4c7959ef5917ee5a44f75c83e870bc488143d4d69ac635e93687c21020429f776e15770e4dc52bd6f72e6ed6908d51de1c4a64878433c4e3860a48dc4ac635f93680150a000000000"); -} - -BOOST_AUTO_TEST_CASE(pw_separate_sign) { - // key set for the old Primary Wallet - std::vector priv_old; - for (unsigned i = 0; i < 15; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_old.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - // print old keys - for (auto key : priv_old) { - fc::sha256 secret = key.get_secret(); - bytes data({239}); - data.insert(data.end(), secret.data(), secret.data() + secret.data_size()); - fc::sha256 cs = fc::sha256::hash(fc::sha256::hash((char *)&data[0], data.size())); - data.insert(data.end(), cs.data(), cs.data() + 4); - } - std::vector pub_old; - for (auto &key : priv_old) - pub_old.push_back(key.get_public_key()); - // old key weights - std::vector> weights_old; - for (unsigned i = 0; i < 15; ++i) - weights_old.push_back(std::make_pair(pub_old[i], i + 1)); - // redeem script for old PW - bytes redeem_old = generate_redeem_script(weights_old); - - // Old PW address - std::string old_pw = p2wsh_address_from_redeem_script(redeem_old, bitcoin_network::testnet); - // This address was filled with testnet transaction 508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766 - BOOST_REQUIRE(old_pw == "tb1qfhstznulf5cmjzahlkmnuuvs0tkjtwjlme3ugz8jzfjanf8h5rwsp45t7e"); - - bytes scriptPubKey = lock_script_for_redeem_script(redeem_old); - - // key set for the new Primary Wallet - std::vector priv_new; - for (unsigned i = 16; i < 31; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_new.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - std::vector pub_new; - for (auto &key : priv_new) - pub_new.push_back(key.get_public_key()); - // new key weights - std::vector> weights_new; - for (unsigned i = 0; i < 15; ++i) - weights_new.push_back(std::make_pair(pub_new[i], 16 - i)); - // redeem script for new PW - bytes redeem_new = generate_redeem_script(weights_new); - // New PW address - std::string new_pw = p2wsh_address_from_redeem_script(redeem_new, bitcoin_network::testnet); - BOOST_REQUIRE(new_pw == "tb1qzegrz8r8z8ddfkql8595d90czng6eyjmx4ur73ls4pq57jg99qhsh9fd2y"); - - // try to move funds from old wallet to new one - - // get unspent outputs for old wallet with list_uspent (address should be - // added to wallet with import_address before). It should return - // 1 UTXO: [508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766:0] - // with 20000 satoshis - // So, we creating a raw transaction with 1 input and one output that gets - // 20000 - fee satoshis with createrawtransaction call (bitcoin_rpc_client::prepare_tx) - // Here we just serialize the transaction without scriptSig in inputs then sign it. - btc_outpoint outpoint; - outpoint.hash = fc::uint256("508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766"); - // reverse hash due to the different from_hex algo - std::reverse(outpoint.hash.data(), outpoint.hash.data() + outpoint.hash.data_size()); - outpoint.n = 0; - btc_in input; - input.prevout = outpoint; - input.nSequence = 0xffffffff; - btc_out output; - output.nValue = 19000; - output.scriptPubKey = lock_script_for_redeem_script(redeem_new); - btc_tx tx; - tx.nVersion = 2; - tx.nLockTime = 0; - tx.hasWitness = false; - tx.vin.push_back(input); - tx.vout.push_back(output); - bytes unsigned_tx; - tx.to_bytes(unsigned_tx); - std::vector in_amounts({20000}); - - // prepare tx with dummy signs - bytes partially_signed_tx = add_dummy_signatures_for_pw_transfer(unsigned_tx, redeem_old, 15); - - // sign with every old key one by one - for (unsigned idx = 0; idx < 15; idx++) - partially_signed_tx = partially_sign_pw_transfer_transaction(partially_signed_tx, in_amounts, priv_old[idx], idx); - - // now this is real testnet tx with id 1734a2f6192c3953c90f9fd7f69eba16eeb0922207f81f3af32d6534a6f8e850 - BOOST_CHECK(fc::to_hex((char *)&partially_signed_tx[0], partially_signed_tx.size()) == "020000000001016617ba8fec01d942ef23dfa26c99badceb682050c5e67ec5b76de65dd6368a500000000000ffffffff01384a0000000000002200201650311c6711dad4d81f3d0b4695f814d1ac925b35783f47f0a8414f4905282f10473044022028cf6df7ed5c2761d7aa2af20717c8b5ace168a7800d6a566f2c1ae28160cae502205e01a3d91f5b9870577e36fbc26ce0cecc3e628cc376c7016364ec3f370703140147304402205c9a88cbe41eb9c6a16ba1d747456222cbe951d04739d21309ef0c0cf00727f202202d06db830ee5823882c7b6f82b708111a8f37741878896cd3558fb91efe8076401473044022009c3184fc0385eb7ed8dc0374791cbdace0eff0dc27dd80ac68f8cb81110f700022042267e8a8788c314347234ea10db6c1ec21a2d423b784cbfbaadf3b2393c44630147304402202363ce306570dc0bbf6d18d41b67c6488a014a91d8e24c03670b4f65523aca12022029d04c114b8e93d982cadee89d80bb25c5c8bc437d6cd2bfce8e0d83a08d14410148304502210087b4742e5cf9c77ca9f99928e7c7087e7d786e09216485628509e4e0b2f29d7e02207daf2eaee9fe8bf117074be137b7ae4b8503a4f6d263424e8e6a16405d5b723c0147304402204f1c3ed8cf595bfaf79d90f4c55c04c17bb6d446e3b9beca7ee6ee7895c6b752022022ac032f219a81b2845d0a1abfb904e40036a3ad332e7dfada6fda21ef7080b501483045022100d020eca4ba1aa77de9caf98f3a29f74f55268276860b9fa35fa16cfc00219dd8022028237de6ad063116cf8182d2dd45a09cb90c2ec8104d793eb3635a1290027cd6014730440220322193b0feba7356651465b86463c7619cd3d96729df6242e9571c74ff1c3c2902206e1de8e77b71c7b6031a934b52321134b6a8d138e2124e90f6345decbd543efb01483045022100d70ade49b3f17812785a41711e107b27c3d4981f8e12253629c07ec46ee511af02203e1ea9059ed9165eeff827002c7399a30c478a9b6f2b958621bfbc6713ab4dd30147304402206f7f10d9993c7019360276bbe790ab587adadeab08088593a9a0c56524aca4df02207c147fe2e51484801a4e059e611e7514729d685a5df892dcf02ba59d455e678101483045022100d5071b8039364bfaa53ef5e22206f773539b082f28bd1fbaaea995fa28aae0f5022056edf7a7bdd8a9a54273a667be5bcd11191fc871798fb44f6e1e35c95d86a81201483045022100a39f8ffbcd9c3f0591fc731a9856c8e024041017cba20c9935f13e4abcf9e9dc0220786823b8cd55664ff9ad6277899aacfd56fa8e48c38881482418b7d50ca27211014730440220361d3b87fcc2b1c12a9e7c684c78192ccb7fe51b90c281b7058384b0b036927a0220434c9b403ee3802b4e5b53feb9bb37d2a9d8746c3688da993549dd9d9954c6800147304402206dc4c3a4407fe9cbffb724928aa0597148c14a20d0d7fbb36ad5d3e2a3abf85e022039ef7baebbf08494495a038b009c6d4ff4b91c38db840673b87f6c27c3b53e7e01483045022100cadac495ea78d0ce9678a4334b8c43f7fafeea5a59413cc2a0144addb63485f9022078ca133e020e3afd0e79936337afefc21d84d3839f5a225a0f3d3eebc15f959901fd5c02007c21030e88484f2bb5dcfc0b326e9eb565c27c8291efb064d060d226916857a2676e62ac635193687c2102151ad794a3aeb3cf9c190120da3d13d36cd8bdf21ca1ccb15debd61c601314b0ac635293687c2103b45a5955ea7847d121225c752edaeb4a5d731a056a951a876caaf6d1f69adb7dac635393687c2102def03a6ffade4ffb0017c8d93859a247badd60e2d76d00e2a3713f6621932ec1ac635493687c21035f17aa7d58b8c3ee0d87240fded52b27f3f12768a0a54ba2595e0a929dd87155ac635593687c2103c8582ac6b0bd20cc1b02c6a86bad2ea10cadb758fedd754ba0d97be85b63b5a7ac635693687c21028148a1f9669fc4471e76f7a371d7cc0563b26e0821d9633fd37649744ff54edaac635793687c2102f0313701b0035f0365a59ce1a3d7ae7045e1f2fb25c4656c08071e5baf51483dac635893687c21024c4c25d08173b3c4d4e1375f8107fd7040c2dc0691ae1bf6fe82b8c88a85185fac635993687c210360fe2daa8661a3d25d0df79875d70b1c3d443ade731caafda7488cb68b4071b0ac635a93687c210250e41a6a4abd7b0b3a49eaec24a6fafa99e5aa7b1e3a5aabe60664276df3d937ac635b93687c2103045a32125930ca103c7d7c79b6f379754796cd4ea7fb0059da926e415e3877d3ac635c93687c210344943249d7ca9b47316fef0c2a413dda3a75416a449a29f310ab7fc9d052ed70ac635d93687c2103c62967320b63df5136ff1ef4c7959ef5917ee5a44f75c83e870bc488143d4d69ac635e93687c21020429f776e15770e4dc52bd6f72e6ed6908d51de1c4a64878433c4e3860a48dc4ac635f93680150a000000000"); -} - -BOOST_AUTO_TEST_CASE(pw_separate_sign2) { - // key set for the old Primary Wallet - std::vector priv_old; - for (unsigned i = 0; i < 15; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_old.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - // print old keys - for (auto key : priv_old) { - fc::sha256 secret = key.get_secret(); - bytes data({239}); - data.insert(data.end(), secret.data(), secret.data() + secret.data_size()); - fc::sha256 cs = fc::sha256::hash(fc::sha256::hash((char *)&data[0], data.size())); - data.insert(data.end(), cs.data(), cs.data() + 4); - } - std::vector pub_old; - for (auto &key : priv_old) - pub_old.push_back(key.get_public_key()); - // old key weights - std::vector> weights_old; - for (unsigned i = 0; i < 15; ++i) - weights_old.push_back(std::make_pair(pub_old[i], i + 1)); - // redeem script for old PW - bytes redeem_old = generate_redeem_script(weights_old); - - // Old PW address - std::string old_pw = p2wsh_address_from_redeem_script(redeem_old, bitcoin_network::testnet); - // This address was filled with testnet transaction 508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766 - BOOST_REQUIRE(old_pw == "tb1qfhstznulf5cmjzahlkmnuuvs0tkjtwjlme3ugz8jzfjanf8h5rwsp45t7e"); - - bytes scriptPubKey = lock_script_for_redeem_script(redeem_old); - - // key set for the new Primary Wallet - std::vector priv_new; - for (unsigned i = 16; i < 31; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_new.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - std::vector pub_new; - for (auto &key : priv_new) - pub_new.push_back(key.get_public_key()); - // new key weights - std::vector> weights_new; - for (unsigned i = 0; i < 15; ++i) - weights_new.push_back(std::make_pair(pub_new[i], 16 - i)); - // redeem script for new PW - bytes redeem_new = generate_redeem_script(weights_new); - // New PW address - std::string new_pw = p2wsh_address_from_redeem_script(redeem_new, bitcoin_network::testnet); - BOOST_REQUIRE(new_pw == "tb1qzegrz8r8z8ddfkql8595d90czng6eyjmx4ur73ls4pq57jg99qhsh9fd2y"); - - // try to move funds from old wallet to new one - - // get unspent outputs for old wallet with list_uspent (address should be - // added to wallet with import_address before). It should return - // 1 UTXO: [508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766:0] - // with 20000 satoshis - // So, we creating a raw transaction with 1 input and one output that gets - // 20000 - fee satoshis with createrawtransaction call (bitcoin_rpc_client::prepare_tx) - // Here we just serialize the transaction without scriptSig in inputs then sign it. - btc_outpoint outpoint; - outpoint.hash = fc::uint256("508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766"); - // reverse hash due to the different from_hex algo - std::reverse(outpoint.hash.data(), outpoint.hash.data() + outpoint.hash.data_size()); - outpoint.n = 0; - btc_in input; - input.prevout = outpoint; - input.nSequence = 0xffffffff; - btc_out output; - output.nValue = 19000; - output.scriptPubKey = lock_script_for_redeem_script(redeem_new); - btc_tx tx; - tx.nVersion = 2; - tx.nLockTime = 0; - tx.hasWitness = false; - tx.vin.push_back(input); - tx.vout.push_back(output); - bytes unsigned_tx; - tx.to_bytes(unsigned_tx); - std::vector in_amounts({20000}); - - // gather all signatures from all SONs separatelly - std::vector> signature_set; - for (auto key : priv_old) { - std::vector signatures = signatures_for_raw_transaction(unsigned_tx, in_amounts, redeem_old, key); - signature_set.push_back(signatures); - } - - // create signed tx with all signatures - bytes signed_tx = add_signatures_to_unsigned_tx(unsigned_tx, signature_set, redeem_old); - - // now this is real testnet tx with id 1734a2f6192c3953c90f9fd7f69eba16eeb0922207f81f3af32d6534a6f8e850 - BOOST_CHECK(fc::to_hex((char *)&signed_tx[0], signed_tx.size()) == "020000000001016617ba8fec01d942ef23dfa26c99badceb682050c5e67ec5b76de65dd6368a500000000000ffffffff01384a0000000000002200201650311c6711dad4d81f3d0b4695f814d1ac925b35783f47f0a8414f4905282f10473044022028cf6df7ed5c2761d7aa2af20717c8b5ace168a7800d6a566f2c1ae28160cae502205e01a3d91f5b9870577e36fbc26ce0cecc3e628cc376c7016364ec3f370703140147304402205c9a88cbe41eb9c6a16ba1d747456222cbe951d04739d21309ef0c0cf00727f202202d06db830ee5823882c7b6f82b708111a8f37741878896cd3558fb91efe8076401473044022009c3184fc0385eb7ed8dc0374791cbdace0eff0dc27dd80ac68f8cb81110f700022042267e8a8788c314347234ea10db6c1ec21a2d423b784cbfbaadf3b2393c44630147304402202363ce306570dc0bbf6d18d41b67c6488a014a91d8e24c03670b4f65523aca12022029d04c114b8e93d982cadee89d80bb25c5c8bc437d6cd2bfce8e0d83a08d14410148304502210087b4742e5cf9c77ca9f99928e7c7087e7d786e09216485628509e4e0b2f29d7e02207daf2eaee9fe8bf117074be137b7ae4b8503a4f6d263424e8e6a16405d5b723c0147304402204f1c3ed8cf595bfaf79d90f4c55c04c17bb6d446e3b9beca7ee6ee7895c6b752022022ac032f219a81b2845d0a1abfb904e40036a3ad332e7dfada6fda21ef7080b501483045022100d020eca4ba1aa77de9caf98f3a29f74f55268276860b9fa35fa16cfc00219dd8022028237de6ad063116cf8182d2dd45a09cb90c2ec8104d793eb3635a1290027cd6014730440220322193b0feba7356651465b86463c7619cd3d96729df6242e9571c74ff1c3c2902206e1de8e77b71c7b6031a934b52321134b6a8d138e2124e90f6345decbd543efb01483045022100d70ade49b3f17812785a41711e107b27c3d4981f8e12253629c07ec46ee511af02203e1ea9059ed9165eeff827002c7399a30c478a9b6f2b958621bfbc6713ab4dd30147304402206f7f10d9993c7019360276bbe790ab587adadeab08088593a9a0c56524aca4df02207c147fe2e51484801a4e059e611e7514729d685a5df892dcf02ba59d455e678101483045022100d5071b8039364bfaa53ef5e22206f773539b082f28bd1fbaaea995fa28aae0f5022056edf7a7bdd8a9a54273a667be5bcd11191fc871798fb44f6e1e35c95d86a81201483045022100a39f8ffbcd9c3f0591fc731a9856c8e024041017cba20c9935f13e4abcf9e9dc0220786823b8cd55664ff9ad6277899aacfd56fa8e48c38881482418b7d50ca27211014730440220361d3b87fcc2b1c12a9e7c684c78192ccb7fe51b90c281b7058384b0b036927a0220434c9b403ee3802b4e5b53feb9bb37d2a9d8746c3688da993549dd9d9954c6800147304402206dc4c3a4407fe9cbffb724928aa0597148c14a20d0d7fbb36ad5d3e2a3abf85e022039ef7baebbf08494495a038b009c6d4ff4b91c38db840673b87f6c27c3b53e7e01483045022100cadac495ea78d0ce9678a4334b8c43f7fafeea5a59413cc2a0144addb63485f9022078ca133e020e3afd0e79936337afefc21d84d3839f5a225a0f3d3eebc15f959901fd5c02007c21030e88484f2bb5dcfc0b326e9eb565c27c8291efb064d060d226916857a2676e62ac635193687c2102151ad794a3aeb3cf9c190120da3d13d36cd8bdf21ca1ccb15debd61c601314b0ac635293687c2103b45a5955ea7847d121225c752edaeb4a5d731a056a951a876caaf6d1f69adb7dac635393687c2102def03a6ffade4ffb0017c8d93859a247badd60e2d76d00e2a3713f6621932ec1ac635493687c21035f17aa7d58b8c3ee0d87240fded52b27f3f12768a0a54ba2595e0a929dd87155ac635593687c2103c8582ac6b0bd20cc1b02c6a86bad2ea10cadb758fedd754ba0d97be85b63b5a7ac635693687c21028148a1f9669fc4471e76f7a371d7cc0563b26e0821d9633fd37649744ff54edaac635793687c2102f0313701b0035f0365a59ce1a3d7ae7045e1f2fb25c4656c08071e5baf51483dac635893687c21024c4c25d08173b3c4d4e1375f8107fd7040c2dc0691ae1bf6fe82b8c88a85185fac635993687c210360fe2daa8661a3d25d0df79875d70b1c3d443ade731caafda7488cb68b4071b0ac635a93687c210250e41a6a4abd7b0b3a49eaec24a6fafa99e5aa7b1e3a5aabe60664276df3d937ac635b93687c2103045a32125930ca103c7d7c79b6f379754796cd4ea7fb0059da926e415e3877d3ac635c93687c210344943249d7ca9b47316fef0c2a413dda3a75416a449a29f310ab7fc9d052ed70ac635d93687c2103c62967320b63df5136ff1ef4c7959ef5917ee5a44f75c83e870bc488143d4d69ac635e93687c21020429f776e15770e4dc52bd6f72e6ed6908d51de1c4a64878433c4e3860a48dc4ac635f93680150a000000000"); -} - -BOOST_AUTO_TEST_CASE(pw_partially_sign) { - // key set for the old Primary Wallet - std::vector priv_old; - for (unsigned i = 0; i < 15; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_old.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - // print old keys - for (auto key : priv_old) { - fc::sha256 secret = key.get_secret(); - bytes data({239}); - data.insert(data.end(), secret.data(), secret.data() + secret.data_size()); - fc::sha256 cs = fc::sha256::hash(fc::sha256::hash((char *)&data[0], data.size())); - data.insert(data.end(), cs.data(), cs.data() + 4); - } - std::vector pub_old; - for (auto &key : priv_old) - pub_old.push_back(key.get_public_key()); - // old key weights - std::vector> weights_old; - for (unsigned i = 0; i < 15; ++i) - weights_old.push_back(std::make_pair(pub_old[i], i + 1)); - // redeem script for old PW - bytes redeem_old = generate_redeem_script(weights_old); - - // Old PW address - std::string old_pw = p2wsh_address_from_redeem_script(redeem_old, bitcoin_network::testnet); - // This address was filled with testnet transaction 508a36d65de66db7c57ee6c5502068ebdcba996ca2df23ef42d901ec8fba1766 - BOOST_REQUIRE(old_pw == "tb1qfhstznulf5cmjzahlkmnuuvs0tkjtwjlme3ugz8jzfjanf8h5rwsp45t7e"); - - bytes scriptPubKey = lock_script_for_redeem_script(redeem_old); - - // key set for the new Primary Wallet - std::vector priv_new; - for (unsigned i = 16; i < 31; ++i) { - const char *seed = reinterpret_cast(&i); - fc::sha256 h = fc::sha256::hash(seed, sizeof(i)); - priv_new.push_back(fc::ecc::private_key::generate_from_seed(h)); - } - std::vector pub_new; - for (auto &key : priv_new) - pub_new.push_back(key.get_public_key()); - // new key weights - std::vector> weights_new; - for (unsigned i = 0; i < 15; ++i) - weights_new.push_back(std::make_pair(pub_new[i], 16 - i)); - // redeem script for new PW - bytes redeem_new = generate_redeem_script(weights_new); - // New PW address - std::string new_pw = p2wsh_address_from_redeem_script(redeem_new, bitcoin_network::testnet); - BOOST_REQUIRE(new_pw == "tb1qzegrz8r8z8ddfkql8595d90czng6eyjmx4ur73ls4pq57jg99qhsh9fd2y"); - - // try to move funds from old wallet to new one - - // Spent 1 UTXO: [7007b77fcd5fe097d02679252aa112900d08ab20c06052f4148265b21b1f9fbf:0] - // with 29999 satoshis - // So, we creating a raw transaction with 1 input and one output that gets - // 29999 - fee satoshis with createrawtransaction call (bitcoin_rpc_client::prepare_tx) - btc_outpoint outpoint; - outpoint.hash = fc::uint256("7007b77fcd5fe097d02679252aa112900d08ab20c06052f4148265b21b1f9fbf"); - // reverse hash due to the different from_hex algo - std::reverse(outpoint.hash.data(), outpoint.hash.data() + outpoint.hash.data_size()); - outpoint.n = 0; - btc_in input; - input.prevout = outpoint; - input.nSequence = 0xffffffff; - btc_out output; - output.nValue = 29000; - output.scriptPubKey = lock_script_for_redeem_script(redeem_new); - btc_tx tx; - tx.nVersion = 2; - tx.nLockTime = 0; - tx.hasWitness = false; - tx.vin.push_back(input); - tx.vout.push_back(output); - bytes unsigned_tx; - tx.to_bytes(unsigned_tx); - std::vector in_amounts({29999}); - - // prepare tx with dummy signs - bytes partially_signed_tx = add_dummy_signatures_for_pw_transfer(unsigned_tx, redeem_old, 15); - - // sign with every old key one by one except the first one - for (unsigned idx = 1; idx < 15; idx++) - partially_signed_tx = partially_sign_pw_transfer_transaction(partially_signed_tx, in_amounts, priv_old[idx], idx); - - // now this is real testnet tx with id e86455c40da6993b6fed70daea2046287b206ab5c16e1ab58c4dfb4a7d6efb84 - BOOST_CHECK(fc::to_hex((char *)&partially_signed_tx[0], partially_signed_tx.size()) == "02000000000101bf9f1f1bb2658214f45260c020ab080d9012a12a257926d097e05fcd7fb707700000000000ffffffff0148710000000000002200201650311c6711dad4d81f3d0b4695f814d1ac925b35783f47f0a8414f4905282f10483045022100c4c567419754c5c1768e959a35633012e8d22ccc90d7cd1b88d6d430a513fbbd0220729c2a3520d0cae7dd6dcd928624ffa3e0b6ce0c4f5c340653a6c18549182588014830450221008c868ea2cdf5b23bdf9e6c7d7c283b8424aeb4aec43621424baef1ee77dd399a02205431f608006f0f0dcd392fab4f25328808b45d4a73852a197e947b289faefece01483045022100aecac85bbb81bc0a4e127c15090c5ab82a62b9e27a9a6eb8eddf8de294aa9d920220482f2ba8d7b62e9f3f7a68b0ef3236bc56e44481d3eb59f62d1daf4b191dc86001483045022100eb27943f8b511a36b1a843f9b3ddf6930aece5a3c0be697dbafc921924fc049c022065ba3e1e4ad57f56337143136c5d3ee3f56dd60f36e798f07b5646e29343d7320147304402206e24158484ebb2cd14b9c410ecd04841d806d8464ce9a827533484c8ad8d921b022021baec9cd0ad46e7b19c8de7df286093b835df5c6243e90b14f5748dc1b7c13901473044022067bfaf0e39d72e49a081d4e43828746ab7524c4764e445173dd96cc7e6187d46022063ef107375cc45d1c26b1e1c87b97694f71645187ad871db9c05b8e981a0da8601483045022100da0162de3e4a5268b616b9d01a1a4f64b0c371c6b44fb1f740a264455f2bc20d02203a0b45a98a341722ad65ae4ad68538d617b1cfbb229751f875615317eaf15dd4014830450221008220c4f97585e67966d4435ad8497eb89945f13dd8ff24048b830582349041a002204cb03f7271895637a31ce6479d15672c2d70528148e3cd6196e6f722117745c50147304402203e83ab4b15bb0680f82779335acf9a3ce45316150a4538d5e3d25cb863fcec5702204b3913874077ed2cae4e10f8786053b6f157973a54d156d5863f13accca595f50147304402201420d2a2830278ffff5842ecb7173a23642f179435443e780b3d1fe04be5c32e02203818202390e0e63b4309b89f9cce08c0f4dfa539c2ed59b05e24325671e2747c0147304402205624ca9d47ae04afd8fff705706d6853f8c679abb385f19e01c36f9380a0bad602203dc817fc55497e4c1759a3dbfff1662faca593a9f10d3a9b3e24d5ee3165d4400147304402203a959f9a34587c56b86826e6ab65644ab19cbd09ca078459eb59956b02bc753002206df5ded568d0e3e3645f8cb8ca02874dd1bfa82933eb5e01ff2e5a773633e51601483045022100a84ed5be60b9e095d40f3f6bd698425cb9c4d8f95e8b43ca6c5120a6c599e9eb022064c703952d18d753f9198d78188a26888e6b06c832d93f8075311d57a13240160147304402202e71d3af33a18397b90072098881fdbdb8d6e4ffa34d21141212dd815c97d00f02207195f1c06a8f44ca72af15fdaba89b07cf6daef9be981c432b9f5c10f1e374200100fd5c02007c21030e88484f2bb5dcfc0b326e9eb565c27c8291efb064d060d226916857a2676e62ac635193687c2102151ad794a3aeb3cf9c190120da3d13d36cd8bdf21ca1ccb15debd61c601314b0ac635293687c2103b45a5955ea7847d121225c752edaeb4a5d731a056a951a876caaf6d1f69adb7dac635393687c2102def03a6ffade4ffb0017c8d93859a247badd60e2d76d00e2a3713f6621932ec1ac635493687c21035f17aa7d58b8c3ee0d87240fded52b27f3f12768a0a54ba2595e0a929dd87155ac635593687c2103c8582ac6b0bd20cc1b02c6a86bad2ea10cadb758fedd754ba0d97be85b63b5a7ac635693687c21028148a1f9669fc4471e76f7a371d7cc0563b26e0821d9633fd37649744ff54edaac635793687c2102f0313701b0035f0365a59ce1a3d7ae7045e1f2fb25c4656c08071e5baf51483dac635893687c21024c4c25d08173b3c4d4e1375f8107fd7040c2dc0691ae1bf6fe82b8c88a85185fac635993687c210360fe2daa8661a3d25d0df79875d70b1c3d443ade731caafda7488cb68b4071b0ac635a93687c210250e41a6a4abd7b0b3a49eaec24a6fafa99e5aa7b1e3a5aabe60664276df3d937ac635b93687c2103045a32125930ca103c7d7c79b6f379754796cd4ea7fb0059da926e415e3877d3ac635c93687c210344943249d7ca9b47316fef0c2a413dda3a75416a449a29f310ab7fc9d052ed70ac635d93687c2103c62967320b63df5136ff1ef4c7959ef5917ee5a44f75c83e870bc488143d4d69ac635e93687c21020429f776e15770e4dc52bd6f72e6ed6908d51de1c4a64878433c4e3860a48dc4ac635f93680150a000000000"); -} diff --git a/tests/tests/sidechain_addresses_test.cpp b/tests/tests/sidechain_addresses_test.cpp index b06e3b74..f0dbe520 100644 --- a/tests/tests/sidechain_addresses_test.cpp +++ b/tests/tests/sidechain_addresses_test.cpp @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE( sidechain_address_add_test ) { BOOST_TEST_MESSAGE("Send sidechain_address_add_operation"); sidechain_address_add_operation op; - + op.payer = alice_id; op.sidechain_address_account = alice_id; op.sidechain = sidechain_type::bitcoin; op.deposit_public_key = "deposit_public_key"; @@ -77,6 +77,7 @@ BOOST_AUTO_TEST_CASE( sidechain_address_update_test ) { BOOST_TEST_MESSAGE("Send sidechain_address_update_operation"); sidechain_address_update_operation op; + op.payer = alice_id; op.sidechain_address_id = sidechain_address_id_type(0); op.sidechain_address_account = obj->sidechain_address_account; op.sidechain = obj->sidechain; @@ -124,8 +125,9 @@ BOOST_AUTO_TEST_CASE( sidechain_address_delete_test ) { BOOST_TEST_MESSAGE("Send sidechain_address_delete_operation"); sidechain_address_delete_operation op; + op.payer = alice_id; op.sidechain_address_id = sidechain_address_id_type(0); - op.sidechain_address_account = obj->sidechain_address_account; + op.sidechain_address_account = alice_id; op.sidechain = obj->sidechain; trx.operations.push_back(op);