From 1f505d9db92e916aae538cce2e9f04c556d0a25e Mon Sep 17 00:00:00 2001 From: gladcow Date: Fri, 24 Jan 2020 14:15:16 +0300 Subject: [PATCH] unit test for btc tx serialization --- .../peerplays_sidechain/bitcoin_utils.cpp | 129 +++++++----------- .../peerplays_sidechain/bitcoin_utils.hpp | 38 ++++++ .../bitcoin_utils_test.cpp | 25 ++++ 3 files changed, 111 insertions(+), 81 deletions(-) create mode 100644 tests/peerplays_sidechain/bitcoin_utils_test.cpp diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp index d3c089fe..8ac185f8 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp @@ -169,88 +169,59 @@ bytes signature_for_raw_transaction(const bytes& unsigned_tx, const fc::ecc::pri return bytes(res.begin(), res.begin() + res.size()); } -struct btc_outpoint +bytes btc_tx::to_bytes() const { - fc::uint256 hash; - uint32_t n; -}; - -struct btc_in -{ - btc_outpoint prevout; - bytes scriptSig; - uint32_t nSequence; - bytes scriptWitness; -}; - -struct btc_out -{ - int64_t nValue; - bytes scriptPubKey; -}; - -struct btc_tx -{ - std::vector vin; - std::vector vout; - int32_t nVersion; - uint32_t nLockTime; - bool hasWitness; - - bytes to_bytes() const + bytes res; + WriteBytesStream str(res); + str.add(nVersion); + if(hasWitness) { - bytes res; - WriteBytesStream str(res); - str.add(nVersion); - if(hasWitness) - { - std::vector dummy; - fc::raw::pack(str, dummy); - unsigned char flags = 1; - str.put(flags); - } - fc::raw::pack(str, vin); - fc::raw::pack(str, vout); - if(hasWitness) - { - for(const auto& in: vin) - fc::raw::pack(str, in.scriptWitness); - } - str.add(nLockTime); - return res; + std::vector dummy; + fc::raw::pack(str, dummy); + unsigned char flags = 1; + str.put(flags); } - - void fill_from_bytes(const bytes& data) + fc::raw::pack(str, vin); + fc::raw::pack(str, vout); + if(hasWitness) { - ReadBytesStream ds( data ); - ds.direct_read(nVersion); - 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. */ - fc::raw::unpack(ds, vin); - if (vin.size() == 0) { - /* We read a dummy or an empty vin. */ - ds.get(flags); - if (flags != 0) { - fc::raw::unpack(ds, vin); - fc::raw::unpack(ds, vout); - hasWitness = true; - } - } else { - /* We read a non-empty vin. Assume a normal vout follows. */ - fc::raw::unpack(ds, vout); - } - if (hasWitness) { - /* The witness flag is present, and we support witnesses. */ - for (size_t i = 0; i < vin.size(); i++) { - fc::raw::unpack(ds, vin[i].scriptWitness); - } - } - ds.direct_read(nLockTime); + for(const auto& in: vin) + fc::raw::pack(str, in.scriptWitness); } -}; + str.add(nLockTime); + return res; +} + +void btc_tx::fill_from_bytes(const bytes& data) +{ + ReadBytesStream ds( data ); + ds.direct_read(nVersion); + 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. */ + fc::raw::unpack(ds, vin); + if (vin.size() == 0) { + /* We read a dummy or an empty vin. */ + ds.get(flags); + if (flags != 0) { + fc::raw::unpack(ds, vin); + fc::raw::unpack(ds, vout); + hasWitness = true; + } + } else { + /* We read a non-empty vin. Assume a normal vout follows. */ + fc::raw::unpack(ds, vout); + } + if (hasWitness) { + /* The witness flag is present, and we support witnesses. */ + for (size_t i = 0; i < vin.size(); i++) { + fc::raw::unpack(ds, vin[i].scriptWitness); + } + } + ds.direct_read(nLockTime); +} bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, const bytes& redeem_script, const std::vector > &priv_keys) { @@ -278,7 +249,3 @@ bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, const bytes& redeem } }} - -FC_REFLECT(graphene::peerplays_sidechain::btc_outpoint, (hash)(n)) -FC_REFLECT(graphene::peerplays_sidechain::btc_in, (prevout)(scriptSig)(nSequence)) -FC_REFLECT(graphene::peerplays_sidechain::btc_out, (nValue)(scriptPubKey)) 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 index cf5dcb68..8ca5475f 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp @@ -18,4 +18,42 @@ std::string p2sh_address_from_redeem_script(const bytes& script, bitcoin_network */ bytes sign_pw_transfer_transaction(const bytes& unsigned_tx, const bytes& redeem_script, const std::vector>& priv_keys); +struct btc_outpoint +{ + fc::uint256 hash; + uint32_t n; +}; + +struct btc_in +{ + btc_outpoint prevout; + bytes scriptSig; + uint32_t nSequence; + bytes scriptWitness; +}; + +struct btc_out +{ + int64_t nValue; + bytes scriptPubKey; +}; + +struct btc_tx +{ + std::vector vin; + std::vector vout; + int32_t nVersion; + uint32_t nLockTime; + bool hasWitness; + + bytes to_bytes() const; + void fill_from_bytes(const bytes& data); +}; + }} + +FC_REFLECT(graphene::peerplays_sidechain::btc_outpoint, (hash)(n)) +// btc_in::scriptWitness is filled only in transaction serialization +FC_REFLECT(graphene::peerplays_sidechain::btc_in, (prevout)(scriptSig)(nSequence)) +FC_REFLECT(graphene::peerplays_sidechain::btc_out, (nValue)(scriptPubKey)) +// btc_tx is serialized manually diff --git a/tests/peerplays_sidechain/bitcoin_utils_test.cpp b/tests/peerplays_sidechain/bitcoin_utils_test.cpp new file mode 100644 index 00000000..3b66aff6 --- /dev/null +++ b/tests/peerplays_sidechain/bitcoin_utils_test.cpp @@ -0,0 +1,25 @@ +#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(); + BOOST_CHECK(bintx == buff); +}