CLANG code format

This commit is contained in:
satyakoneru 2020-04-17 04:59:11 +00:00
parent 2739b56b94
commit b5a3ca8040
19 changed files with 1015 additions and 1098 deletions

281
libraries/plugins/peerplays_sidechain/bitcoin/bech32.cpp Executable file → Normal file
View file

@ -6,138 +6,135 @@
// #include <bech32.h> // #include <bech32.h>
namespace namespace {
{
typedef std::vector<uint8_t> data; typedef std::vector<uint8_t> data;
/** The Bech32 character set for encoding. */ /** The Bech32 character set for encoding. */
const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; const char *CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
/** The Bech32 character set for decoding. */ /** The Bech32 character set for decoding. */
const int8_t CHARSET_REV[128] = { const int8_t CHARSET_REV[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1};
};
/** Concatenate two byte arrays. */ /** Concatenate two byte arrays. */
data Cat(data x, const data& y) data Cat(data x, const data &y) {
{ x.insert(x.end(), y.begin(), y.end());
x.insert(x.end(), y.begin(), y.end()); return x;
return x;
} }
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to /** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
* bits correspond to earlier values. */ * bits correspond to earlier values. */
uint32_t PolyMod(const data& v) uint32_t PolyMod(const data &v) {
{ // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
// The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
// implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) = // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
// 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
// [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
// The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
// v(x) mod g(x), where g(x) is the Bech32 generator, // v(x) mod g(x), where g(x) is the Bech32 generator,
// x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
// that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
// window of 1023 characters. Among the various possible BCH codes, one was selected to in // window of 1023 characters. Among the various possible BCH codes, one was selected to in
// fact guarantee detection of up to 4 errors within a window of 89 characters. // fact guarantee detection of up to 4 errors within a window of 89 characters.
// Note that the coefficients are elements of GF(32), here represented as decimal numbers // Note that the coefficients are elements of GF(32), here represented as decimal numbers
// between {}. In this finite field, addition is just XOR of the corresponding numbers. For // between {}. In this finite field, addition is just XOR of the corresponding numbers. For
// example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
// treating the bits of values themselves as coefficients of a polynomial over a smaller field, // treating the bits of values themselves as coefficients of a polynomial over a smaller field,
// GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} = // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
// (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
// = a^3 + 1 (mod a^5 + a^3 + 1) = {9}. // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
// During the course of the loop below, `c` contains the bitpacked coefficients of the // During the course of the loop below, `c` contains the bitpacked coefficients of the
// polynomial constructed from just the values of v that were processed so far, mod g(x). In // polynomial constructed from just the values of v that were processed so far, mod g(x). In
// the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of // the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of
// v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
// for `c`. // for `c`.
uint32_t c = 1; uint32_t c = 1;
for (auto v_i : v) { for (auto v_i : v) {
// We want to update `c` to correspond to a polynomial with one extra term. If the initial // We want to update `c` to correspond to a polynomial with one extra term. If the initial
// value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
// correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
// process. Simplifying: // process. Simplifying:
// c'(x) = (f(x) * x + v_i) mod g(x) // c'(x) = (f(x) * x + v_i) mod g(x)
// ((f(x) mod g(x)) * x + v_i) mod g(x) // ((f(x) mod g(x)) * x + v_i) mod g(x)
// (c(x) * x + v_i) mod g(x) // (c(x) * x + v_i) mod g(x)
// If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
// c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x) // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
// = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x) // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
// = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
// If we call (x^6 mod g(x)) = k(x), this can be written as // If we call (x^6 mod g(x)) = k(x), this can be written as
// c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x) // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
// First, determine the value of c0: // First, determine the value of c0:
uint8_t c0 = c >> 25; uint8_t c0 = c >> 25;
// Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i: // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
c = ((c & 0x1ffffff) << 5) ^ v_i; c = ((c & 0x1ffffff) << 5) ^ v_i;
// Finally, for each set bit n in c0, conditionally add {2^n}k(x): // Finally, for each set bit n in c0, conditionally add {2^n}k(x):
if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18} if (c0 & 1)
if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13} c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26} if (c0 & 2)
if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29} c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19} if (c0 & 4)
} c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
return c; if (c0 & 8)
c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
if (c0 & 16)
c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
}
return c;
} }
/** Convert to lower case. */ /** Convert to lower case. */
inline unsigned char LowerCase(unsigned char c) inline unsigned char LowerCase(unsigned char c) {
{ return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
} }
/** Expand a HRP for use in checksum computation. */ /** Expand a HRP for use in checksum computation. */
data ExpandHRP(const std::string& hrp) data ExpandHRP(const std::string &hrp) {
{ data ret;
data ret; ret.reserve(hrp.size() + 90);
ret.reserve(hrp.size() + 90); ret.resize(hrp.size() * 2 + 1);
ret.resize(hrp.size() * 2 + 1); for (size_t i = 0; i < hrp.size(); ++i) {
for (size_t i = 0; i < hrp.size(); ++i) { unsigned char c = hrp[i];
unsigned char c = hrp[i]; ret[i] = c >> 5;
ret[i] = c >> 5; ret[i + hrp.size() + 1] = c & 0x1f;
ret[i + hrp.size() + 1] = c & 0x1f; }
} ret[hrp.size()] = 0;
ret[hrp.size()] = 0; return ret;
return ret;
} }
/** Verify a checksum. */ /** Verify a checksum. */
bool VerifyChecksum(const std::string& hrp, const data& values) bool VerifyChecksum(const std::string &hrp, const data &values) {
{ // PolyMod computes what value to xor into the final values to make the checksum 0. However,
// PolyMod computes what value to xor into the final values to make the checksum 0. However, // if we required that the checksum was 0, it would be the case that appending a 0 to a valid
// if we required that the checksum was 0, it would be the case that appending a 0 to a valid // list of values would result in a new valid list. For that reason, Bech32 requires the
// list of values would result in a new valid list. For that reason, Bech32 requires the // resulting checksum to be 1 instead.
// resulting checksum to be 1 instead. return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
} }
/** Create a checksum. */ /** Create a checksum. */
data CreateChecksum(const std::string& hrp, const data& values) data CreateChecksum(const std::string &hrp, const data &values) {
{ data enc = Cat(ExpandHRP(hrp), values);
data enc = Cat(ExpandHRP(hrp), values); enc.resize(enc.size() + 6); // Append 6 zeroes
enc.resize(enc.size() + 6); // Append 6 zeroes uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes. data ret(6);
data ret(6); for (size_t i = 0; i < 6; ++i) {
for (size_t i = 0; i < 6; ++i) { // Convert the 5-bit groups in mod to checksum values.
// Convert the 5-bit groups in mod to checksum values. ret[i] = (mod >> (5 * (5 - i))) & 31;
ret[i] = (mod >> (5 * (5 - i))) & 31; }
} return ret;
return ret;
} }
} // namespace } // namespace
@ -145,48 +142,52 @@ data CreateChecksum(const std::string& hrp, const data& values)
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace bech32 { namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace bech32 {
/** Encode a Bech32 string. */ /** Encode a Bech32 string. */
std::string Encode(const std::string& hrp, const data& values) { std::string Encode(const std::string &hrp, const data &values) {
data checksum = CreateChecksum(hrp, values); data checksum = CreateChecksum(hrp, values);
data combined = Cat(values, checksum); data combined = Cat(values, checksum);
std::string ret = hrp + '1'; std::string ret = hrp + '1';
ret.reserve(ret.size() + combined.size()); ret.reserve(ret.size() + combined.size());
for (auto c : combined) { for (auto c : combined) {
ret += CHARSET[c]; ret += CHARSET[c];
} }
return ret; return ret;
} }
/** Decode a Bech32 string. */ /** Decode a Bech32 string. */
std::pair<std::string, data> Decode(const std::string& str) { std::pair<std::string, data> Decode(const std::string &str) {
bool lower = false, upper = false; bool lower = false, upper = false;
for (size_t i = 0; i < str.size(); ++i) { for (size_t i = 0; i < str.size(); ++i) {
unsigned char c = str[i]; unsigned char c = str[i];
if (c < 33 || c > 126) return {}; if (c < 33 || c > 126)
if (c >= 'a' && c <= 'z') lower = true; return {};
if (c >= 'A' && c <= 'Z') upper = true; if (c >= 'a' && c <= 'z')
} lower = true;
if (lower && upper) return {}; if (c >= 'A' && c <= 'Z')
size_t pos = str.rfind('1'); upper = true;
if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) { }
return {}; if (lower && upper)
} return {};
data values(str.size() - 1 - pos); size_t pos = str.rfind('1');
for (size_t i = 0; i < str.size() - 1 - pos; ++i) { if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
unsigned char c = str[i + pos + 1]; return {};
int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c]; }
if (rev == -1) { data values(str.size() - 1 - pos);
return {}; for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
} unsigned char c = str[i + pos + 1];
values[i] = rev; int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c];
} if (rev == -1) {
std::string hrp; return {};
for (size_t i = 0; i < pos; ++i) { }
hrp += LowerCase(str[i]); values[i] = rev;
} }
if (!VerifyChecksum(hrp, values)) { std::string hrp;
return {}; for (size_t i = 0; i < pos; ++i) {
} hrp += LowerCase(str[i]);
return {hrp, data(values.begin(), values.end() - 6)}; }
if (!VerifyChecksum(hrp, values)) {
return {};
}
return {hrp, data(values.begin(), values.end() - 6)};
} }
} } } }// namespace sidechain::bech32 }}}} // namespace graphene::peerplays_sidechain::bitcoin::bech32

View file

