Merge branch 'feature/417/Add_support_in_bitcoin_for_P2SH-P2WSH_address_format' into 'feature/libbitcoin-son'

Add support for P2SH-P2WSH address format

See merge request PBSA/peerplays!140
This commit is contained in:
serkixenos 2022-09-05 13:27:27 +00:00
commit 789c0547cf
5 changed files with 100 additions and 20 deletions

View file

@ -242,12 +242,12 @@ bytes btc_multisig_segwit_address::get_address_bytes(const bytes &script_hash) {
}
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, payment_type type) {
network_type = ntype;
this->type = type;
create_redeem_script(keys_data);
create_witness_script();
create_segwit_address();
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) {
@ -278,26 +278,43 @@ void btc_weighted_multisig_address::create_witness_script() {
script_builder builder;
builder << op::_0;
builder << fc::sha256::hash(redeem_script_.data(), redeem_script_.size());
witness_script_ = builder;
}
void btc_weighted_multisig_address::create_segwit_address() {
std::string hrp;
address_types byte_version;
switch (network_type) {
case (network::mainnet):
hrp = "bc";
byte_version = address_types::MAINNET_SCRIPT;
break;
case (network::testnet):
hrp = "tb";
byte_version = address_types::TESTNET_SCRIPT;
break;
case (network::regtest):
hrp = "bcrt";
byte_version = address_types::TESTNET_SCRIPT;
break;
}
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
address = segwit_addr::encode(hrp, 0, hash_data);
if (type == payment_type::P2WSH) {
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
address = segwit_addr::encode(hrp, 0, hash_data);
} else if (type == payment_type::P2SH_WSH) {
fc::sha256 hash256 = fc::sha256::hash(&witness_script_[0], witness_script_.size());
fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
bytes address_bytes(1, byte_version); // 1 byte version
address_bytes.insert(address_bytes.end(), raw_address.begin(), raw_address.end());
fc::sha256 hash256_1 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
address_bytes.insert(address_bytes.end(), hash256_1.data(), hash256_1.data() + 4); // 4 byte checksum
address = fc::to_base58(address_bytes);
} else {
wlog("Unsupported payment type of address");
}
}
btc_one_or_m_of_n_multisig_address::btc_one_or_m_of_n_multisig_address(const fc::ecc::public_key &user_key_data,
@ -353,12 +370,12 @@ 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,
const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data,
bitcoin_address::network ntype) {
bitcoin_address::network ntype, payment_type type) {
network_type = ntype;
this->type = type;
create_redeem_script(user_key_data, keys_data);
create_witness_script();
create_segwit_address();
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) {
@ -398,20 +415,39 @@ void btc_one_or_weighted_multisig_address::create_witness_script() {
void btc_one_or_weighted_multisig_address::create_segwit_address() {
std::string hrp;
address_types byte_version;
switch (network_type) {
case (network::mainnet):
byte_version = address_types::MAINNET_SCRIPT;
hrp = "bc";
break;
case (network::testnet):
byte_version = address_types::TESTNET_SCRIPT;
hrp = "tb";
break;
case (network::regtest):
byte_version = address_types::TESTNET_SCRIPT;
hrp = "bcrt";
break;
}
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
address = segwit_addr::encode(hrp, 0, hash_data);
if (type == payment_type::P2WSH) {
fc::sha256 sh = fc::sha256::hash(&redeem_script_[0], redeem_script_.size());
std::vector<uint8_t> hash_data(sh.data(), sh.data() + sh.data_size());
address = segwit_addr::encode(hrp, 0, hash_data);
} else if (type == payment_type::P2SH_WSH) {
fc::sha256 hash256 = fc::sha256::hash(&witness_script_[0], witness_script_.size());
fc::ripemd160 hash160 = fc::ripemd160::hash(hash256.data(), hash256.data_size());
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size());
bytes address_bytes(1, byte_version); // 1 byte version test net
address_bytes.insert(address_bytes.end(), raw_address.begin(), raw_address.end());
fc::sha256 hash256_1 = fc::sha256::hash(fc::sha256::hash(address_bytes.data(), address_bytes.size()));
address_bytes.insert(address_bytes.end(), hash256_1.data(), hash256_1.data() + 4); // 4 byte checksum
address = fc::to_base58(address_bytes);
} else {
elog("Unsupported payment type of address");
}
}
btc_timelocked_one_or_weighted_multisig_address::btc_timelocked_one_or_weighted_multisig_address(const fc::ecc::public_key &user_key_data, uint32_t latency, const std::vector<std::pair<fc::ecc::public_key, uint16_t>> &keys_data, bitcoin_address::network ntype) :

View file

@ -8,6 +8,14 @@ using namespace graphene::chain;
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
enum address_types { MAINNET_SCRIPT = 5,
TESTNET_SCRIPT = 196 };
enum script_op {
OP_0 = 0x00,
OP_PUSH = 0x20,
OP_SIZE_34 = 0x22
};
class bitcoin_address {
@ -96,9 +104,6 @@ private:
void create_address();
public:
enum address_types { MAINNET_SCRIPT = 5,
TESTNET_SCRIPT = 196 };
enum { OP_0 = 0x00,
OP_EQUAL = 0x87,
OP_HASH160 = 0xa9,
@ -145,7 +150,7 @@ public:
btc_weighted_multisig_address() = default;
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, payment_type type = payment_type::P2SH_WSH);
bytes get_redeem_script() const {
return redeem_script_;
@ -190,7 +195,7 @@ class btc_one_or_weighted_multisig_address : public bitcoin_address {
public:
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,
network network_type = network::regtest);
network network_type = network::regtest, payment_type type = payment_type::P2SH_WSH);
bytes get_redeem_script() const {
return redeem_script_;
}

View file

@ -57,6 +57,7 @@ protected:
sidechain_type sidechain;
bool debug_rpc_calls;
bool use_p2wsh_address;
std::map<std::string, std::string> private_keys;

View file

@ -165,6 +165,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
cli.add_options()("sidechain-retry-threshold", bpo::value<uint16_t>()->default_value(150), "Sidechain retry throttling threshold");
cli.add_options()("debug-rpc-calls", bpo::value<bool>()->default_value(false), "Outputs RPC calls to console");
cli.add_options()("use-p2wsh-address", bpo::value<bool>()->default_value(false), "Use p2wsh address instead of p2sh address");
cli.add_options()("bitcoin-sidechain-enabled", bpo::value<bool>()->default_value(false), "Bitcoin sidechain handler enabled");
cli.add_options()("bitcoin-node-ip", bpo::value<string>()->default_value("127.0.0.1"), "IP address of Bitcoin node");

View file

@ -329,6 +329,10 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
}
if (options.count("use-p2wsh-address")) {
use_p2wsh_address = options.at("use-p2wsh-address").as<bool>();
}
ip = options.at("bitcoin-node-ip").as<std::string>();
zmq_port = options.at("bitcoin-node-zmq-port").as<uint32_t>();
rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>();
@ -793,7 +797,12 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
if (sao.expires == time_point_sec::maximum()) {
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type);
payment_type payment_type_address = payment_type::P2SH_WSH;
if (use_p2wsh_address) {
payment_type_address = payment_type::P2WSH;
}
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type, payment_type_address);
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
@ -953,7 +962,13 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain
auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(si.public_key)));
pubkey_weights.push_back(std::make_pair(pub_key, si.weight));
}
btc_weighted_multisig_address addr(pubkey_weights, network_type);
payment_type payment_type_address = payment_type::P2SH_WSH;
if (use_p2wsh_address) {
payment_type_address = payment_type::P2WSH;
}
btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address);
std::string tx_txid = tx_json.get<std::string>("result.txid");
uint32_t tx_confirmations = tx_json.get<uint32_t>("result.confirmations");
@ -1003,7 +1018,11 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
}
btc_weighted_multisig_address addr(pubkey_weights, network_type);
payment_type payment_type_address = payment_type::P2SH_WSH;
if (use_p2wsh_address) {
payment_type_address = payment_type::P2WSH;
}
btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address);
std::stringstream ss;
@ -1239,6 +1258,18 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran
}
// Add redeemscripts to vins and make tx ready for sending
sign_witness_transaction_finalize(tx, redeem_scripts, false);
if (!use_p2wsh_address) {
// get witness script from redeem script
bitcoin::bytes redeem_bytes = parse_hex(redeem_script);
fc::sha256 sha = fc::sha256::hash(&redeem_bytes[0], redeem_bytes.size());
std::string witness_script(sha.str());
witness_script.insert(0, std::string("220020"));
for (size_t i = 0; i < tx.vin.size(); i++) {
tx.vin[i].scriptSig = parse_hex(witness_script);
}
}
std::string final_tx_hex = fc::to_hex(pack(tx));
std::string res = bitcoin_client->sendrawtransaction(final_tx_hex);
@ -1309,7 +1340,13 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons
pubkey_weights.push_back(std::make_pair(pub_key, son.weight));
}
auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key)));
btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type);
payment_type payment_type_address = payment_type::P2SH_WSH;
if (use_p2wsh_address) {
payment_type_address = payment_type::P2WSH;
}
btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type, payment_type_address);
return fc::to_hex(deposit_addr.get_redeem_script());
}