peerplays_migrated/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp
serkixenos cb786554fc
Remove as much warnings from build log as possible (#400)
* Remove as much warnings from build log as possible
2020-12-18 14:23:37 +01:00

258 lines
8.2 KiB
C++

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