@ -1,93 +1,89 @@
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
#include <sstream>
#include <fc/crypto/base58.hpp> #include <fc/crypto/base58.hpp>
#include <graphene/peerplays_sidechain/bitcoin/segwit_addr.hpp> #include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_script.hpp> #include <graphene/peerplays_sidechain/bitcoin/bitcoin_script.hpp>
#include <graphene/peerplays_sidechain/bitcoin/segwit_addr.hpp>
#include <sstream>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
bool bitcoin_address::operator==( const bitcoin_address& btc_addr ) const { bool bitcoin_address::operator==(const bitcoin_address &btc_addr) const {
return ( this->address == btc_addr.address ) && return (this->address == btc_addr.address) &&
( this->type == btc_addr.type ) && (this->type == btc_addr.type) &&
( this->raw_address == btc_addr.raw_address ) && (this->raw_address == btc_addr.raw_address) &&
( this->network_type == btc_addr.network_type); (this->network_type == btc_addr.network_type);
} }
bytes bitcoin_address::get_script() const bytes bitcoin_address::get_script() const {
{ switch (type) {
switch ( type ) { case payment_type::NULLDATA:
case payment_type::NULLDATA: return script_builder() << op::RETURN << raw_address;
return script_builder() << op::RETURN << raw_address; case payment_type::P2PK:
case payment_type::P2PK: return script_builder() << raw_address << op::CHECKSIG;
return script_builder() << raw_address << op::CHECKSIG; case payment_type::P2PKH:
case payment_type::P2PKH: return script_builder() << op::DUP << op::HASH160 << raw_address << op::EQUALVERIFY << op::CHECKSIG;
return script_builder() << op::DUP << op::HASH160 << raw_address << op::EQUALVERIFY << op::CHECKSIG; case payment_type::P2SH:
case payment_type::P2SH: case payment_type::P2SH_WPKH:
case payment_type::P2SH_WPKH: case payment_type::P2SH_WSH:
case payment_type::P2SH_WSH: return script_builder() << op::HASH160 << raw_address << op::EQUAL;
return script_builder() << op::HASH160 << raw_address << op::EQUAL; case payment_type::P2WPKH:
case payment_type::P2WPKH: case payment_type::P2WSH:
case payment_type::P2WSH: return script_builder() << op::_0 << raw_address;
return script_builder() << op::_0 << raw_address; default:
default: return raw_address;
return raw_address; }
}
} }
payment_type bitcoin_address::determine_type() payment_type bitcoin_address::determine_type() {
{ if (is_p2pk()) {
if( is_p2pk() ) {
return payment_type::P2PK; return payment_type::P2PK;
} else if( is_p2wpkh() ) { } else if (is_p2wpkh()) {
return payment_type::P2WPKH; return payment_type::P2WPKH;
} else if( is_p2wsh() ) { } else if (is_p2wsh()) {
return payment_type::P2WSH; return payment_type::P2WSH;
} else if( is_p2pkh() ) { } else if (is_p2pkh()) {
return payment_type::P2PKH; return payment_type::P2PKH;
} else if( is_p2sh() ) { } else if (is_p2sh()) {
return payment_type::P2SH; return payment_type::P2SH;
} else { } else {
return payment_type::NULLDATA; return payment_type::NULLDATA;
} }
} }
bytes bitcoin_address::determine_raw_address() bytes bitcoin_address::determine_raw_address() {
{
bytes result; bytes result;
switch( type ) { switch (type) {
case payment_type::P2PK : { case payment_type::P2PK: {
result = parse_hex( address ); result = parse_hex(address);
break; break;
} }
case payment_type::P2WPKH : case payment_type::P2WPKH:
case payment_type::P2WSH : { case payment_type::P2WSH: {
std::string prefix( address.compare(0,4,"bcrt") == 0 ? std::string( address.begin(), address.begin() + 4 ) : std::string prefix(address.compare(0, 4, "bcrt") == 0 ? std::string(address.begin(), address.begin() + 4) : std::string(address.begin(), address.begin() + 2));
std::string( address.begin(), address.begin() + 2 ) ); const auto &decode_bech32 = segwit_addr::decode(prefix, address);
const auto& decode_bech32 = segwit_addr::decode( prefix, address ); result = bytes(decode_bech32.second.begin(), decode_bech32.second.end());
result = bytes( decode_bech32.second.begin(), decode_bech32.second.end() ); break;
break; }
} case payment_type::P2SH_WPKH:
case payment_type::P2SH_WPKH : case payment_type::P2SH_WSH:
case payment_type::P2SH_WSH : case payment_type::P2PKH:
case payment_type::P2PKH : case payment_type::P2SH: {
case payment_type::P2SH : { bytes hex_addr = fc::from_base58(address);
bytes hex_addr = fc::from_base58( address ); result = bytes(hex_addr.begin() + 1, hex_addr.begin() + 21);
result = bytes( hex_addr.begin() + 1, hex_addr.begin() + 21 ); break;
break; }
} case payment_type::NULLDATA:
case payment_type::NULLDATA : return result; return result;
} }
return result; return result;
} }
bool bitcoin_address::check_segwit_address( const size_segwit_address& size ) const { bool bitcoin_address::check_segwit_address(const size_segwit_address &size) const {
if( !address.compare(0,4,"bcrt") || !address.compare(0,2,"bc") || !address.compare(0,2,"tb") ) { if (!address.compare(0, 4, "bcrt") || !address.compare(0, 2, "bc") || !address.compare(0, 2, "tb")) {
std::string prefix( !address.compare(0,4,"bcrt") ? std::string(address.begin(), address.begin() + 4) : std::string prefix(!address.compare(0, 4, "bcrt") ? std::string(address.begin(), address.begin() + 4) : std::string(address.begin(), address.begin() + 2));
std::string(address.begin(), address.begin() + 2) );
const auto& decode_bech32 = segwit_addr::decode( prefix, address ); const auto &decode_bech32 = segwit_addr::decode(prefix, address);
if( decode_bech32.first == -1 || decode_bech32.second.size() != size ) { if (decode_bech32.first == -1 || decode_bech32.second.size() != size) {
return false; return false;
} }
@ -96,170 +92,156 @@ bool bitcoin_address::check_segwit_address( const size_segwit_address& size ) co
return false; return false;
} }
bool bitcoin_address::is_p2pk() const bool bitcoin_address::is_p2pk() const {
{
try { try {
bool prefix = !address.compare(0,2,"02") || !address.compare(0,2,"03"); bool prefix = !address.compare(0, 2, "02") || !address.compare(0, 2, "03");
if( address.size() == 66 && prefix ) { if (address.size() == 66 && prefix) {
parse_hex( address ); parse_hex(address);
return true; return true;
} }
} catch( fc::exception e ) { } catch (fc::exception e) {
return false; return false;
} }
return false; return false;
} }
bool bitcoin_address::is_p2wpkh() const bool bitcoin_address::is_p2wpkh() const {
{ return check_segwit_address(size_segwit_address::P2WPKH);
return check_segwit_address( size_segwit_address::P2WPKH );
} }
bool bitcoin_address::is_p2wsh() const bool bitcoin_address::is_p2wsh() const {
{ return check_segwit_address(size_segwit_address::P2WSH);
return check_segwit_address( size_segwit_address::P2WSH );
} }
bool bitcoin_address::is_p2pkh() const bool bitcoin_address::is_p2pkh() const {
{
try { try {
bytes hex_addr = fc::from_base58( address ); bytes hex_addr = fc::from_base58(address);
if( hex_addr.size() == 25 && ( static_cast<unsigned char>( hex_addr[0] ) == 0x00 || if (hex_addr.size() == 25 && (static_cast<unsigned char>(hex_addr[0]) == 0x00 ||
static_cast<unsigned char>( hex_addr[0] ) == 0x6f ) ) { static_cast<unsigned char>(hex_addr[0]) == 0x6f)) {
return true; return true;
} }
return false; return false;
} catch( fc::exception e ) { } catch (fc::exception e) {
return false; return false;
} }
} }
bool bitcoin_address::is_p2sh() const bool bitcoin_address::is_p2sh() const {
{
try { try {
bytes hex_addr = fc::from_base58( address ); bytes hex_addr = fc::from_base58(address);
if( hex_addr.size() == 25 && ( static_cast<unsigned char>( hex_addr[0] ) == 0x05 || if (hex_addr.size() == 25 && (static_cast<unsigned char>(hex_addr[0]) == 0x05 ||
static_cast<unsigned char>( hex_addr[0] ) == 0xc4 ) ) { static_cast<unsigned char>(hex_addr[0]) == 0xc4)) {
return true; return true;
} }
return false; return false;
} catch( fc::exception e ) { } catch (fc::exception e) {
return false; return false;
} }
} }
btc_multisig_address::btc_multisig_address( const size_t n_required, const accounts_keys& keys ) : btc_multisig_address::btc_multisig_address(const size_t n_required, const accounts_keys &keys) :
keys_required ( n_required ), witnesses_keys( keys ) keys_required(n_required),
{ witnesses_keys(keys) {
create_redeem_script(); create_redeem_script();
create_address(); create_address();
type = payment_type::P2SH; type = payment_type::P2SH;
} }
size_t btc_multisig_address::count_intersection( const accounts_keys& keys ) const size_t btc_multisig_address::count_intersection(const accounts_keys &keys) const {
{ FC_ASSERT(keys.size() > 0);
FC_ASSERT( keys.size() > 0 );
int intersections_count = 0; int intersections_count = 0;
for( auto& key : keys ) { for (auto &key : keys) {
auto witness_key = witnesses_keys.find( key.first ); auto witness_key = witnesses_keys.find(key.first);
if( witness_key == witnesses_keys.end() ) continue; if (witness_key == witnesses_keys.end())
if( key.second == witness_key->second ) continue;
if (key.second == witness_key->second)
intersections_count++; intersections_count++;
} }
return intersections_count; return intersections_count;
} }
void btc_multisig_address::create_redeem_script() void btc_multisig_address::create_redeem_script() {
{ FC_ASSERT(keys_required > 0);
FC_ASSERT( keys_required > 0 ); FC_ASSERT(keys_required < witnesses_keys.size());
FC_ASSERT( keys_required < witnesses_keys.size() );
redeem_script.clear(); redeem_script.clear();
redeem_script.push_back( op_num[keys_required - 1] ); redeem_script.push_back(op_num[keys_required - 1]);
for( const auto& key : witnesses_keys ) { for (const auto &key : witnesses_keys) {
std::stringstream ss; std::stringstream ss;
ss << std::hex << key.second.key_data.size(); ss << std::hex << key.second.key_data.size();
auto key_size_hex = parse_hex( ss.str() ); auto key_size_hex = parse_hex(ss.str());
redeem_script.insert( redeem_script.end(), key_size_hex.begin(), key_size_hex.end() ); redeem_script.insert(redeem_script.end(), key_size_hex.begin(), key_size_hex.end());
redeem_script.insert( redeem_script.end(), key.second.key_data.begin(), key.second.key_data.end() ); redeem_script.insert(redeem_script.end(), key.second.key_data.begin(), key.second.key_data.end());
} }
redeem_script.push_back( op_num[witnesses_keys.size() - 1] ); redeem_script.push_back(op_num[witnesses_keys.size() - 1]);
redeem_script.push_back( OP_CHECKMULTISIG ); redeem_script.push_back(OP_CHECKMULTISIG);
} }
void btc_multisig_address::create_address() void btc_multisig_address::create_address() {
{ FC_ASSERT(redeem_script.size() > 0);
FC_ASSERT( redeem_script.size() > 0 );
raw_address.clear(); raw_address.clear();
fc::sha256 hash256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() ); fc::sha256 hash256 = fc::sha256::hash(redeem_script.data(), redeem_script.size());
fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
bytes temp_addr_hash( parse_hex( hash160.str() ) ); bytes temp_addr_hash(parse_hex(hash160.str()));
raw_address.push_back( OP_HASH160 ); raw_address.push_back(OP_HASH160);
std::stringstream ss; std::stringstream ss;
ss << std::hex << temp_addr_hash.size(); ss << std::hex << temp_addr_hash.size();
auto address_size_hex = parse_hex( ss.str() ); auto address_size_hex = parse_hex(ss.str());
raw_address.insert( raw_address.end(), address_size_hex.begin(), address_size_hex.end() ); raw_address.insert(raw_address.end(), address_size_hex.begin(), address_size_hex.end());
raw_address.insert( raw_address.end(), temp_addr_hash.begin(), temp_addr_hash.end() ); raw_address.insert(raw_address.end(), temp_addr_hash.begin(), temp_addr_hash.end());
raw_address.push_back( OP_EQUAL ); raw_address.push_back(OP_EQUAL);
} }
btc_multisig_segwit_address::btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ) : btc_multisig_segwit_address::btc_multisig_segwit_address(const size_t n_required, const accounts_keys &keys) :
btc_multisig_address( n_required, keys ) btc_multisig_address(n_required, keys) {
{
create_witness_script(); create_witness_script();
create_segwit_address(); create_segwit_address();
type = payment_type::P2SH; type = payment_type::P2SH;
} }
bool btc_multisig_segwit_address::operator==( const btc_multisig_segwit_address& addr ) const bool btc_multisig_segwit_address::operator==(const btc_multisig_segwit_address &addr) const {
{ if (address != addr.address || redeem_script != addr.redeem_script ||
if( address != addr.address || redeem_script != addr.redeem_script ||
witnesses_keys != addr.witnesses_keys || witness_script != addr.witness_script || witnesses_keys != addr.witnesses_keys || witness_script != addr.witness_script ||
raw_address != addr.raw_address ) raw_address != addr.raw_address)
return false; return false;
return true; return true;
} }
std::vector<public_key_type> btc_multisig_segwit_address::get_keys() { std::vector<public_key_type> btc_multisig_segwit_address::get_keys() {
std::vector<public_key_type> keys; std::vector<public_key_type> keys;
for( const auto& k : witnesses_keys ) { for (const auto &k : witnesses_keys) {
keys.push_back( k.second ); keys.push_back(k.second);
} }
return keys; return keys;
} }
void btc_multisig_segwit_address::create_witness_script() void btc_multisig_segwit_address::create_witness_script() {
{ const auto redeem_sha256 = fc::sha256::hash(redeem_script.data(), redeem_script.size());
const auto redeem_sha256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() ); witness_script.push_back(OP_0);
witness_script.push_back( OP_0 ); witness_script.push_back(0x20); // PUSH_32
witness_script.push_back( 0x20 ); // PUSH_32 witness_script.insert(witness_script.end(), redeem_sha256.data(), redeem_sha256.data() + redeem_sha256.data_size());
witness_script.insert( witness_script.end(), redeem_sha256.data(), redeem_sha256.data() + redeem_sha256.data_size() );
} }
void btc_multisig_segwit_address::create_segwit_address() void btc_multisig_segwit_address::create_segwit_address() {
{ fc::sha256 hash256 = fc::sha256::hash(witness_script.data(), witness_script.size());
fc::sha256 hash256 = fc::sha256::hash( witness_script.data(), witness_script.size() ); fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() );
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size() ); raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
address = fc::to_base58( get_address_bytes( raw_address ) ); address = fc::to_base58(get_address_bytes(raw_address));
} }
bytes btc_multisig_segwit_address::get_address_bytes( const bytes& script_hash ) bytes btc_multisig_segwit_address::get_address_bytes(const bytes &script_hash) {
{ bytes address_bytes(1, TESTNET_SCRIPT); // 1 byte version
bytes address_bytes( 1, TESTNET_SCRIPT ); // 1 byte version address_bytes.insert(address_bytes.end(), script_hash.begin(), script_hash.end());
address_bytes.insert( address_bytes.end(), script_hash.begin(), script_hash.end() ); fc::sha256 hash256 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
fc::sha256 hash256 = fc::sha256::hash( fc::sha256::hash( address_bytes.data(), address_bytes.size() ) ); address_bytes.insert(address_bytes.end(), hash256.data(), hash256.data() + 4); // 4 byte checksum
address_bytes.insert( address_bytes.end(), hash256.data(), hash256.data() + 4 ); // 4 byte checksum
return address_bytes; return address_bytes;
} }
btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t> > &keys_data, network ntype) {
network ntype)
{
network_type = ntype; network_type = ntype;
create_redeem_script(keys_data); create_redeem_script(keys_data);
create_witness_script(); create_witness_script();
@ -267,8 +249,7 @@ btc_weighted_multisig_address::btc_weighted_multisig_address(const std::vector<s
type = payment_type::P2WSH; type = payment_type::P2WSH;
} }
void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>>& keys_data) void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
{
script_builder builder; script_builder builder;
uint32_t total_weight = 0; uint32_t total_weight = 0;
builder << uint32_t(0); builder << uint32_t(0);
@ -292,27 +273,24 @@ void btc_weighted_multisig_address::create_redeem_script(const std::vector<std::
raw_address = bytes(sh.data(), sh.data() + sh.data_size()); raw_address = bytes(sh.data(), sh.data() + sh.data_size());
} }
void btc_weighted_multisig_address::create_witness_script() void btc_weighted_multisig_address::create_witness_script() {
{
script_builder builder; script_builder builder;
builder << op::_0; builder << op::_0;
builder << fc::sha256::hash( redeem_script_.data(), redeem_script_.size() ); builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size());
witness_script_ = builder; witness_script_ = builder;
} }
void btc_weighted_multisig_address::create_segwit_address() void btc_weighted_multisig_address::create_segwit_address() {
{
std::string hrp; std::string hrp;
switch(network_type) switch (network_type) {
{ case (network::mainnet):
case(network::mainnet):
hrp = "bc"; hrp = "bc";
break; break;
case(network::testnet): case (network::testnet):
hrp = "tb"; hrp = "tb";
break; break;
case(network::regtest): case (network::regtest):
hrp = "bcrt"; hrp = "bcrt";
break; break;
} }
@ -373,9 +351,8 @@ void btc_one_or_m_of_n_multisig_address::create_segwit_address() {
} }
btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data,
const std::vector<std::pair<fc::ecc::public_key, uint16_t> > &keys_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
bitcoin_address::network ntype) bitcoin_address::network ntype) {
{
network_type = ntype; network_type = ntype;
create_redeem_script(user_key_data, keys_data); create_redeem_script(user_key_data, keys_data);
create_witness_script(); create_witness_script();
@ -383,8 +360,7 @@ btc_one_or_weighted_multisig_address::btc_one_or_weighted_multisig_address(const
type = payment_type::P2WSH; type = payment_type::P2WSH;
} }
void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t> > &keys_data) void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data) {
{
script_builder builder; script_builder builder;
builder << user_key_data.serialize(); builder << user_key_data.serialize();
builder << op::CHECKSIG; builder << op::CHECKSIG;
@ -412,16 +388,14 @@ void btc_one_or_weighted_multisig_address::create_redeem_script(const fc::ecc::p
raw_address = bytes(sh.data(), sh.data() + sh.data_size()); raw_address = bytes(sh.data(), sh.data() + sh.data_size());
} }
void btc_one_or_weighted_multisig_address::create_witness_script() void btc_one_or_weighted_multisig_address::create_witness_script() {
{
script_builder builder; script_builder builder;
builder << op::_0; builder << op::_0;
builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size()); builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size());
witness_script_ = builder; witness_script_ = builder;
} }
void btc_one_or_weighted_multisig_address::create_segwit_address() void btc_one_or_weighted_multisig_address::create_segwit_address() {
{
std::string hrp; std::string hrp;
switch (network_type) { switch (network_type) {
case (network::mainnet): case (network::mainnet):
@ -439,4 +413,4 @@ void btc_one_or_weighted_multisig_address::create_segwit_address()
address = segwit_addr::encode(hrp, 0, hash_data); address = segwit_addr::encode(hrp, 0, hash_data);
} }
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -3,21 +3,19 @@
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
script_builder& script_builder::operator<<( op opcode ) script_builder &script_builder::operator<<(op opcode) {
{ const auto op_byte = static_cast<uint8_t>(opcode);
const auto op_byte = static_cast<uint8_t>( opcode ); if (op_byte < 0 || op_byte > 0xff)
if ( op_byte < 0 || op_byte > 0xff ) throw std::runtime_error("script_builder::operator<<(OP): invalid opcode");
throw std::runtime_error( "script_builder::operator<<(OP): invalid opcode" ); script.push_back(op_byte);
script.push_back( op_byte );
return *this; return *this;
} }
script_builder& script_builder::operator<<( uint32_t number ) script_builder &script_builder::operator<<(uint32_t number) {
{ if (number == 0) {
if ( number == 0 ) { script.push_back(static_cast<uint8_t>(op::_0));
script.push_back( static_cast<uint8_t>( op::_0 ) ); } else if (number <= 16) {
} else if ( number <= 16) { script.push_back(static_cast<uint8_t>(op::_1) + number - 1);
script.push_back( static_cast<uint8_t>( op::_1 ) + number - 1 );
} else { } else {
bytes pack_buf; bytes pack_buf;
while (number) { while (number) {
@ -28,44 +26,40 @@ script_builder& script_builder::operator<<( uint32_t number )
// new zero-byte to make the significant byte < 0x80 again. So, the result can // new zero-byte to make the significant byte < 0x80 again. So, the result can
// be 5 bytes max. // be 5 bytes max.
if (pack_buf.back() & 0x80) if (pack_buf.back() & 0x80)
pack_buf.push_back(0); pack_buf.push_back(0);
*this << pack_buf; *this << pack_buf;
} }
return *this; return *this;
} }
script_builder& script_builder::operator<<( size_t size ) script_builder &script_builder::operator<<(size_t size) {
{ write_compact_size(script, size);
write_compact_size( script, size );
return *this; return *this;
} }
script_builder& script_builder::operator<<( const bytes& sc ) { script_builder &script_builder::operator<<(const bytes &sc) {
write_compact_size( script, sc.size() ); write_compact_size(script, sc.size());
script.insert( script.end(), sc.begin(), sc.end() ); script.insert(script.end(), sc.begin(), sc.end());
return *this; return *this;
} }
script_builder& script_builder::operator<<( const fc::sha256& hash ) script_builder &script_builder::operator<<(const fc::sha256 &hash) {
{ write_compact_size(script, hash.data_size());
write_compact_size( script, hash.data_size() ); script.insert(script.end(), hash.data(), hash.data() + hash.data_size());
script.insert( script.end(), hash.data(), hash.data() + hash.data_size() );
return *this; return *this;
} }
script_builder& script_builder::operator<<( const fc::ripemd160& hash ) script_builder &script_builder::operator<<(const fc::ripemd160 &hash) {
{ write_compact_size(script, hash.data_size());
write_compact_size( script, hash.data_size() ); script.insert(script.end(), hash.data(), hash.data() + hash.data_size());
script.insert( script.end(), hash.data(), hash.data() + hash.data_size() );
return *this; return *this;
} }
script_builder& script_builder::operator<<( const fc::ecc::public_key_data& pubkey_data ) script_builder &script_builder::operator<<(const fc::ecc::public_key_data &pubkey_data) {
{ write_compact_size(script, pubkey_data.size());
write_compact_size( script, pubkey_data.size() ); script.insert(script.end(), pubkey_data.begin(), pubkey_data.begin() + pubkey_data.size());
script.insert( script.end(), pubkey_data.begin(), pubkey_data.begin() + pubkey_data.size() );
return *this; return *this;
} }
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -1,153 +1,133 @@
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp>
#include <fc/crypto/base58.hpp> #include <fc/crypto/base58.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_script.hpp> #include <graphene/peerplays_sidechain/bitcoin/bitcoin_script.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp>
#include <graphene/peerplays_sidechain/bitcoin/serialize.hpp> #include <graphene/peerplays_sidechain/bitcoin/serialize.hpp>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
bool out_point::operator==( const out_point& op ) const bool out_point::operator==(const out_point &op) const {
{ if (this->hash == op.hash &&
if( this->hash == op.hash && this->n == op.n) {
this->n == op.n )
{
return true; return true;
} }
return false; return false;
} }
bool tx_in::operator==( const tx_in& ti ) const bool tx_in::operator==(const tx_in &ti) const {
{ if (this->prevout == ti.prevout &&
if( this->prevout == ti.prevout &&
this->scriptSig == ti.scriptSig && this->scriptSig == ti.scriptSig &&
this->nSequence == ti.nSequence ) this->nSequence == ti.nSequence) {
{
return true; return true;
} }
return false; return false;
} }
bool tx_out::operator==( const tx_out& to ) const bool tx_out::operator==(const tx_out &to) const {
{ if (this->value == to.value &&
if( this->value == to.value && this->scriptPubKey == to.scriptPubKey) {
this->scriptPubKey == to.scriptPubKey )
{
return true; return true;
} }
return false; return false;
} }
bool tx_out::is_p2wsh() const bool tx_out::is_p2wsh() const {
{ if (scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x20)) {
if( scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x20) ) {
return true; return true;
} }
return false; return false;
} }
bool tx_out::is_p2wpkh() const bool tx_out::is_p2wpkh() const {
{ if (scriptPubKey.size() == 22 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x14)) {
if( scriptPubKey.size() == 22 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x14) ) {
return true; return true;
} }
return false; return false;
} }
bool tx_out::is_p2pkh() const bool tx_out::is_p2pkh() const {
{ if (scriptPubKey.size() == 25 && scriptPubKey[0] == static_cast<char>(0x76) && scriptPubKey[1] == static_cast<char>(0xa9) &&
if( scriptPubKey.size() == 25 && scriptPubKey[0] == static_cast<char>(0x76) && scriptPubKey[1] == static_cast<char>(0xa9) && scriptPubKey[2] == static_cast<char>(0x14) && scriptPubKey[23] == static_cast<char>(0x88) && scriptPubKey[24] == static_cast<char>(0xac)) {
scriptPubKey[2] == static_cast<char>(0x14) && scriptPubKey[23] == static_cast<char>(0x88) && scriptPubKey[24] == static_cast<char>(0xac) ) {
return true;
}
return false;
}
bool tx_out::is_p2sh() const
{
if( scriptPubKey.size() == 23 && scriptPubKey[0] == static_cast<char>(0xa9) &&
scriptPubKey[1] == static_cast<char>(0x14) && scriptPubKey[22] == static_cast<char>(0x87) ) {
return true;
}
return false;
}
bool tx_out::is_p2pk() const
{
if( scriptPubKey.size() == 35 && scriptPubKey[0] == static_cast<char>(0x21) && scriptPubKey[34] == static_cast<char>(0xac) ) {
return true; return true;
} }
return false; return false;
} }
bytes tx_out::get_data_or_script() const bool tx_out::is_p2sh() const {
{ if (scriptPubKey.size() == 23 && scriptPubKey[0] == static_cast<char>(0xa9) &&
if( is_p2pkh() ) { scriptPubKey[1] == static_cast<char>(0x14) && scriptPubKey[22] == static_cast<char>(0x87)) {
return bytes( scriptPubKey.begin() + 3, scriptPubKey.begin() + 23 ); return true;
} else if( is_p2sh() || is_p2wpkh() ) { }
return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 22 ); return false;
} else if( is_p2wsh() ) { }
return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 34 );
} else if( is_p2pk() ) { bool tx_out::is_p2pk() const {
return bytes( scriptPubKey.begin() + 1, scriptPubKey.begin() + 34 ); if (scriptPubKey.size() == 35 && scriptPubKey[0] == static_cast<char>(0x21) && scriptPubKey[34] == static_cast<char>(0xac)) {
return true;
}
return false;
}
bytes tx_out::get_data_or_script() const {
if (is_p2pkh()) {
return bytes(scriptPubKey.begin() + 3, scriptPubKey.begin() + 23);
} else if (is_p2sh() || is_p2wpkh()) {
return bytes(scriptPubKey.begin() + 2, scriptPubKey.begin() + 22);
} else if (is_p2wsh()) {
return bytes(scriptPubKey.begin() + 2, scriptPubKey.begin() + 34);
} else if (is_p2pk()) {
return bytes(scriptPubKey.begin() + 1, scriptPubKey.begin() + 34);
} }
return scriptPubKey; return scriptPubKey;
} }
bool bitcoin_transaction::operator!=( const bitcoin_transaction& bt ) const bool bitcoin_transaction::operator!=(const bitcoin_transaction &bt) const {
{ if (this->nVersion != bt.nVersion ||
if( this->nVersion != bt.nVersion || this->vin != bt.vin ||
this->vin != bt.vin || this->vout != bt.vout ||
this->vout != bt.vout || this->nLockTime != bt.nLockTime) {
this->nLockTime != bt.nLockTime )
{
return true; return true;
} }
return false; return false;
} }
fc::sha256 bitcoin_transaction::get_hash() const fc::sha256 bitcoin_transaction::get_hash() const {
{ const auto bytes = pack(*this, true);
const auto bytes = pack( *this, true) ; const auto hash = fc::sha256::hash(fc::sha256::hash(bytes.data(), bytes.size()));
const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); std::reverse(hash.data(), hash.data() + hash.data_size());
std::reverse( hash.data(), hash.data() + hash.data_size() );
return hash; return hash;
} }
fc::sha256 bitcoin_transaction::get_txid() const fc::sha256 bitcoin_transaction::get_txid() const {
{ const auto bytes = pack(*this, false);
const auto bytes = pack( *this, false ); const auto hash = fc::sha256::hash(fc::sha256::hash(bytes.data(), bytes.size()));
const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); std::reverse(hash.data(), hash.data() + hash.data_size());
std::reverse( hash.data(), hash.data() + hash.data_size() );
return hash; return hash;
} }
size_t bitcoin_transaction::get_vsize() const size_t bitcoin_transaction::get_vsize() const {
{
static const auto witness_scale_factor = 4; static const auto witness_scale_factor = 4;
fc::datastream<size_t> no_wit_ds; fc::datastream<size_t> no_wit_ds;
pack( no_wit_ds, *this, false ); pack(no_wit_ds, *this, false);
fc::datastream<size_t> wit_ds; fc::datastream<size_t> wit_ds;
pack( wit_ds, *this, true ); pack(wit_ds, *this, true);
const size_t weight = no_wit_ds.tellp() * ( witness_scale_factor - 1 ) + wit_ds.tellp(); const size_t weight = no_wit_ds.tellp() * (witness_scale_factor - 1) + wit_ds.tellp();
const size_t vsize = ( weight + witness_scale_factor - 1 ) / witness_scale_factor; const size_t vsize = (weight + witness_scale_factor - 1) / witness_scale_factor;
return vsize; return vsize;
} }
void bitcoin_transaction_builder::set_version( int32_t version ) void bitcoin_transaction_builder::set_version(int32_t version) {
{ tx.nVersion = version;
tx.nVersion = version;
} }
void bitcoin_transaction_builder::set_locktime(uint32_t lock_time) void bitcoin_transaction_builder::set_locktime(uint32_t lock_time) {
{ tx.nLockTime = lock_time;
tx.nLockTime = lock_time;
} }
void bitcoin_transaction_builder::add_in( payment_type type, const fc::sha256& txid, uint32_t n_out, const bytes& script_code, bool front, uint32_t sequence ) void bitcoin_transaction_builder::add_in(payment_type type, const fc::sha256 &txid, uint32_t n_out, const bytes &script_code, bool front, uint32_t sequence) {
{
out_point prevout; out_point prevout;
prevout.hash = txid; prevout.hash = txid;
prevout.n = n_out; prevout.n = n_out;
@ -156,97 +136,91 @@ void bitcoin_transaction_builder::add_in( payment_type type, const fc::sha256& t
txin.prevout = prevout; txin.prevout = prevout;
txin.nSequence = sequence; txin.nSequence = sequence;
add_in( type, txin, script_code, front ); add_in(type, txin, script_code, front);
} }
void bitcoin_transaction_builder::add_in( payment_type type, tx_in txin, const bytes& script_code, bool front ) void bitcoin_transaction_builder::add_in(payment_type type, tx_in txin, const bytes &script_code, bool front) {
{ switch (type) {
switch ( type ) { case payment_type::P2SH_WPKH:
case payment_type::P2SH_WPKH: case payment_type::P2SH_WSH:
case payment_type::P2SH_WSH: FC_ASSERT(script_code != bytes());
FC_ASSERT( script_code != bytes() ); txin.scriptSig = script_code;
break;
default: {
if (txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000")) { //coinbase
FC_ASSERT(script_code != bytes());
txin.scriptSig = script_code; txin.scriptSig = script_code;
break;
default:{
if( txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000") ) { //coinbase
FC_ASSERT( script_code != bytes() );
txin.scriptSig = script_code;
}
break;
} }
break;
}
} }
if( front ) { if (front) {
tx.vin.insert( tx.vin.begin(), txin ); tx.vin.insert(tx.vin.begin(), txin);
} else { } else {
tx.vin.push_back( txin ); tx.vin.push_back(txin);
} }
} }
void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const std::string& base58_address, bool front ) void bitcoin_transaction_builder::add_out(payment_type type, int64_t amount, const std::string &base58_address, bool front) {
{
// TODO: add checks // TODO: add checks
const auto address_bytes = fc::from_base58(base58_address); const auto address_bytes = fc::from_base58(base58_address);
add_out( type, amount, bytes( address_bytes.begin() + 1, address_bytes.begin() + 1 + 20 ), front ); add_out(type, amount, bytes(address_bytes.begin() + 1, address_bytes.begin() + 1 + 20), front);
} }
void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const fc::ecc::public_key_data& pubkey, bool front ) void bitcoin_transaction_builder::add_out(payment_type type, int64_t amount, const fc::ecc::public_key_data &pubkey, bool front) {
{ FC_ASSERT(is_payment_to_pubkey(type));
FC_ASSERT( is_payment_to_pubkey( type ) );
if ( type == payment_type::P2PK ) { if (type == payment_type::P2PK) {
const auto pubkey_bytes = bytes( pubkey.begin(), pubkey.begin() + pubkey.size() ); const auto pubkey_bytes = bytes(pubkey.begin(), pubkey.begin() + pubkey.size());
add_out( type, amount, pubkey_bytes, front ); add_out(type, amount, pubkey_bytes, front);
} else { } else {
const auto hash256 = fc::sha256::hash( pubkey.begin(), pubkey.size() ); const auto hash256 = fc::sha256::hash(pubkey.begin(), pubkey.size());
const auto hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); const auto hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
add_out( type, amount, bytes( hash160.data(), hash160.data() + hash160.data_size() ), front ); add_out(type, amount, bytes(hash160.data(), hash160.data() + hash160.data_size()), front);
} }
} }
void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const bytes& script_code, bool front ) void bitcoin_transaction_builder::add_out(payment_type type, int64_t amount, const bytes &script_code, bool front) {
{
tx_out out; tx_out out;
out.value = amount; out.value = amount;
out.scriptPubKey = get_script_pubkey( type, script_code ); out.scriptPubKey = get_script_pubkey(type, script_code);
if( front ) { if (front) {
tx.vout.insert( tx.vout.begin(), out ); tx.vout.insert(tx.vout.begin(), out);
} else { } else {
tx.vout.push_back( out ); tx.vout.push_back(out);
} }
} }
void bitcoin_transaction_builder::add_out_all_type( const uint64_t& amount, const bitcoin_address& address, bool front ) void bitcoin_transaction_builder::add_out_all_type(const uint64_t &amount, const bitcoin_address &address, bool front) {
{ switch (address.get_type()) {
switch( address.get_type() ) { case payment_type::P2PK: {
case payment_type::P2PK: { bytes raw_address(address.get_raw_address());
bytes raw_address( address.get_raw_address() ); fc::ecc::public_key_data public_key;
fc::ecc::public_key_data public_key; std::copy(raw_address.begin(), raw_address.end(), public_key.begin());
std::copy( raw_address.begin(), raw_address.end(), public_key.begin() ); add_out(address.get_type(), amount, public_key, front);
add_out( address.get_type(), amount, public_key, front ); break;
break; }
} case payment_type::P2PKH:
case payment_type::P2PKH: case payment_type::P2SH:
case payment_type::P2SH: case payment_type::P2SH_WPKH:
case payment_type::P2SH_WPKH: case payment_type::P2SH_WSH: {
case payment_type::P2SH_WSH: { add_out(address.get_type(), amount, address.get_address(), front);
add_out( address.get_type(), amount, address.get_address(), front ); break;
break; }
} case payment_type::P2WPKH:
case payment_type::P2WPKH: case payment_type::P2WSH: {
case payment_type::P2WSH: { add_out(address.get_type(), amount, address.get_raw_address(), front);
add_out( address.get_type(), amount, address.get_raw_address(), front ); break;
break; }
} default:
default: break;
break;
} }
} }
inline bool bitcoin_transaction_builder::is_payment_to_pubkey( payment_type type ) inline bool bitcoin_transaction_builder::is_payment_to_pubkey(payment_type type) {
{ switch (type) {
switch ( type ) {
case payment_type::P2PK: case payment_type::P2PK:
case payment_type::P2PKH: case payment_type::P2PKH:
case payment_type::P2WPKH: case payment_type::P2WPKH:
@ -257,25 +231,24 @@ inline bool bitcoin_transaction_builder::is_payment_to_pubkey( payment_type type
} }
} }
bytes bitcoin_transaction_builder::get_script_pubkey( payment_type type, const bytes& script_code ) bytes bitcoin_transaction_builder::get_script_pubkey(payment_type type, const bytes &script_code) {
{ switch (type) {
switch ( type ) { case payment_type::NULLDATA:
case payment_type::NULLDATA: return script_builder() << op::RETURN << script_code;
return script_builder() << op::RETURN << script_code; case payment_type::P2PK:
case payment_type::P2PK: return script_builder() << script_code << op::CHECKSIG;
return script_builder() << script_code << op::CHECKSIG; case payment_type::P2PKH:
case payment_type::P2PKH: return script_builder() << op::DUP << op::HASH160 << script_code << op::EQUALVERIFY << op::CHECKSIG;
return script_builder() << op::DUP << op::HASH160 << script_code << op::EQUALVERIFY << op::CHECKSIG; case payment_type::P2SH:
case payment_type::P2SH: case payment_type::P2SH_WPKH:
case payment_type::P2SH_WPKH: case payment_type::P2SH_WSH:
case payment_type::P2SH_WSH: return script_builder() << op::HASH160 << script_code << op::EQUAL;
return script_builder() << op::HASH160 << script_code << op::EQUAL; case payment_type::P2WPKH:
case payment_type::P2WPKH: case payment_type::P2WSH:
case payment_type::P2WSH: return script_builder() << op::_0 << script_code;
return script_builder() << op::_0 << script_code; default:
default: return script_code;
return script_code; }
}
} }
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -19,63 +19,64 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include <graphene/peerplays_sidechain/bitcoin/segwit_addr.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bech32.hpp> #include <graphene/peerplays_sidechain/bitcoin/bech32.hpp>
#include <graphene/peerplays_sidechain/bitcoin/segwit_addr.hpp>
namespace namespace {
{
typedef std::vector<uint8_t> data; typedef std::vector<uint8_t> data;
/** Convert from one power-of-2 number base to another. */ /** Convert from one power-of-2 number base to another. */
template<int frombits, int tobits, bool pad> template <int frombits, int tobits, bool pad>
bool convertbits(data& out, const data& in) { bool convertbits(data &out, const data &in) {
int acc = 0; int acc = 0;
int bits = 0; int bits = 0;
const int maxv = (1 << tobits) - 1; const int maxv = (1 << tobits) - 1;
const int max_acc = (1 << (frombits + tobits - 1)) - 1; const int max_acc = (1 << (frombits + tobits - 1)) - 1;
for (size_t i = 0; i < in.size(); ++i) { for (size_t i = 0; i < in.size(); ++i) {
int value = in[i]; int value = in[i];
acc = ((acc << frombits) | value) & max_acc; acc = ((acc << frombits) | value) & max_acc;
bits += frombits; bits += frombits;
while (bits >= tobits) { while (bits >= tobits) {
bits -= tobits; bits -= tobits;
out.push_back((acc >> bits) & maxv); out.push_back((acc >> bits) & maxv);
} }
} }
if (pad) { if (pad) {
if (bits) out.push_back((acc << (tobits - bits)) & maxv); if (bits)
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { out.push_back((acc << (tobits - bits)) & maxv);
return false; } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
} return false;
return true; }
return true;
} }
} } // namespace
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace segwit_addr { namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace segwit_addr {
/** Decode a SegWit address. */ /** Decode a SegWit address. */
std::pair<int, data> decode(const std::string& hrp, const std::string& addr) { std::pair<int, data> decode(const std::string &hrp, const std::string &addr) {
std::pair<std::string, data> dec = bech32::Decode(addr); std::pair<std::string, data> dec = bech32::Decode(addr);
if (dec.first != hrp || dec.second.size() < 1) return std::make_pair(-1, data()); if (dec.first != hrp || dec.second.size() < 1)
data conv; return std::make_pair(-1, data());
if (!convertbits<5, 8, false>(conv, data(dec.second.begin() + 1, dec.second.end())) || data conv;
conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 || (dec.second[0] == 0 && if (!convertbits<5, 8, false>(conv, data(dec.second.begin() + 1, dec.second.end())) ||
conv.size() != 20 && conv.size() != 32)) { conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 || (dec.second[0] == 0 && conv.size() != 20 && conv.size() != 32)) {
return std::make_pair(-1, data()); return std::make_pair(-1, data());
} }
return std::make_pair(dec.second[0], conv); return std::make_pair(dec.second[0], conv);
} }
/** Encode a SegWit address. */ /** Encode a SegWit address. */
std::string encode(const std::string& hrp, int witver, const data& witprog) { std::string encode(const std::string &hrp, int witver, const data &witprog) {
data enc; data enc;
enc.push_back(witver); enc.push_back(witver);
convertbits<8, 5, true>(enc, witprog); convertbits<8, 5, true>(enc, witprog);
std::string ret = bech32::Encode(hrp, enc); std::string ret = bech32::Encode(hrp, enc);
if (decode(hrp, ret).first == -1) return ""; if (decode(hrp, ret).first == -1)
return ret; return "";
return ret;
} }
} } } } }}}} // namespace graphene::peerplays_sidechain::bitcoin::segwit_addr

View file

@ -1,136 +1,130 @@
#include <graphene/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.hpp>
#include <graphene/peerplays_sidechain/bitcoin/serialize.hpp> #include <graphene/peerplays_sidechain/bitcoin/serialize.hpp>
#include <graphene/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.hpp>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
const secp256k1_context_t *btc_context() const secp256k1_context_t *btc_context() {
{
static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
return ctx; return ctx;
} }
fc::sha256 get_signature_hash( const bitcoin_transaction& tx, const bytes& scriptCode, int64_t amount, fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &scriptCode, int64_t amount,
size_t in_index, int hash_type, bool is_witness ) size_t in_index, int hash_type, bool is_witness) {
{
fc::datastream<size_t> ps; fc::datastream<size_t> ps;
if ( is_witness ) if (is_witness)
pack_tx_witness_signature( ps, scriptCode, tx, in_index, amount, hash_type ); pack_tx_witness_signature(ps, scriptCode, tx, in_index, amount, hash_type);
else else
pack_tx_signature( ps, scriptCode, tx, in_index, hash_type ); pack_tx_signature(ps, scriptCode, tx, in_index, hash_type);
std::vector<char> vec( ps.tellp() ); std::vector<char> vec(ps.tellp());
if ( !vec.empty() ) { if (!vec.empty()) {
fc::datastream<char*> ds( vec.data(), vec.size() ); fc::datastream<char *> ds(vec.data(), vec.size());
if ( is_witness ) if (is_witness)
pack_tx_witness_signature( ds, scriptCode, tx, in_index, amount, hash_type ); pack_tx_witness_signature(ds, scriptCode, tx, in_index, amount, hash_type);
else else
pack_tx_signature( ds, scriptCode, tx, in_index, hash_type ); pack_tx_signature(ds, scriptCode, tx, in_index, hash_type);
} }
return fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); return fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
} }
std::vector<char> privkey_sign( const bytes& privkey, const fc::sha256 &hash, const secp256k1_context_t* context_sign ) std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context_t *context_sign) {
{
bytes sig; bytes sig;
sig.resize( 72 ); sig.resize(72);
int sig_len = sig.size(); int sig_len = sig.size();
FC_ASSERT( secp256k1_ecdsa_sign( FC_ASSERT(secp256k1_ecdsa_sign(
context_sign, context_sign,
reinterpret_cast<unsigned char*>( hash.data() ), reinterpret_cast<unsigned char *>(hash.data()),
reinterpret_cast<unsigned char*>( sig.data() ), reinterpret_cast<unsigned char *>(sig.data()),
&sig_len, &sig_len,
reinterpret_cast<const unsigned char*>( privkey.data() ), reinterpret_cast<const unsigned char *>(privkey.data()),
secp256k1_nonce_function_rfc6979, secp256k1_nonce_function_rfc6979,
nullptr ) ); // TODO: replace assert with exception nullptr)); // TODO: replace assert with exception
sig.resize( sig_len ); sig.resize(sig_len);
return sig; return sig;
} }
std::vector<bytes> sign_witness_transaction_part( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts, std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t>& amounts, const bytes& privkey, const std::vector<uint64_t> &amounts, const bytes &privkey,
const secp256k1_context_t* context_sign, int hash_type ) const secp256k1_context_t *context_sign, int hash_type) {
{ FC_ASSERT(tx.vin.size() == redeem_scripts.size() && tx.vin.size() == amounts.size());
FC_ASSERT( tx.vin.size() == redeem_scripts.size() && tx.vin.size() == amounts.size() ); FC_ASSERT(!privkey.empty());
FC_ASSERT( !privkey.empty() );
std::vector< bytes > signatures; std::vector<bytes> signatures;
for( size_t i = 0; i < tx.vin.size(); i++ ) { for (size_t i = 0; i < tx.vin.size(); i++) {
const auto sighash = get_signature_hash( tx, redeem_scripts[i], static_cast<int64_t>( amounts[i] ), i, hash_type, true ); const auto sighash = get_signature_hash(tx, redeem_scripts[i], static_cast<int64_t>(amounts[i]), i, hash_type, true);
auto sig = privkey_sign( privkey, sighash, context_sign ); auto sig = privkey_sign(privkey, sighash, context_sign);
sig.push_back( static_cast<uint8_t>( hash_type ) ); sig.push_back(static_cast<uint8_t>(hash_type));
signatures.push_back( sig ); signatures.push_back(sig);
} }
return signatures; return signatures;
} }
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts, bool use_mulisig_workaround ) void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts, bool use_mulisig_workaround) {
{ FC_ASSERT(tx.vin.size() == redeem_scripts.size());
FC_ASSERT( tx.vin.size() == redeem_scripts.size() );
for( size_t i = 0; i < tx.vin.size(); i++ ) { for (size_t i = 0; i < tx.vin.size(); i++) {
if (use_mulisig_workaround) if (use_mulisig_workaround)
tx.vin[i].scriptWitness.insert( tx.vin[i].scriptWitness.begin(), bytes() ); // Bitcoin workaround CHECKMULTISIG bug tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), bytes()); // Bitcoin workaround CHECKMULTISIG bug
tx.vin[i].scriptWitness.push_back( redeem_scripts[i] ); tx.vin[i].scriptWitness.push_back(redeem_scripts[i]);
} }
} }
bool verify_sig( const bytes& sig, const bytes& pubkey, const bytes& msg, const secp256k1_context_t* context ) bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context_t *context) {
{ std::vector<unsigned char> sig_temp(sig.begin(), sig.end());
std::vector<unsigned char> sig_temp( sig.begin(), sig.end() ); std::vector<unsigned char> pubkey_temp(pubkey.begin(), pubkey.end());
std::vector<unsigned char> pubkey_temp( pubkey.begin(), pubkey.end() ); std::vector<unsigned char> msg_temp(msg.begin(), msg.end());
std::vector<unsigned char> msg_temp( msg.begin(), msg.end() );
int result = secp256k1_ecdsa_verify( context, msg_temp.data(), sig_temp.data(), sig_temp.size(), pubkey_temp.data(), pubkey_temp.size() ); int result = secp256k1_ecdsa_verify(context, msg_temp.data(), sig_temp.data(), sig_temp.size(), pubkey_temp.data(), pubkey_temp.size());
return result == 1; return result == 1;
} }
std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts, std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t>& amounts, const secp256k1_context_t* context ) const std::vector<uint64_t> &amounts, const secp256k1_context_t *context) {
{ FC_ASSERT(redeem_scripts.size() == amounts.size());
FC_ASSERT( redeem_scripts.size() == amounts.size() );
using data = std::pair<size_t, bytes>; using data = std::pair<size_t, bytes>;
struct comp { struct comp {
bool operator() (const data& lhs, const data& rhs) const { return lhs.first < rhs.first; } bool operator()(const data &lhs, const data &rhs) const {
return lhs.first < rhs.first;
}
}; };
std::vector<std::vector<bytes>> new_stacks; std::vector<std::vector<bytes>> new_stacks;
for( size_t i = 0; i < redeem_scripts.size(); i++ ) { for (size_t i = 0; i < redeem_scripts.size(); i++) {
const std::vector<bytes>& keys = get_pubkey_from_redeemScript( redeem_scripts[i] ); const std::vector<bytes> &keys = get_pubkey_from_redeemScript(redeem_scripts[i]);
const auto& sighash = get_signature_hash( tx, redeem_scripts[i], static_cast<int64_t>( amounts[i] ), i, 1, true ).str(); const auto &sighash = get_signature_hash(tx, redeem_scripts[i], static_cast<int64_t>(amounts[i]), i, 1, true).str();
bytes sighash_temp( parse_hex( sighash ) ); bytes sighash_temp(parse_hex(sighash));
std::vector<bytes> stack( tx.vin[i].scriptWitness ); std::vector<bytes> stack(tx.vin[i].scriptWitness);
std::vector<bool> marker( tx.vin[i].scriptWitness.size(), false ); std::vector<bool> marker(tx.vin[i].scriptWitness.size(), false);
std::set<data, comp> sigs; std::set<data, comp> sigs;
for( size_t j = 0; j < keys.size(); j++ ) { for (size_t j = 0; j < keys.size(); j++) {
for( size_t l = 0; l < stack.size(); l++ ) { for (size_t l = 0; l < stack.size(); l++) {
if( !verify_sig( stack[l], keys[j], sighash_temp, context ) || marker[l] ) if (!verify_sig(stack[l], keys[j], sighash_temp, context) || marker[l])
continue; continue;
sigs.insert(std::make_pair(j, stack[l])); sigs.insert(std::make_pair(j, stack[l]));
marker[l] = true; marker[l] = true;
break; break;
} }
} }
std::vector<bytes> temp_sig; std::vector<bytes> temp_sig;
for( auto s : sigs ) { for (auto s : sigs) {
temp_sig.push_back( s.second ); temp_sig.push_back(s.second);
} }
new_stacks.push_back( temp_sig ); new_stacks.push_back(temp_sig);
} }
return new_stacks; return new_stacks;
} }
void add_signatures_to_transaction_multisig( bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set ) void add_signatures_to_transaction_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set) {
{
for (unsigned int i = 0; i < signature_set.size(); i++) { for (unsigned int i = 0; i < signature_set.size(); i++) {
std::vector<bytes> signatures = signature_set[i]; std::vector<bytes> signatures = signature_set[i];
FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number"); FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number");
@ -139,8 +133,7 @@ void add_signatures_to_transaction_multisig( bitcoin_transaction &tx, std::vecto
} }
} }
void add_signatures_to_transaction_weighted_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set) void add_signatures_to_transaction_weighted_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set) {
{
for (unsigned int i = 0; i < signature_set.size(); i++) { for (unsigned int i = 0; i < signature_set.size(); i++) {
std::vector<bytes> signatures = signature_set[i]; std::vector<bytes> signatures = signature_set[i];
FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number"); FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number");
@ -150,4 +143,4 @@ void add_signatures_to_transaction_weighted_multisig(bitcoin_transaction &tx, st
} }
} }
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

51
libraries/plugins/peerplays_sidechain/bitcoin/utils.cpp Executable file → Normal file
View file

@ -1,53 +1,48 @@
#include <graphene/peerplays_sidechain/bitcoin/utils.hpp>
#include <fc/crypto/base58.hpp> #include <fc/crypto/base58.hpp>
#include <graphene/peerplays_sidechain/bitcoin/utils.hpp>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
fc::ecc::public_key_data create_public_key_data( const std::vector<char>& public_key ) fc::ecc::public_key_data create_public_key_data(const std::vector<char> &public_key) {
{ FC_ASSERT(public_key.size() == 33);
FC_ASSERT( public_key.size() == 33 );
fc::ecc::public_key_data key; fc::ecc::public_key_data key;
for(size_t i = 0; i < 33; i++) { for (size_t i = 0; i < 33; i++) {
key.at(i) = public_key[i]; key.at(i) = public_key[i];
} }
return key; return key;
} }
bytes get_privkey_bytes( const std::string& privkey_base58 ) bytes get_privkey_bytes(const std::string &privkey_base58) {
{ const auto privkey = fc::from_base58(privkey_base58);
const auto privkey = fc::from_base58( privkey_base58 );
// Remove version and hash // Remove version and hash
return bytes( privkey.cbegin() + 1, privkey.cbegin() + 1 + 32 ); return bytes(privkey.cbegin() + 1, privkey.cbegin() + 1 + 32);
} }
bytes parse_hex( const std::string& str ) bytes parse_hex(const std::string &str) {
{ bytes vec(str.size() / 2);
bytes vec( str.size() / 2 ); fc::from_hex(str, vec.data(), vec.size());
fc::from_hex( str, vec.data(), vec.size() ); return vec;
return vec;
} }
std::vector<bytes> get_pubkey_from_redeemScript( bytes script ) std::vector<bytes> get_pubkey_from_redeemScript(bytes script) {
{ FC_ASSERT(script.size() >= 37);
FC_ASSERT( script.size() >= 37 );
script.erase( script.begin() ); script.erase(script.begin());
script.erase( script.end() - 2, script.end() ); script.erase(script.end() - 2, script.end());
std::vector<bytes> result; std::vector<bytes> result;
uint64_t count = script.size() / 34; uint64_t count = script.size() / 34;
for( size_t i = 0; i < count; i++ ) { for (size_t i = 0; i < count; i++) {
result.push_back( bytes( script.begin() + (34 * i) + 1, script.begin() + (34 * (i + 1)) ) ); result.push_back(bytes(script.begin() + (34 * i) + 1, script.begin() + (34 * (i + 1))));
} }
return result; return result;
} }
bytes public_key_data_to_bytes( const fc::ecc::public_key_data& key ) bytes public_key_data_to_bytes(const fc::ecc::public_key_data &key) {
{ bytes result;
bytes result; result.resize(key.size());
result.resize( key.size() ); std::copy(key.begin(), key.end(), result.begin());
std::copy( key.begin(), key.end(), result.begin() ); return result;
return result;
} }
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -1,3 +1,4 @@
#include <boost/property_tree/json_parser.hpp>
#include <fc/crypto/base58.hpp> #include <fc/crypto/base58.hpp>
#include <fc/crypto/elliptic.hpp> #include <fc/crypto/elliptic.hpp>
#include <fc/crypto/ripemd160.hpp> #include <fc/crypto/ripemd160.hpp>
@ -5,7 +6,6 @@
#include <fc/io/raw.hpp> #include <fc/io/raw.hpp>
#include <graphene/peerplays_sidechain/bitcoin_utils.hpp> #include <graphene/peerplays_sidechain/bitcoin_utils.hpp>
#include <secp256k1.h> #include <secp256k1.h>
#include <boost/property_tree/json_parser.hpp>
namespace graphene { namespace peerplays_sidechain { namespace graphene { namespace peerplays_sidechain {

View file

@ -16,9 +16,9 @@
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace bech32 { namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace bech32 {
/** Encode a Bech32 string. Returns the empty string in case of failure. */ /** Encode a Bech32 string. Returns the empty string in case of failure. */
std::string Encode(const std::string& hrp, const std::vector<uint8_t>& values); std::string Encode(const std::string &hrp, const std::vector<uint8_t> &values);
/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */ /** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
std::pair<std::string, std::vector<uint8_t>> Decode(const std::string& str); std::pair<std::string, std::vector<uint8_t>> Decode(const std::string &str);
} } } } // namespace sidechain::bech32 }}}} // namespace graphene::peerplays_sidechain::bitcoin::bech32

View file

@ -7,10 +7,9 @@ using namespace graphene::chain;
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
const bytes op_num = {0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f}; // OP_1 - OP_15 const bytes op_num = {0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; // OP_1 - OP_15
class bitcoin_address class bitcoin_address {
{
public: public:
enum network { enum network {
@ -21,31 +20,42 @@ public:
bitcoin_address() = default; bitcoin_address() = default;
bitcoin_address( const std::string& addr, network ntype = network::regtest ) : address( addr ), type( determine_type() ), bitcoin_address(const std::string &addr, network ntype = network::regtest) :
raw_address( determine_raw_address() ), network_type(ntype) {} address(addr),
type(determine_type()),
raw_address(determine_raw_address()),
network_type(ntype) {
}
bool operator==( const bitcoin_address& btc_addr ) const; bool operator==(const bitcoin_address &btc_addr) const;
payment_type get_type() const { return type; } payment_type get_type() const {
return type;
}
std::string get_address() const { return address; } std::string get_address() const {
return address;
}
bytes get_raw_address() const { return raw_address; } bytes get_raw_address() const {
return raw_address;
}
bytes get_script() const; bytes get_script() const;
network get_network_type() const { network get_network_type() const {
return network_type; return network_type;
} }
private:
enum size_segwit_address { P2WSH = 32, P2WPKH = 20 }; private:
enum size_segwit_address { P2WSH = 32,
P2WPKH = 20 };
payment_type determine_type(); payment_type determine_type();
bytes determine_raw_address(); bytes determine_raw_address();
bool check_segwit_address( const size_segwit_address& size ) const; bool check_segwit_address(const size_segwit_address &size) const;
bool is_p2pk() const; bool is_p2pk() const;
@ -58,7 +68,6 @@ private:
bool is_p2sh() const; bool is_p2sh() const;
public: public:
std::string address; std::string address;
payment_type type; payment_type type;
@ -66,87 +75,87 @@ public:
bytes raw_address; bytes raw_address;
network network_type; network network_type;
}; };
class btc_multisig_address : public bitcoin_address class btc_multisig_address : public bitcoin_address {
{
public: public:
btc_multisig_address() = default; btc_multisig_address() = default;
btc_multisig_address( const size_t n_required, const accounts_keys& keys ); btc_multisig_address(const size_t n_required, const accounts_keys &keys);
size_t count_intersection( const accounts_keys& keys ) const; size_t count_intersection(const accounts_keys &keys) const;
bytes get_redeem_script() const { return redeem_script; } bytes get_redeem_script() const {
return redeem_script;
}
private: private:
void create_redeem_script(); void create_redeem_script();
void create_address(); void create_address();
public: public:
enum address_types { MAINNET_SCRIPT = 5,
TESTNET_SCRIPT = 196 };
enum address_types { MAINNET_SCRIPT = 5, TESTNET_SCRIPT = 196 }; enum { OP_0 = 0x00,
OP_EQUAL = 0x87,
enum { OP_0 = 0x00, OP_EQUAL = 0x87, OP_HASH160 = 0xa9, OP_CHECKMULTISIG = 0xae }; OP_HASH160 = 0xa9,
OP_CHECKMULTISIG = 0xae };
bytes redeem_script; bytes redeem_script;
size_t keys_required = 0; size_t keys_required = 0;
accounts_keys witnesses_keys; accounts_keys witnesses_keys;
}; };
// multisig segwit address (P2WSH) // multisig segwit address (P2WSH)
// https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa // https://0bin.net/paste/nfnSf0HcBqBUGDto#7zJMRUhGEBkyh-eASQPEwKfNHgQ4D5KrUJRsk8MTPSa
class btc_multisig_segwit_address : public btc_multisig_address class btc_multisig_segwit_address : public btc_multisig_address {
{
public: public:
btc_multisig_segwit_address() = default; btc_multisig_segwit_address() = default;
btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ); btc_multisig_segwit_address(const size_t n_required, const accounts_keys &keys);
bool operator==( const btc_multisig_segwit_address& addr ) const; bool operator==(const btc_multisig_segwit_address &addr) const;
bytes get_witness_script() const { return witness_script; } bytes get_witness_script() const {
return witness_script;
}
std::vector<public_key_type> get_keys(); std::vector<public_key_type> get_keys();
private: private:
void create_witness_script(); void create_witness_script();
void create_segwit_address(); void create_segwit_address();
bytes get_address_bytes( const bytes& script_hash ); bytes get_address_bytes(const bytes &script_hash);
public: public:
bytes witness_script; bytes witness_script;
}; };
class btc_weighted_multisig_address : public bitcoin_address class btc_weighted_multisig_address : public bitcoin_address {
{
public: public:
btc_weighted_multisig_address() = default; btc_weighted_multisig_address() = default;
btc_weighted_multisig_address( const std::vector<std::pair<fc::ecc::public_key, uint16_t>>& keys_data, btc_weighted_multisig_address(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
network network_type = network::regtest); network network_type = network::regtest);
bytes get_redeem_script() const {
return redeem_script_;
}
bytes get_witness_script() const {
return witness_script_;
}
bytes get_redeem_script() const { return redeem_script_; }
bytes get_witness_script() const { return witness_script_; }
private: private:
void create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data);
void create_redeem_script(const std::vector<std::pair<fc::ecc::public_key, uint16_t>>& keys_data);
void create_witness_script(); void create_witness_script();
void create_segwit_address(); void create_segwit_address();
@ -166,10 +175,12 @@ public:
bytes get_witness_script() const { bytes get_witness_script() const {
return witness_script_; return witness_script_;
} }
private: private:
void create_redeem_script(const fc::ecc::public_key &user_key_data, const uint8_t nrequired, const std::vector<fc::ecc::public_key> &keys_data); void create_redeem_script(const fc::ecc::public_key &user_key_data, const uint8_t nrequired, const std::vector<fc::ecc::public_key> &keys_data);
void create_witness_script(); void create_witness_script();
void create_segwit_address(); void create_segwit_address();
public: public:
bytes redeem_script_; bytes redeem_script_;
bytes witness_script_; bytes witness_script_;
@ -178,42 +189,41 @@ public:
class btc_one_or_weighted_multisig_address : public bitcoin_address { class btc_one_or_weighted_multisig_address : public bitcoin_address {
public: public:
btc_one_or_weighted_multisig_address() = default; btc_one_or_weighted_multisig_address() = default;
btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>>& keys_data, btc_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
network network_type = network::regtest); network network_type = network::regtest);
bytes get_redeem_script() const { bytes get_redeem_script() const {
return redeem_script_; return redeem_script_;
} }
bytes get_witness_script() const { bytes get_witness_script() const {
return witness_script_; return witness_script_;
} }
private: private:
void create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>>& keys_data); void create_redeem_script(const fc::ecc::public_key &user_key_data, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data);
void create_witness_script(); void create_witness_script();
void create_segwit_address(); void create_segwit_address();
public: public:
bytes redeem_script_; bytes redeem_script_;
bytes witness_script_; bytes witness_script_;
}; };
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin
FC_REFLECT_ENUM(graphene::peerplays_sidechain::bitcoin::bitcoin_address::network, FC_REFLECT_ENUM(graphene::peerplays_sidechain::bitcoin::bitcoin_address::network,
(mainnet) (mainnet)(testnet)(regtest))
(testnet)
(regtest)
)
FC_REFLECT( graphene::peerplays_sidechain::bitcoin::bitcoin_address, (address)(type)(raw_address)(network_type) ); FC_REFLECT(graphene::peerplays_sidechain::bitcoin::bitcoin_address, (address)(type)(raw_address)(network_type));
FC_REFLECT_DERIVED( graphene::peerplays_sidechain::bitcoin::btc_multisig_address, (graphene::peerplays_sidechain::bitcoin::bitcoin_address), FC_REFLECT_DERIVED(graphene::peerplays_sidechain::bitcoin::btc_multisig_address, (graphene::peerplays_sidechain::bitcoin::bitcoin_address),
(redeem_script)(keys_required)(witnesses_keys) ); (redeem_script)(keys_required)(witnesses_keys));
FC_REFLECT_DERIVED( graphene::peerplays_sidechain::bitcoin::btc_multisig_segwit_address, (graphene::peerplays_sidechain::bitcoin::btc_multisig_address), (witness_script) ); FC_REFLECT_DERIVED(graphene::peerplays_sidechain::bitcoin::btc_multisig_segwit_address, (graphene::peerplays_sidechain::bitcoin::btc_multisig_address), (witness_script));
FC_REFLECT_DERIVED( graphene::peerplays_sidechain::bitcoin::btc_weighted_multisig_address, FC_REFLECT_DERIVED(graphene::peerplays_sidechain::bitcoin::btc_weighted_multisig_address,
(graphene::peerplays_sidechain::bitcoin::bitcoin_address), (graphene::peerplays_sidechain::bitcoin::bitcoin_address),
(redeem_script_)(witness_script_) ); (redeem_script_)(witness_script_));
FC_REFLECT_DERIVED( graphene::peerplays_sidechain::bitcoin::btc_one_or_m_of_n_multisig_address, FC_REFLECT_DERIVED(graphene::peerplays_sidechain::bitcoin::btc_one_or_m_of_n_multisig_address,
(graphene::peerplays_sidechain::bitcoin::bitcoin_address), (graphene::peerplays_sidechain::bitcoin::bitcoin_address),
(redeem_script_)(witness_script_) ); (redeem_script_)(witness_script_));

View file

@ -54,27 +54,26 @@ enum class op {
class script_builder { class script_builder {
public: public:
script_builder &operator<<(op opcode);
script_builder& operator<<( op opcode ); script_builder &operator<<(uint32_t number);
script_builder& operator<<( uint32_t number ); script_builder &operator<<(size_t size);
script_builder& operator<<( size_t size ); script_builder &operator<<(const bytes &sc);
script_builder& operator<<( const bytes& sc ); script_builder &operator<<(const fc::sha256 &hash);
script_builder& operator<<( const fc::sha256& hash ); script_builder &operator<<(const fc::ripemd160 &hash);
script_builder& operator<<( const fc::ripemd160& hash ); script_builder &operator<<(const fc::ecc::public_key_data &pubkey_data);
script_builder& operator<<( const fc::ecc::public_key_data& pubkey_data ); operator bytes() const {
return std::move(script);
operator bytes() const { return std::move( script ); } }
private: private:
bytes script; bytes script;
}; };
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -7,13 +7,16 @@ struct out_point {
fc::sha256 hash; fc::sha256 hash;
uint32_t n = 0; uint32_t n = 0;
out_point() = default; out_point() = default;
out_point( fc::sha256 _hash, uint32_t _n ) : hash( _hash ), n( _n ) {} out_point(fc::sha256 _hash, uint32_t _n) :
bool operator==( const out_point& op ) const; hash(_hash),
n(_n) {
}
bool operator==(const out_point &op) const;
}; };
struct tx_in { struct tx_in {
bool operator==( const tx_in& ti ) const; bool operator==(const tx_in &ti) const;
out_point prevout; out_point prevout;
bytes scriptSig; bytes scriptSig;
@ -25,7 +28,7 @@ struct tx_out {
int64_t value = 0; int64_t value = 0;
bytes scriptPubKey; bytes scriptPubKey;
bool operator==( const tx_out& to ) const; bool operator==(const tx_out &to) const;
bool is_p2wsh() const; bool is_p2wsh() const;
@ -42,7 +45,7 @@ struct tx_out {
struct bitcoin_transaction { struct bitcoin_transaction {
bool operator!=( const bitcoin_transaction& bt ) const; bool operator!=(const bitcoin_transaction &bt) const;
int32_t nVersion = 1; int32_t nVersion = 1;
std::vector<tx_in> vin; std::vector<tx_in> vin;
@ -54,47 +57,47 @@ struct bitcoin_transaction {
size_t get_vsize() const; size_t get_vsize() const;
}; };
class bitcoin_transaction_builder class bitcoin_transaction_builder {
{
public: public:
bitcoin_transaction_builder() = default; bitcoin_transaction_builder() = default;
bitcoin_transaction_builder( const bitcoin_transaction _tx ) : tx( _tx ) {} bitcoin_transaction_builder(const bitcoin_transaction _tx) :
tx(_tx) {
}
void set_version( int32_t version ); void set_version(int32_t version);
void set_locktime( uint32_t lock_time ); void set_locktime(uint32_t lock_time);
void add_in( payment_type type, const fc::sha256& txid, uint32_t n_out, void add_in(payment_type type, const fc::sha256 &txid, uint32_t n_out,
const bytes& script_code, bool front = false, uint32_t sequence = 0xffffffff ); const bytes &script_code, bool front = false, uint32_t sequence = 0xffffffff);
void add_in( payment_type type, tx_in txin, const bytes& script_code, bool front = false ); void add_in(payment_type type, tx_in txin, const bytes &script_code, bool front = false);
void add_out( payment_type type, int64_t amount, const std::string& base58_address, bool front = false ); void add_out(payment_type type, int64_t amount, const std::string &base58_address, bool front = false);
void add_out( payment_type type, int64_t amount, const fc::ecc::public_key_data& pubkey, bool front = false ); void add_out(payment_type type, int64_t amount, const fc::ecc::public_key_data &pubkey, bool front = false);
void add_out( payment_type type, int64_t amount, const bytes& script_code, bool front = false ); void add_out(payment_type type, int64_t amount, const bytes &script_code, bool front = false);
void add_out_all_type( const uint64_t& amount, const bitcoin_address& address, bool front = false ); void add_out_all_type(const uint64_t &amount, const bitcoin_address &address, bool front = false);
bitcoin_transaction get_transaction() const { return tx; } bitcoin_transaction get_transaction() const {
return tx;
}
private: private:
inline bool is_payment_to_pubkey(payment_type type);
inline bool is_payment_to_pubkey( payment_type type ); bytes get_script_pubkey(payment_type type, const bytes &script_code);
bytes get_script_pubkey( payment_type type, const bytes& script_code );
bitcoin_transaction tx; bitcoin_transaction tx;
}; };
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin
FC_REFLECT( graphene::peerplays_sidechain::bitcoin::out_point, (hash)(n) ) FC_REFLECT(graphene::peerplays_sidechain::bitcoin::out_point, (hash)(n))
FC_REFLECT( graphene::peerplays_sidechain::bitcoin::tx_in, (prevout)(scriptSig)(nSequence)(scriptWitness) ) FC_REFLECT(graphene::peerplays_sidechain::bitcoin::tx_in, (prevout)(scriptSig)(nSequence)(scriptWitness))
FC_REFLECT( graphene::peerplays_sidechain::bitcoin::tx_out, (value)(scriptPubKey) ) FC_REFLECT(graphene::peerplays_sidechain::bitcoin::tx_out, (value)(scriptPubKey))
FC_REFLECT( graphene::peerplays_sidechain::bitcoin::bitcoin_transaction, (nVersion)(vin)(vout)(nLockTime) ) FC_REFLECT(graphene::peerplays_sidechain::bitcoin::bitcoin_transaction, (nVersion)(vin)(vout)(nLockTime))

View file

@ -20,15 +20,15 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <vector>
#include <string> #include <string>
#include <vector>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace segwit_addr { namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace segwit_addr {
/** Decode a SegWit address. Returns (witver, witprog). witver = -1 means failure. */ /** Decode a SegWit address. Returns (witver, witprog). witver = -1 means failure. */
std::pair<int, std::vector<uint8_t> > decode(const std::string& hrp, const std::string& addr); std::pair<int, std::vector<uint8_t>> decode(const std::string &hrp, const std::string &addr);
/** Encode a SegWit address. Empty string means failure. */ /** Encode a SegWit address. Empty string means failure. */
std::string encode(const std::string& hrp, int witver, const std::vector<uint8_t>& witprog); std::string encode(const std::string &hrp, int witver, const std::vector<uint8_t> &witprog);
} } } } }}}} // namespace graphene::peerplays_sidechain::bitcoin::segwit_addr

View file

@ -1,305 +1,292 @@
#pragma once #pragma once
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp> #include <graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp>
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
inline void write_compact_size( bytes& vec, size_t size ) inline void write_compact_size(bytes &vec, size_t size) {
{
bytes sb; bytes sb;
sb.reserve( 2 ); sb.reserve(2);
if ( size < 253 ) { if (size < 253) {
sb.insert( sb.end(), static_cast<uint8_t>( size ) ); sb.insert(sb.end(), static_cast<uint8_t>(size));
} else if ( size <= std::numeric_limits<unsigned short>::max() ) { } else if (size <= std::numeric_limits<unsigned short>::max()) {
uint16_t tmp = htole16( static_cast<uint16_t>( size ) ); uint16_t tmp = htole16(static_cast<uint16_t>(size));
sb.insert( sb.end(), static_cast<uint8_t>( 253 ) ); sb.insert(sb.end(), static_cast<uint8_t>(253));
sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) ); sb.insert(sb.end(), reinterpret_cast<const char *>(tmp), reinterpret_cast<const char *>(tmp) + sizeof(tmp));
} else if ( size <= std::numeric_limits<unsigned int>::max() ) { } else if (size <= std::numeric_limits<unsigned int>::max()) {
uint32_t tmp = htole32( static_cast<uint32_t>( size ) ); uint32_t tmp = htole32(static_cast<uint32_t>(size));
sb.insert( sb.end(), static_cast<uint8_t>( 254 ) ); sb.insert(sb.end(), static_cast<uint8_t>(254));
sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) ); sb.insert(sb.end(), reinterpret_cast<const char *>(tmp), reinterpret_cast<const char *>(tmp) + sizeof(tmp));
} else { } else {
uint64_t tmp = htole64( static_cast<uint64_t>( size ) ); uint64_t tmp = htole64(static_cast<uint64_t>(size));
sb.insert( sb.end(), static_cast<uint8_t>( 255 ) ); sb.insert(sb.end(), static_cast<uint8_t>(255));
sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) ); sb.insert(sb.end(), reinterpret_cast<const char *>(tmp), reinterpret_cast<const char *>(tmp) + sizeof(tmp));
} }
vec.insert( vec.end(), sb.begin(), sb.end() ); vec.insert(vec.end(), sb.begin(), sb.end());
} }
template<typename Stream> template <typename Stream>
inline void pack_compact_size(Stream& s, size_t size) inline void pack_compact_size(Stream &s, size_t size) {
{ if (size < 253) {
if ( size < 253 ) { fc::raw::pack(s, static_cast<uint8_t>(size));
fc::raw::pack( s, static_cast<uint8_t>( size ) ); } else if (size <= std::numeric_limits<unsigned short>::max()) {
} else if ( size <= std::numeric_limits<unsigned short>::max() ) { fc::raw::pack(s, static_cast<uint8_t>(253));
fc::raw::pack( s, static_cast<uint8_t>( 253 ) ); fc::raw::pack(s, htole16(static_cast<uint16_t>(size)));
fc::raw::pack( s, htole16( static_cast<uint16_t>( size ) ) ); } else if (size <= std::numeric_limits<unsigned int>::max()) {
} else if ( size <= std::numeric_limits<unsigned int>::max() ) { fc::raw::pack(s, static_cast<uint8_t>(254));
fc::raw::pack( s, static_cast<uint8_t>( 254 ) ); fc::raw::pack(s, htole32(static_cast<uint32_t>(size)));
fc::raw::pack( s, htole32(static_cast<uint32_t>( size ) ) );
} else { } else {
fc::raw::pack( s, static_cast<uint8_t>( 255 ) ); fc::raw::pack(s, static_cast<uint8_t>(255));
fc::raw::pack( s, htole64( static_cast<uint64_t>( size ) ) ); fc::raw::pack(s, htole64(static_cast<uint64_t>(size)));
} }
} }
template<typename Stream> template <typename Stream>
inline uint64_t unpack_compact_size( Stream& s ) inline uint64_t unpack_compact_size(Stream &s) {
{
uint8_t size; uint8_t size;
uint64_t size_ret; uint64_t size_ret;
fc::raw::unpack( s, size ); fc::raw::unpack(s, size);
if (size < 253) { if (size < 253) {
size_ret = size; size_ret = size;
} else if ( size == 253 ) { } else if (size == 253) {
uint16_t tmp; uint16_t tmp;
fc::raw::unpack( s, tmp ); fc::raw::unpack(s, tmp);
size_ret = le16toh( tmp ); size_ret = le16toh(tmp);
if ( size_ret < 253 ) if (size_ret < 253)
FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); FC_THROW_EXCEPTION(fc::parse_error_exception, "non-canonical unpack_compact_size()");
} else if ( size == 254 ) { } else if (size == 254) {
uint32_t tmp; uint32_t tmp;
fc::raw::unpack( s, tmp ); fc::raw::unpack(s, tmp);
size_ret = le32toh( tmp ); size_ret = le32toh(tmp);
if ( size_ret < 0x10000u ) if (size_ret < 0x10000u)
FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); FC_THROW_EXCEPTION(fc::parse_error_exception, "non-canonical unpack_compact_size()");
} else { } else {
uint32_t tmp; uint32_t tmp;
fc::raw::unpack( s, tmp ); fc::raw::unpack(s, tmp);
size_ret = le64toh( tmp ); size_ret = le64toh(tmp);
if ( size_ret < 0x100000000ULL ) if (size_ret < 0x100000000ULL)
FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); FC_THROW_EXCEPTION(fc::parse_error_exception, "non-canonical unpack_compact_size()");
} }
if ( size_ret > 0x08000000 ) if (size_ret > 0x08000000)
FC_THROW_EXCEPTION( fc::parse_error_exception, "unpack_compact_size(): size too large" ); FC_THROW_EXCEPTION(fc::parse_error_exception, "unpack_compact_size(): size too large");
return size_ret; return size_ret;
} }
template <typename Stream>
template<typename Stream> inline void unpack(Stream &s, int64_t &u, uint32_t _max_depth = FC_PACK_MAX_DEPTH) {
inline void unpack( Stream& s, int64_t& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { s.read( (char*)&u, sizeof(u) ); } s.read((char *)&u, sizeof(u));
template<typename Stream>
inline void unpack( Stream& s, int32_t& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { s.read( (char*)&u, sizeof(u) ); }
template<typename Stream>
inline void pack( Stream& s, const std::vector<char>& v )
{
pack_compact_size( s, v.size() );
if ( !v.empty() )
s.write( v.data(), v.size() );
} }
template<typename Stream> template <typename Stream>
inline void unpack( Stream& s, std::vector<char>& v ) inline void unpack(Stream &s, int32_t &u, uint32_t _max_depth = FC_PACK_MAX_DEPTH) {
{ s.read((char *)&u, sizeof(u));
const auto size = unpack_compact_size( s );
v.resize( size );
if ( size )
s.read( v.data(), size );
} }
template<typename Stream, typename T> template <typename Stream>
inline void pack( Stream& s, const T& val ) inline void pack(Stream &s, const std::vector<char> &v) {
{ pack_compact_size(s, v.size());
fc::raw::pack( s, val ); if (!v.empty())
s.write(v.data(), v.size());
} }
template<typename Stream, typename T> template <typename Stream>
inline void unpack( Stream& s, T& val ) inline void unpack(Stream &s, std::vector<char> &v) {
{ const auto size = unpack_compact_size(s);
fc::raw::unpack( s, val ); v.resize(size);
if (size)
s.read(v.data(), size);
} }
template<typename Stream> template <typename Stream, typename T>
inline void pack( Stream& s, const out_point& op ) inline void pack(Stream &s, const T &val) {
{ fc::raw::pack(s, val);
fc::sha256 reversed( op.hash );
std::reverse( reversed.data(), reversed.data() + reversed.data_size() );
s.write( reversed.data(), reversed.data_size() );
pack( s, op.n );
} }
template<typename Stream> template <typename Stream, typename T>
inline void unpack( Stream& s, out_point& op ) inline void unpack(Stream &s, T &val) {
{ fc::raw::unpack(s, val);
}
template <typename Stream>
inline void pack(Stream &s, const out_point &op) {
fc::sha256 reversed(op.hash);
std::reverse(reversed.data(), reversed.data() + reversed.data_size());
s.write(reversed.data(), reversed.data_size());
pack(s, op.n);
}
template <typename Stream>
inline void unpack(Stream &s, out_point &op) {
uint64_t hash_size = op.hash.data_size(); uint64_t hash_size = op.hash.data_size();
std::unique_ptr<char[]> hash_data( new char[hash_size] ); std::unique_ptr<char[]> hash_data(new char[hash_size]);
s.read( hash_data.get(), hash_size ); s.read(hash_data.get(), hash_size);
std::reverse( hash_data.get(), hash_data.get() + hash_size ); std::reverse(hash_data.get(), hash_data.get() + hash_size);
op.hash = fc::sha256( hash_data.get(), hash_size ); op.hash = fc::sha256(hash_data.get(), hash_size);
unpack( s, op.n ); unpack(s, op.n);
} }
template<typename Stream> template <typename Stream>
inline void pack( Stream& s, const tx_in& in ) inline void pack(Stream &s, const tx_in &in) {
{ pack(s, in.prevout);
pack( s, in.prevout ); pack(s, in.scriptSig);
pack( s, in.scriptSig ); pack(s, in.nSequence);
pack( s, in.nSequence );
} }
template<typename Stream> template <typename Stream>
inline void unpack( Stream& s, tx_in& in ) inline void unpack(Stream &s, tx_in &in) {
{ unpack(s, in.prevout);
unpack( s, in.prevout ); unpack(s, in.scriptSig);
unpack( s, in.scriptSig ); unpack(s, in.nSequence);
unpack( s, in.nSequence );
} }
template<typename Stream> template <typename Stream>
inline void pack( Stream& s, const tx_out& out ) inline void pack(Stream &s, const tx_out &out) {
{ pack(s, out.value);
pack( s, out.value ); pack(s, out.scriptPubKey);
pack( s, out.scriptPubKey );
} }
template<typename Stream> template <typename Stream>
inline void unpack( Stream& s, tx_out& out ) inline void unpack(Stream &s, tx_out &out) {
{ unpack(s, out.value);
unpack( s, out.value ); unpack(s, out.scriptPubKey);
unpack( s, out.scriptPubKey );
} }
template<typename Stream> template <typename Stream>
inline void pack( Stream& s, const bitcoin_transaction& tx, bool with_witness = true ) inline void pack(Stream &s, const bitcoin_transaction &tx, bool with_witness = true) {
{
uint8_t flags = 0; uint8_t flags = 0;
if ( with_witness ) { if (with_witness) {
for ( const auto& in : tx.vin ) { for (const auto &in : tx.vin) {
if ( !in.scriptWitness.empty() ) { if (!in.scriptWitness.empty()) {
flags |= 1; flags |= 1;
break; break;
} }
} }
} }
pack( s, tx.nVersion ); pack(s, tx.nVersion);
if ( flags ) { if (flags) {
pack_compact_size( s, 0 ); pack_compact_size(s, 0);
pack( s, flags ); pack(s, flags);
} }
pack_compact_size( s, tx.vin.size() ); pack_compact_size(s, tx.vin.size());
for ( const auto& in : tx.vin ) for (const auto &in : tx.vin)
pack( s, in ); pack(s, in);
pack_compact_size( s, tx.vout.size() ); pack_compact_size(s, tx.vout.size());
for ( const auto& out : tx.vout ) for (const auto &out : tx.vout)
pack( s, out ); pack(s, out);
if ( flags & 1 ) { if (flags & 1) {
for ( const auto in : tx.vin ) { for (const auto in : tx.vin) {
pack_compact_size( s, in.scriptWitness.size() ); pack_compact_size(s, in.scriptWitness.size());
for ( const auto& sc : in.scriptWitness ) for (const auto &sc : in.scriptWitness)
pack( s, sc ); pack(s, sc);
} }
} }
pack( s, tx.nLockTime ); pack(s, tx.nLockTime);
} }
template<typename Stream> template <typename Stream>
inline void unpack( Stream& s, bitcoin_transaction& tx ) inline void unpack(Stream &s, bitcoin_transaction &tx) {
{
uint8_t flags = 0; uint8_t flags = 0;
unpack( s, tx.nVersion ); unpack(s, tx.nVersion);
auto vin_size = unpack_compact_size( s ); auto vin_size = unpack_compact_size(s);
if ( vin_size == 0 ) { if (vin_size == 0) {
unpack( s, flags ); unpack(s, flags);
vin_size = unpack_compact_size( s ); vin_size = unpack_compact_size(s);
} }
tx.vin.reserve( vin_size ); tx.vin.reserve(vin_size);
for ( size_t i = 0; i < vin_size; i++ ) { for (size_t i = 0; i < vin_size; i++) {
tx_in in; tx_in in;
unpack( s, in ); unpack(s, in);
tx.vin.push_back( in ); tx.vin.push_back(in);
} }
const auto vout_size = unpack_compact_size( s ); const auto vout_size = unpack_compact_size(s);
tx.vout.reserve( vout_size ); tx.vout.reserve(vout_size);
for ( size_t i = 0; i < vout_size; i++ ) { for (size_t i = 0; i < vout_size; i++) {
tx_out out; tx_out out;
unpack( s, out ); unpack(s, out);
tx.vout.push_back( out ); tx.vout.push_back(out);
} }
if ( flags & 1 ) { if (flags & 1) {
for ( auto& in : tx.vin ) { for (auto &in : tx.vin) {
uint64_t stack_size = unpack_compact_size( s ); uint64_t stack_size = unpack_compact_size(s);
in.scriptWitness.reserve( stack_size ); in.scriptWitness.reserve(stack_size);
for ( uint64_t i = 0; i < stack_size; i++ ) { for (uint64_t i = 0; i < stack_size; i++) {
std::vector<char> script; std::vector<char> script;
unpack( s, script ); unpack(s, script);
in.scriptWitness.push_back( script ); in.scriptWitness.push_back(script);
} }
} }
} }
unpack( s, tx.nLockTime ); unpack(s, tx.nLockTime);
} }
inline std::vector<char> pack( const bitcoin_transaction& v, bool with_witness = true ) inline std::vector<char> pack(const bitcoin_transaction &v, bool with_witness = true) {
{
fc::datastream<size_t> ps; fc::datastream<size_t> ps;
pack( ps, v, with_witness ); pack(ps, v, with_witness);
std::vector<char> vec( ps.tellp() ); std::vector<char> vec(ps.tellp());
if( !vec.empty() ) { if (!vec.empty()) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); fc::datastream<char *> ds(vec.data(), size_t(vec.size()));
pack( ds, v, with_witness ); pack(ds, v, with_witness);
} }
return vec; return vec;
} }
inline bitcoin_transaction unpack( const std::vector<char>& s ) inline bitcoin_transaction unpack(const std::vector<char> &s) {
{ try { try {
bitcoin_transaction tmp; bitcoin_transaction tmp;
if( !s.empty() ) { if (!s.empty()) {
fc::datastream<const char*> ds( s.data(), size_t( s.size() ) ); fc::datastream<const char *> ds(s.data(), size_t(s.size()));
unpack(ds, tmp); unpack(ds, tmp);
}
return tmp;
} }
return tmp; FC_RETHROW_EXCEPTIONS(warn, "error unpacking ${type}", ("type", "transaction"))
} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) }
template<typename Stream>
inline void pack_tx_signature( Stream& s, const std::vector<char>& scriptPubKey, const bitcoin_transaction& tx, unsigned int in_index, int hash_type )
{
pack( s, tx.nVersion );
pack_compact_size( s, tx.vin.size() );
for ( size_t i = 0; i < tx.vin.size(); i++ ) {
const auto& in = tx.vin[i];
pack( s, in.prevout );
if ( i == in_index )
pack( s, scriptPubKey );
else
pack_compact_size( s, 0 ); // Blank signature
pack( s, in.nSequence );
}
pack_compact_size( s, tx.vout.size() );
for ( const auto& out : tx.vout )
pack( s, out );
pack( s, tx.nLockTime );
pack( s, hash_type );
} }
template<typename Stream> template <typename Stream>
inline void pack_tx_witness_signature( Stream& s, const std::vector<char>& scriptCode, const bitcoin_transaction& tx, unsigned int in_index, int64_t amount, int hash_type ) inline void pack_tx_signature(Stream &s, const std::vector<char> &scriptPubKey, const bitcoin_transaction &tx, unsigned int in_index, int hash_type) {
{ pack(s, tx.nVersion);
pack_compact_size(s, tx.vin.size());
for (size_t i = 0; i < tx.vin.size(); i++) {
const auto &in = tx.vin[i];
pack(s, in.prevout);
if (i == in_index)
pack(s, scriptPubKey);
else
pack_compact_size(s, 0); // Blank signature
pack(s, in.nSequence);
}
pack_compact_size(s, tx.vout.size());
for (const auto &out : tx.vout)
pack(s, out);
pack(s, tx.nLockTime);
pack(s, hash_type);
}
template <typename Stream>
inline void pack_tx_witness_signature(Stream &s, const std::vector<char> &scriptCode, const bitcoin_transaction &tx, unsigned int in_index, int64_t amount, int hash_type) {
fc::sha256 hash_prevouts; fc::sha256 hash_prevouts;
fc::sha256 hash_sequence; fc::sha256 hash_sequence;
@ -307,61 +294,61 @@ inline void pack_tx_witness_signature( Stream& s, const std::vector<char>& scrip
{ {
fc::datastream<size_t> ps; fc::datastream<size_t> ps;
for ( const auto in : tx.vin ) for (const auto in : tx.vin)
pack( ps, in.prevout ); pack(ps, in.prevout);
std::vector<char> vec( ps.tellp() ); std::vector<char> vec(ps.tellp());
if ( vec.size() ) { if (vec.size()) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); fc::datastream<char *> ds(vec.data(), size_t(vec.size()));
for ( const auto in : tx.vin ) for (const auto in : tx.vin)
pack( ds, in.prevout ); pack(ds, in.prevout);
} }
hash_prevouts = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); hash_prevouts = fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
} }
{ {
fc::datastream<size_t> ps; fc::datastream<size_t> ps;
for ( const auto in : tx.vin ) for (const auto in : tx.vin)
pack( ps, in.nSequence ); pack(ps, in.nSequence);
std::vector<char> vec( ps.tellp() ); std::vector<char> vec(ps.tellp());
if ( vec.size() ) { if (vec.size()) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); fc::datastream<char *> ds(vec.data(), size_t(vec.size()));
for ( const auto in : tx.vin ) for (const auto in : tx.vin)
pack( ds, in.nSequence ); pack(ds, in.nSequence);
} }
hash_sequence = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); hash_sequence = fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
}; };
{ {
fc::datastream<size_t> ps; fc::datastream<size_t> ps;
for ( const auto out : tx.vout ) for (const auto out : tx.vout)
pack( ps, out ); pack(ps, out);
std::vector<char> vec( ps.tellp() ); std::vector<char> vec(ps.tellp());
if ( vec.size() ) { if (vec.size()) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); fc::datastream<char *> ds(vec.data(), size_t(vec.size()));
for ( const auto out : tx.vout ) for (const auto out : tx.vout)
pack( ds, out ); pack(ds, out);
} }
hash_output = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); hash_output = fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
} }
pack( s, tx.nVersion ); pack(s, tx.nVersion);
pack( s, hash_prevouts ); pack(s, hash_prevouts);
pack( s, hash_sequence ); pack(s, hash_sequence);
pack( s, tx.vin[in_index].prevout ); pack(s, tx.vin[in_index].prevout);
pack( s, scriptCode ); pack(s, scriptCode);
pack( s, amount ); pack(s, amount);
pack( s, tx.vin[in_index].nSequence ); pack(s, tx.vin[in_index].nSequence);
pack( s, hash_output ); pack(s, hash_output);
pack( s, tx.nLockTime ); pack(s, tx.nLockTime);
pack( s, hash_type ); pack(s, hash_type);
} }
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
#include <fc/crypto/sha256.hpp> #include <fc/crypto/sha256.hpp>
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
#include <secp256k1.h> #include <secp256k1.h>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
@ -10,24 +10,24 @@ class bitcoin_transaction;
const secp256k1_context_t *btc_context(); const secp256k1_context_t *btc_context();
fc::sha256 get_signature_hash( const bitcoin_transaction& tx, const bytes& scriptPubKey, int64_t amount, fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &scriptPubKey, int64_t amount,
size_t in_index, int hash_type, bool is_witness ); size_t in_index, int hash_type, bool is_witness);
std::vector<char> privkey_sign( const bytes& privkey, const fc::sha256 &hash, const secp256k1_context_t* context_sign = nullptr ); std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context_t *context_sign = nullptr);
std::vector<bytes> sign_witness_transaction_part( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts, std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t>& amounts, const bytes& privkey, const std::vector<uint64_t> &amounts, const bytes &privkey,
const secp256k1_context_t* context_sign = nullptr, int hash_type = 1 ); const secp256k1_context_t *context_sign = nullptr, int hash_type = 1);
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts, bool use_mulisig_workaround = true ); void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts, bool use_mulisig_workaround = true);
bool verify_sig( const bytes& sig, const bytes& pubkey, const bytes& msg, const secp256k1_context_t* context ); bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context_t *context);
std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts, std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t>& amounts, const secp256k1_context_t* context ); const std::vector<uint64_t> &amounts, const secp256k1_context_t *context);
void add_signatures_to_transaction_multisig( bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set ); void add_signatures_to_transaction_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set);
void add_signatures_to_transaction_weighted_multisig( bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set ); void add_signatures_to_transaction_weighted_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set);
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <map>
#include <vector>
#include <string>
#include <fc/reflect/reflect.hpp> #include <fc/reflect/reflect.hpp>
#include <map>
#include <string>
#include <vector>
#include <graphene/chain/protocol/types.hpp> #include <graphene/chain/protocol/types.hpp>
@ -12,11 +12,10 @@ namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
class bitcoin_transaction; class bitcoin_transaction;
using bytes = std::vector<char>; using bytes = std::vector<char>;
using accounts_keys = std::map< graphene::chain::son_id_type, graphene::chain::public_key_type >; using accounts_keys = std::map<graphene::chain::son_id_type, graphene::chain::public_key_type>;
using full_btc_transaction = std::pair<bitcoin_transaction, uint64_t>; using full_btc_transaction = std::pair<bitcoin_transaction, uint64_t>;
enum class payment_type enum class payment_type {
{
NULLDATA, NULLDATA,
P2PK, P2PK,
P2PKH, P2PKH,
@ -27,21 +26,17 @@ enum class payment_type
P2SH_WSH P2SH_WSH
}; };
enum class sidechain_proposal_type enum class sidechain_proposal_type {
{
ISSUE_BTC, ISSUE_BTC,
SEND_BTC_TRANSACTION, SEND_BTC_TRANSACTION,
REVERT_BTC_TRANSACTION REVERT_BTC_TRANSACTION
}; };
struct prev_out struct prev_out {
{ bool operator!=(const prev_out &obj) const {
bool operator!=( const prev_out& obj ) const if (this->hash_tx != obj.hash_tx ||
{
if( this->hash_tx != obj.hash_tx ||
this->n_vout != obj.n_vout || this->n_vout != obj.n_vout ||
this->amount != obj.amount ) this->amount != obj.amount) {
{
return true; return true;
} }
return false; return false;
@ -52,8 +47,8 @@ struct prev_out
uint64_t amount; uint64_t amount;
}; };
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin
FC_REFLECT_ENUM( graphene::peerplays_sidechain::bitcoin::payment_type, (NULLDATA)(P2PK)(P2PKH)(P2SH)(P2WPKH)(P2WSH)(P2SH_WPKH)(P2SH_WSH) ); FC_REFLECT_ENUM(graphene::peerplays_sidechain::bitcoin::payment_type, (NULLDATA)(P2PK)(P2PKH)(P2SH)(P2WPKH)(P2WSH)(P2SH_WPKH)(P2SH_WSH));
FC_REFLECT_ENUM( graphene::peerplays_sidechain::bitcoin::sidechain_proposal_type, (ISSUE_BTC)(SEND_BTC_TRANSACTION)(REVERT_BTC_TRANSACTION) ); FC_REFLECT_ENUM(graphene::peerplays_sidechain::bitcoin::sidechain_proposal_type, (ISSUE_BTC)(SEND_BTC_TRANSACTION)(REVERT_BTC_TRANSACTION));
FC_REFLECT( graphene::peerplays_sidechain::bitcoin::prev_out, (hash_tx)(n_vout)(amount) ); FC_REFLECT(graphene::peerplays_sidechain::bitcoin::prev_out, (hash_tx)(n_vout)(amount));

View file

@ -1,18 +1,18 @@
#pragma once #pragma once
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
#include <fc/crypto/hex.hpp>
#include <fc/crypto/elliptic.hpp> #include <fc/crypto/elliptic.hpp>
#include <fc/crypto/hex.hpp>
#include <graphene/peerplays_sidechain/bitcoin/types.hpp>
namespace graphene { namespace peerplays_sidechain { namespace bitcoin { namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
fc::ecc::public_key_data create_public_key_data( const std::vector<char>& public_key ); fc::ecc::public_key_data create_public_key_data(const std::vector<char> &public_key);
bytes get_privkey_bytes( const std::string& privkey_base58 ); bytes get_privkey_bytes(const std::string &privkey_base58);
bytes parse_hex( const std::string& str ); bytes parse_hex(const std::string &str);
std::vector<bytes> get_pubkey_from_redeemScript( bytes script ); std::vector<bytes> get_pubkey_from_redeemScript(bytes script);
bytes public_key_data_to_bytes( const fc::ecc::public_key_data& key ); bytes public_key_data_to_bytes(const fc::ecc::public_key_data &key);
} } } }}} // namespace graphene::peerplays_sidechain::bitcoin

View file

@ -1278,10 +1278,10 @@ std::string sidechain_net_handler_bitcoin::send_sidechain_transaction(const side
std::string sidechain_net_handler_bitcoin::create_multisig_address_standalone(const std::vector<son_info> &son_pubkeys) { std::string sidechain_net_handler_bitcoin::create_multisig_address_standalone(const std::vector<son_info> &son_pubkeys) {
using namespace bitcoin; using namespace bitcoin;
std::vector<std::pair<fc::ecc::public_key, uint16_t> > pubkey_weights; std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
for (auto &son: son_pubkeys) { for (auto &son : son_pubkeys) {
std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin);
auto pub_key = fc::ecc::public_key(create_public_key_data( parse_hex(pub_key_str) )); auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
} }
@ -1293,7 +1293,7 @@ std::string sidechain_net_handler_bitcoin::create_multisig_address_standalone(co
<< "}, \"error\":null}"; << "}, \"error\":null}";
std::string res = ss.str(); std::string res = ss.str();
ilog("Weighted Multisig Address = ${a}",("a", res)); ilog("Weighted Multisig Address = ${a}", ("a", res));
return res; return res;
} }
@ -1454,29 +1454,26 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran
} }
} }
std::vector<bitcoin::bytes> read_byte_arrays_from_string(const std::string &string_buf) std::vector<bitcoin::bytes> read_byte_arrays_from_string(const std::string &string_buf) {
{
std::stringstream ss(string_buf); std::stringstream ss(string_buf);
boost::property_tree::ptree json; boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json); boost::property_tree::read_json(ss, json);
std::vector<bitcoin::bytes> data; std::vector<bitcoin::bytes> data;
for(auto &v: json) for (auto &v : json) {
{
std::string hex = v.second.data(); std::string hex = v.second.data();
bitcoin::bytes item; bitcoin::bytes item;
item.resize(hex.size() / 2); item.resize(hex.size() / 2);
fc::from_hex(hex, (char*)&item[0], item.size()); fc::from_hex(hex, (char *)&item[0], item.size());
data.push_back(item); data.push_back(item);
} }
return data; return data;
} }
std::string write_byte_arrays_to_string(const std::vector<bitcoin::bytes>& data) std::string write_byte_arrays_to_string(const std::vector<bitcoin::bytes> &data) {
{
std::string res = "["; std::string res = "[";
for (unsigned int idx = 0; idx < data.size(); ++idx) { for (unsigned int idx = 0; idx < data.size(); ++idx) {
res += "\"" + fc::to_hex((char*)&data[idx][0], data[idx].size()) + "\""; res += "\"" + fc::to_hex((char *)&data[idx][0], data[idx].size()) + "\"";
if (idx != data.size() - 1) if (idx != data.size() - 1)
res += ","; res += ",";
} }
@ -1484,34 +1481,31 @@ std::string write_byte_arrays_to_string(const std::vector<bitcoin::bytes>& data)
return res; return res;
} }
void read_tx_data_from_string(const std::string &string_buf, std::vector<unsigned char> &tx, std::vector<uint64_t> &in_amounts) void read_tx_data_from_string(const std::string &string_buf, std::vector<unsigned char> &tx, std::vector<uint64_t> &in_amounts) {
{
std::stringstream ss(string_buf); std::stringstream ss(string_buf);
boost::property_tree::ptree json; boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json); boost::property_tree::read_json(ss, json);
std::string tx_hex = json.get<std::string>("tx_hex"); std::string tx_hex = json.get<std::string>("tx_hex");
tx.clear(); tx.clear();
tx.resize(tx_hex.size() / 2); tx.resize(tx_hex.size() / 2);
fc::from_hex(tx_hex, (char*)&tx[0], tx.size()); fc::from_hex(tx_hex, (char *)&tx[0], tx.size());
in_amounts.clear(); in_amounts.clear();
for(auto &v: json.get_child("in_amounts")) for (auto &v : json.get_child("in_amounts"))
in_amounts.push_back(fc::to_uint64(v.second.data())); in_amounts.push_back(fc::to_uint64(v.second.data()));
} }
void read_tx_data_from_string(const std::string &string_buf, std::string &tx_hex, std::vector<uint64_t> &in_amounts) void read_tx_data_from_string(const std::string &string_buf, std::string &tx_hex, std::vector<uint64_t> &in_amounts) {
{
std::stringstream ss(string_buf); std::stringstream ss(string_buf);
boost::property_tree::ptree json; boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json); boost::property_tree::read_json(ss, json);
tx_hex = json.get<std::string>("tx_hex"); tx_hex = json.get<std::string>("tx_hex");
in_amounts.clear(); in_amounts.clear();
for(auto &v: json.get_child("in_amounts")) for (auto &v : json.get_child("in_amounts"))
in_amounts.push_back(fc::to_uint64(v.second.data())); in_amounts.push_back(fc::to_uint64(v.second.data()));
} }
std::string save_tx_data_to_string(const std::vector<unsigned char> &tx, const std::vector<uint64_t> &in_amounts) std::string save_tx_data_to_string(const std::vector<unsigned char> &tx, const std::vector<uint64_t> &in_amounts) {
{ std::string res = "{\"tx_hex\":\"" + fc::to_hex((const char *)&tx[0], tx.size()) + "\",\"in_amounts\":[";
std::string res = "{\"tx_hex\":\"" + fc::to_hex((const char*)&tx[0], tx.size()) + "\",\"in_amounts\":[";
for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) { for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) {
res += fc::to_string(in_amounts[idx]); res += fc::to_string(in_amounts[idx]);
if (idx != in_amounts.size() - 1) if (idx != in_amounts.size() - 1)
@ -1521,8 +1515,7 @@ std::string save_tx_data_to_string(const std::vector<unsigned char> &tx, const s
return res; return res;
} }
std::string save_tx_data_to_string(const std::string &tx, const std::vector<uint64_t> &in_amounts) std::string save_tx_data_to_string(const std::string &tx, const std::vector<uint64_t> &in_amounts) {
{
std::string res = "{\"tx_hex\":\"" + tx + "\",\"in_amounts\":["; std::string res = "{\"tx_hex\":\"" + tx + "\",\"in_amounts\":[";
for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) { for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) {
res += fc::to_string(in_amounts[idx]); res += fc::to_string(in_amounts[idx]);
@ -1547,21 +1540,21 @@ std::string sidechain_net_handler_bitcoin::create_transaction_standalone(const s
bitcoin_transaction_builder tb; bitcoin_transaction_builder tb;
std::vector<uint64_t> in_amounts; std::vector<uint64_t> in_amounts;
tb.set_version( 2 ); tb.set_version(2);
for (auto in : inputs) { for (auto in : inputs) {
tb.add_in( payment_type::P2WSH, fc::sha256(in.txid_), in.out_num_, bitcoin::bytes() ); tb.add_in(payment_type::P2WSH, fc::sha256(in.txid_), in.out_num_, bitcoin::bytes());
in_amounts.push_back(in.amount_); in_amounts.push_back(in.amount_);
} }
for (auto out : outputs) { for (auto out : outputs) {
uint64_t satoshis = out.second * 100000000.0; uint64_t satoshis = out.second * 100000000.0;
tb.add_out_all_type( satoshis, out.first); tb.add_out_all_type(satoshis, out.first);
//tb.add_out( bitcoin_address( out.first ).get_type(), satoshis, out.first); //tb.add_out( bitcoin_address( out.first ).get_type(), satoshis, out.first);
} }
const auto tx = tb.get_transaction(); const auto tx = tb.get_transaction();
std::string hex_tx = fc::to_hex( pack( tx ) ); std::string hex_tx = fc::to_hex(pack(tx));
std::string tx_raw = save_tx_data_to_string(hex_tx, in_amounts); std::string tx_raw = save_tx_data_to_string(hex_tx, in_amounts);
@ -1767,8 +1760,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_standalone(const sid
//const auto privkey_signing = get_privkey_bytes( prvkey ); //const auto privkey_signing = get_privkey_bytes( prvkey );
fc::optional<fc::ecc::private_key> btc_private_key = graphene::utilities::wif_to_key(prvkey); fc::optional<fc::ecc::private_key> btc_private_key = graphene::utilities::wif_to_key(prvkey);
if (!btc_private_key) if (!btc_private_key) {
{
elog("Invalid private key ${pk}", ("pk", prvkey)); elog("Invalid private key ${pk}", ("pk", prvkey));
return ""; return "";
} }
@ -1780,10 +1772,10 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_standalone(const sid
ilog("Sign transaction retreived: ${s}", ("s", tx_hex)); ilog("Sign transaction retreived: ${s}", ("s", tx_hex));
std::vector<std::pair<fc::ecc::public_key, uint16_t> > pubkey_weights; std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
for (auto &son: sto.signers) { for (auto &son : sto.signers) {
std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin);
auto pub_key = fc::ecc::public_key(create_public_key_data( parse_hex(pub_key_str) )); auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
} }
@ -1795,7 +1787,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_standalone(const sid
std::vector<bitcoin::bytes> redeem_scripts(tx.vin.size(), rscript); std::vector<bitcoin::bytes> redeem_scripts(tx.vin.size(), rscript);
auto sigs = sign_witness_transaction_part( tx, redeem_scripts, in_amounts, privkey_signing, btc_context(), 1 ); auto sigs = sign_witness_transaction_part(tx, redeem_scripts, in_amounts, privkey_signing, btc_context(), 1);
std::string tx_signature = write_byte_arrays_to_string(sigs); std::string tx_signature = write_byte_arrays_to_string(sigs);
@ -1906,10 +1898,10 @@ std::string sidechain_net_handler_bitcoin::send_transaction_standalone(const sid
ilog("Send transaction retreived: ${s}", ("s", tx_hex)); ilog("Send transaction retreived: ${s}", ("s", tx_hex));
std::vector<std::pair<fc::ecc::public_key, uint16_t> > pubkey_weights; std::vector<std::pair<fc::ecc::public_key, uint16_t>> pubkey_weights;
for (auto &son: sto.signers) { for (auto &son : sto.signers) {
std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin); std::string pub_key_str = son.sidechain_public_keys.at(sidechain_type::bitcoin);
auto pub_key = fc::ecc::public_key(create_public_key_data( parse_hex(pub_key_str) )); auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str)));
pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
} }
@ -1927,7 +1919,7 @@ std::string sidechain_net_handler_bitcoin::send_transaction_standalone(const sid
vector<vector<bitcoin::bytes>> signatures; vector<vector<bitcoin::bytes>> signatures;
for (unsigned idx = 0; idx < sto.signatures.size(); ++idx) { for (unsigned idx = 0; idx < sto.signatures.size(); ++idx) {
if(sto.signatures[idx].second.empty()) if (sto.signatures[idx].second.empty())
signatures.push_back(dummy); signatures.push_back(dummy);
else else
signatures.push_back(read_byte_arrays_from_string(sto.signatures[idx].second)); signatures.push_back(read_byte_arrays_from_string(sto.signatures[idx].second));
@ -1937,7 +1929,7 @@ std::string sidechain_net_handler_bitcoin::send_transaction_standalone(const sid
sign_witness_transaction_finalize(tx, redeem_scripts, false); sign_witness_transaction_finalize(tx, redeem_scripts, false);
std::string final_tx_hex = fc::to_hex( pack( tx ) ); std::string final_tx_hex = fc::to_hex(pack(tx));
std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); std::string res = bitcoin_client->sendrawtransaction(final_tx_hex);