sending PW transfer in test
This commit is contained in:
parent
1f505d9db9
commit
79cc08c8bf
3 changed files with 376 additions and 121 deletions
|
|
@ -10,43 +10,76 @@ namespace graphene { namespace peerplays_sidechain {
|
|||
static const unsigned char OP_IF = 0x63;
|
||||
static const unsigned char OP_ENDIF = 0x68;
|
||||
static const unsigned char OP_SWAP = 0x7c;
|
||||
static const unsigned char OP_EQUAL = 0x87;
|
||||
static const unsigned char OP_ADD = 0x93;
|
||||
static const unsigned char OP_GREATERTHAN = 0xa0;
|
||||
static const unsigned char OP_HASH160 = 0xa9;
|
||||
static const unsigned char OP_CHECKSIG = 0xac;
|
||||
|
||||
class WriteBytesStream{
|
||||
public:
|
||||
WriteBytesStream(bytes& buffer) : storage_(buffer) {}
|
||||
|
||||
bool write( const char* d, size_t s ) {
|
||||
storage_.insert(storage_.end(), d, d + s);
|
||||
return true;
|
||||
}
|
||||
|
||||
void add( const unsigned char* d, size_t s ) {
|
||||
void write(const unsigned char* d, size_t s) {
|
||||
storage_.insert(storage_.end(), d, d + s);
|
||||
}
|
||||
|
||||
void add( const bytes& data) {
|
||||
storage_.insert(storage_.end(), data.begin(), data.end());
|
||||
}
|
||||
|
||||
void add(int32_t val)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(&val);
|
||||
write(data, sizeof(val));
|
||||
}
|
||||
|
||||
void add(uint32_t val)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(&val);
|
||||
write(data, sizeof(val));
|
||||
}
|
||||
|
||||
bool put(char c) {
|
||||
bool put(unsigned char c) {
|
||||
storage_.push_back(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
void writedata8(uint8_t obj)
|
||||
{
|
||||
write((unsigned char*)&obj, 1);
|
||||
}
|
||||
|
||||
void writedata16(uint16_t obj)
|
||||
{
|
||||
obj = htole16(obj);
|
||||
write((unsigned char*)&obj, 2);
|
||||
}
|
||||
|
||||
void writedata32(uint32_t obj)
|
||||
{
|
||||
obj = htole32(obj);
|
||||
write((unsigned char*)&obj, 4);
|
||||
}
|
||||
|
||||
void writedata64(uint64_t obj)
|
||||
{
|
||||
obj = htole64(obj);
|
||||
write((unsigned char*)&obj, 8);
|
||||
}
|
||||
|
||||
void write_compact_int(uint64_t val)
|
||||
{
|
||||
if (val < 253)
|
||||
{
|
||||
writedata8(val);
|
||||
}
|
||||
else if (val <= std::numeric_limits<unsigned short>::max())
|
||||
{
|
||||
writedata8(253);
|
||||
writedata16(val);
|
||||
}
|
||||
else if (val <= std::numeric_limits<unsigned int>::max())
|
||||
{
|
||||
writedata8(254);
|
||||
writedata32(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
writedata8(255);
|
||||
writedata64(val);
|
||||
}
|
||||
}
|
||||
|
||||
void writedata(const bytes& data)
|
||||
{
|
||||
write_compact_int(data.size());
|
||||
write(&data[0], data.size());
|
||||
}
|
||||
private:
|
||||
bytes& storage_;
|
||||
};
|
||||
|
|
@ -55,7 +88,15 @@ class ReadBytesStream{
|
|||
public:
|
||||
ReadBytesStream(const bytes& buffer, size_t pos = 0) : storage_(buffer), pos_(pos), end_(buffer.size()) {}
|
||||
|
||||
inline bool read( char* d, size_t s ) {
|
||||
size_t current_pos() const { return pos_; }
|
||||
void set_pos(size_t pos)
|
||||
{
|
||||
if(pos > end_)
|
||||
FC_THROW("Invalid position in BTC tx buffer");
|
||||
pos_ = pos;
|
||||
}
|
||||
|
||||
inline bool read( unsigned char* d, size_t s ) {
|
||||
if( end_ - pos_ >= s ) {
|
||||
memcpy( d, &storage_[pos_], s );
|
||||
pos_ += s;
|
||||
|
|
@ -64,34 +105,7 @@ public:
|
|||
FC_THROW( "invalid bitcoin tx buffer" );
|
||||
}
|
||||
|
||||
void direct_read( unsigned char* d, size_t s ) {
|
||||
if( end_ - pos_ >= s ) {
|
||||
memcpy( d, &storage_[pos_], s );
|
||||
pos_ += s;
|
||||
}
|
||||
FC_THROW( "invalid bitcoin tx buffer" );
|
||||
}
|
||||
|
||||
void direct_read( bytes& data, size_t s) {
|
||||
data.clear();
|
||||
data.resize(s);
|
||||
direct_read(&data[0], s);
|
||||
}
|
||||
|
||||
void direct_read(int32_t& val)
|
||||
{
|
||||
char* data = reinterpret_cast<char*>(&val);
|
||||
read(data, sizeof(val));
|
||||
}
|
||||
|
||||
void direct_read(uint32_t& val)
|
||||
{
|
||||
char* data = reinterpret_cast<char*>(&val);
|
||||
read(data, sizeof(val));
|
||||
}
|
||||
|
||||
inline bool get( unsigned char& c ) { return get( *(char*)&c ); }
|
||||
inline bool get( char& c )
|
||||
inline bool get( unsigned char& c )
|
||||
{
|
||||
if( pos_ < end_ ) {
|
||||
c = storage_[pos_++];
|
||||
|
|
@ -99,19 +113,211 @@ public:
|
|||
}
|
||||
FC_THROW( "invalid bitcoin tx buffer" );
|
||||
}
|
||||
|
||||
uint8_t readdata8()
|
||||
{
|
||||
uint8_t obj;
|
||||
read((unsigned char*)&obj, 1);
|
||||
return obj;
|
||||
}
|
||||
uint16_t readdata16()
|
||||
{
|
||||
uint16_t obj;
|
||||
read((unsigned char*)&obj, 2);
|
||||
return le16toh(obj);
|
||||
}
|
||||
uint32_t readdata32()
|
||||
{
|
||||
uint32_t obj;
|
||||
read((unsigned char*)&obj, 4);
|
||||
return le32toh(obj);
|
||||
}
|
||||
uint64_t readdata64()
|
||||
{
|
||||
uint64_t obj;
|
||||
read((unsigned char*)&obj, 8);
|
||||
return le64toh(obj);
|
||||
}
|
||||
|
||||
uint64_t read_compact_int()
|
||||
{
|
||||
uint8_t size = readdata8();
|
||||
uint64_t ret = 0;
|
||||
if (size < 253)
|
||||
{
|
||||
ret = size;
|
||||
}
|
||||
else if (size == 253)
|
||||
{
|
||||
ret = readdata16();
|
||||
if (ret < 253)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
else if (size == 254)
|
||||
{
|
||||
ret = readdata32();
|
||||
if (ret < 0x10000u)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = readdata64();
|
||||
if (ret < 0x100000000ULL)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
if (ret > (uint64_t)0x02000000)
|
||||
FC_THROW("ReadCompactSize(): size too large");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void readdata(bytes& data)
|
||||
{
|
||||
size_t s = read_compact_int();
|
||||
data.clear();
|
||||
data.resize(s);
|
||||
read(&data[0], s);
|
||||
}
|
||||
|
||||
private:
|
||||
const bytes& storage_;
|
||||
size_t pos_;
|
||||
size_t end_;
|
||||
};
|
||||
|
||||
void btc_outpoint::to_bytes(bytes& stream) const
|
||||
{
|
||||
WriteBytesStream str(stream);
|
||||
// TODO: write size?
|
||||
str.write((unsigned char*)hash.data(), hash.data_size());
|
||||
str.writedata32(n);
|
||||
}
|
||||
|
||||
size_t btc_outpoint::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
ReadBytesStream str(data, pos);
|
||||
// TODO: read size?
|
||||
str.read((unsigned char*)hash.data(), hash.data_size());
|
||||
n = str.readdata32();
|
||||
return str.current_pos();
|
||||
}
|
||||
|
||||
void btc_in::to_bytes(bytes& stream) const
|
||||
{
|
||||
prevout.to_bytes(stream);
|
||||
WriteBytesStream str(stream);
|
||||
str.writedata(scriptSig);
|
||||
str.writedata32(nSequence);
|
||||
}
|
||||
|
||||
size_t btc_in::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
pos = prevout.fill_from_bytes(data, pos);
|
||||
ReadBytesStream str(data, pos);
|
||||
str.readdata(scriptSig);
|
||||
nSequence = str.readdata32();
|
||||
return str.current_pos();
|
||||
}
|
||||
|
||||
void btc_out::to_bytes(bytes& stream) const
|
||||
{
|
||||
WriteBytesStream str(stream);
|
||||
str.writedata64(nValue);
|
||||
str.writedata(scriptPubKey);
|
||||
}
|
||||
|
||||
size_t btc_out::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
ReadBytesStream str(data, pos);
|
||||
nValue = str.readdata64();
|
||||
str.readdata(scriptPubKey);
|
||||
return str.current_pos();
|
||||
}
|
||||
|
||||
void btc_tx::to_bytes(bytes& stream) const
|
||||
{
|
||||
WriteBytesStream str(stream);
|
||||
str.writedata32(nVersion);
|
||||
if(hasWitness)
|
||||
{
|
||||
// write dummy inputs and flag
|
||||
str.write_compact_int(0);
|
||||
unsigned char flags = 1;
|
||||
str.put(flags);
|
||||
}
|
||||
str.write_compact_int(vin.size());
|
||||
for(const auto& in: vin)
|
||||
in.to_bytes(stream);
|
||||
str.write_compact_int(vout.size());
|
||||
for(const auto& out: vout)
|
||||
out.to_bytes(stream);
|
||||
if(hasWitness)
|
||||
{
|
||||
for(const auto& in: vin)
|
||||
str.writedata(in.scriptWitness);
|
||||
}
|
||||
str.writedata32(nLockTime);
|
||||
}
|
||||
|
||||
size_t btc_tx::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
ReadBytesStream ds( data, pos );
|
||||
nVersion = ds.readdata32();
|
||||
unsigned char flags = 0;
|
||||
vin.clear();
|
||||
vout.clear();
|
||||
hasWitness = false;
|
||||
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
|
||||
size_t vin_size = ds.read_compact_int();
|
||||
vin.resize(vin_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& in: vin)
|
||||
pos = in.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
if (vin_size == 0) {
|
||||
/* We read a dummy or an empty vin. */
|
||||
ds.get(flags);
|
||||
if (flags != 0) {
|
||||
size_t vin_size = ds.read_compact_int();
|
||||
vin.resize(vin_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& in: vin)
|
||||
pos = in.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
size_t vout_size = ds.read_compact_int();
|
||||
vout.resize(vout_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& out: vout)
|
||||
pos = out.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
hasWitness = true;
|
||||
}
|
||||
} else {
|
||||
/* We read a non-empty vin. Assume a normal vout follows. */
|
||||
size_t vout_size = ds.read_compact_int();
|
||||
vout.resize(vout_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& out: vout)
|
||||
pos = out.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
}
|
||||
if (hasWitness) {
|
||||
/* The witness flag is present, and we support witnesses. */
|
||||
for (auto& in: vin)
|
||||
ds.readdata(in.scriptWitness);
|
||||
|
||||
}
|
||||
nLockTime = ds.readdata32();
|
||||
return ds.current_pos();
|
||||
}
|
||||
|
||||
|
||||
void add_data_to_script(bytes& script, const bytes& data)
|
||||
{
|
||||
WriteBytesStream str(script);
|
||||
fc::raw::pack(str, data, 2);
|
||||
str.writedata(data);
|
||||
}
|
||||
|
||||
bytes generate_redeem_script(fc::flat_map<fc::ecc::public_key, int> key_data)
|
||||
bytes generate_redeem_script(std::vector<std::pair<fc::ecc::public_key, int> > key_data)
|
||||
{
|
||||
int total_weight = 0;
|
||||
bytes result;
|
||||
|
|
@ -162,6 +368,17 @@ std::string p2sh_address_from_redeem_script(const bytes& script, bitcoin_network
|
|||
return fc::to_base58(reinterpret_cast<const char*>(&data[0]), data.size());
|
||||
}
|
||||
|
||||
bytes lock_script_for_redeem_script(const bytes &script)
|
||||
{
|
||||
bytes result;
|
||||
result.push_back(OP_HASH160);
|
||||
fc::ripemd160 h = fc::ripemd160::hash(reinterpret_cast<const char*>(&script[0]), script.size());
|
||||
bytes shash(h.data(), h.data() + h.data_size());
|
||||
add_data_to_script(result, shash);
|
||||
result.push_back(OP_EQUAL);
|
||||
return result;
|
||||
}
|
||||
|
||||
bytes signature_for_raw_transaction(const bytes& unsigned_tx, const fc::ecc::private_key& priv_key)
|
||||
{
|
||||
fc::sha256 digest = fc::sha256::hash(fc::sha256::hash(reinterpret_cast<const char*>(&unsigned_tx[0]), unsigned_tx.size()));
|
||||
|
|
@ -169,65 +386,13 @@ bytes signature_for_raw_transaction(const bytes& unsigned_tx, const fc::ecc::pri
|
|||
return bytes(res.begin(), res.begin() + res.size());
|
||||
}
|
||||
|
||||
bytes btc_tx::to_bytes() const
|
||||
{
|
||||
bytes res;
|
||||
WriteBytesStream str(res);
|
||||
str.add(nVersion);
|
||||
if(hasWitness)
|
||||
{
|
||||
std::vector<btc_in> dummy;
|
||||
fc::raw::pack(str, dummy);
|
||||
unsigned char flags = 1;
|
||||
str.put(flags);
|
||||
}
|
||||
fc::raw::pack(str, vin);
|
||||
fc::raw::pack(str, vout);
|
||||
if(hasWitness)
|
||||
{
|
||||
for(const auto& in: vin)
|
||||
fc::raw::pack(str, in.scriptWitness);
|
||||
}
|
||||
str.add(nLockTime);
|
||||
return res;
|
||||
}
|
||||
|
||||
void btc_tx::fill_from_bytes(const bytes& data)
|
||||
{
|
||||
ReadBytesStream ds( data );
|
||||
ds.direct_read(nVersion);
|
||||
unsigned char flags = 0;
|
||||
vin.clear();
|
||||
vout.clear();
|
||||
hasWitness = false;
|
||||
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
|
||||
fc::raw::unpack(ds, vin);
|
||||
if (vin.size() == 0) {
|
||||
/* We read a dummy or an empty vin. */
|
||||
ds.get(flags);
|
||||
if (flags != 0) {
|
||||
fc::raw::unpack(ds, vin);
|
||||
fc::raw::unpack(ds, vout);
|
||||
hasWitness = true;
|
||||
}
|
||||
} else {
|
||||
/* We read a non-empty vin. Assume a normal vout follows. */
|
||||
fc::raw::unpack(ds, vout);
|
||||
}
|
||||
if (hasWitness) {
|
||||
/* The witness flag is present, and we support witnesses. */
|
||||
for (size_t i = 0; i < vin.size(); i++) {
|
||||
fc::raw::unpack(ds, vin[i].scriptWitness);
|
||||
}
|
||||
}
|
||||
ds.direct_read(nLockTime);
|
||||
}
|
||||
|
||||
bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, const bytes& redeem_script, const std::vector<fc::optional<fc::ecc::private_key> > &priv_keys)
|
||||
{
|
||||
btc_tx tx;
|
||||
tx.fill_from_bytes(unsigned_tx);
|
||||
fc::ecc::compact_signature dummy;
|
||||
fc::ecc::compact_signature dummy_sig;
|
||||
bytes dummy_data(dummy_sig.begin(), dummy_sig.begin() + dummy_sig.size());
|
||||
for(auto& in: tx.vin)
|
||||
{
|
||||
WriteBytesStream script(in.scriptSig);
|
||||
|
|
@ -236,16 +401,18 @@ bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, const bytes& redeem
|
|||
if(key)
|
||||
{
|
||||
bytes signature = signature_for_raw_transaction(unsigned_tx, *key);
|
||||
script.add(signature);
|
||||
script.writedata(signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
script.add(dummy.begin(), dummy.size());
|
||||
script.writedata(dummy_data);
|
||||
}
|
||||
}
|
||||
script.add(redeem_script);
|
||||
script.writedata(redeem_script);
|
||||
}
|
||||
return tx.to_bytes();
|
||||
bytes ret;
|
||||
tx.to_bytes(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ enum bitcoin_network {
|
|||
regtest
|
||||
};
|
||||
|
||||
bytes generate_redeem_script(fc::flat_map<fc::ecc::public_key, int> key_data);
|
||||
bytes generate_redeem_script(std::vector<std::pair<fc::ecc::public_key, int> > key_data);
|
||||
std::string p2sh_address_from_redeem_script(const bytes& script, bitcoin_network network = mainnet);
|
||||
bytes lock_script_for_redeem_script(const bytes& script);
|
||||
/*
|
||||
* unsigned_tx - tx, all inputs of which are spends of the PW P2SH address
|
||||
* returns signed transaction
|
||||
|
|
@ -22,6 +23,9 @@ struct btc_outpoint
|
|||
{
|
||||
fc::uint256 hash;
|
||||
uint32_t n;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
};
|
||||
|
||||
struct btc_in
|
||||
|
|
@ -30,12 +34,18 @@ struct btc_in
|
|||
bytes scriptSig;
|
||||
uint32_t nSequence;
|
||||
bytes scriptWitness;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
};
|
||||
|
||||
struct btc_out
|
||||
{
|
||||
int64_t nValue;
|
||||
bytes scriptPubKey;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
};
|
||||
|
||||
struct btc_tx
|
||||
|
|
@ -46,14 +56,9 @@ struct btc_tx
|
|||
uint32_t nLockTime;
|
||||
bool hasWitness;
|
||||
|
||||
bytes to_bytes() const;
|
||||
void fill_from_bytes(const bytes& data);
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
FC_REFLECT(graphene::peerplays_sidechain::btc_outpoint, (hash)(n))
|
||||
// btc_in::scriptWitness is filled only in transaction serialization
|
||||
FC_REFLECT(graphene::peerplays_sidechain::btc_in, (prevout)(scriptSig)(nSequence))
|
||||
FC_REFLECT(graphene::peerplays_sidechain::btc_out, (nValue)(scriptPubKey))
|
||||
// btc_tx is serialized manually
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
#include <graphene/peerplays_sidechain/bitcoin_utils.hpp>
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/crypto/elliptic.hpp>
|
||||
|
||||
using namespace graphene::peerplays_sidechain;
|
||||
|
||||
|
|
@ -20,6 +21,88 @@ BOOST_AUTO_TEST_CASE(tx_serialization)
|
|||
BOOST_CHECK(tx.nLockTime == 0);
|
||||
BOOST_CHECK(tx.vin.size() == 1);
|
||||
BOOST_CHECK(tx.vout.size() == 2);
|
||||
bytes buff = tx.to_bytes();
|
||||
bytes buff;
|
||||
tx.to_bytes(buff);
|
||||
BOOST_CHECK(bintx == buff);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(pw_transfer)
|
||||
{
|
||||
// key set for the old Primary Wallet
|
||||
std::vector<fc::ecc::private_key> priv_old;
|
||||
for(unsigned i = 0; i < 15; ++i)
|
||||
{
|
||||
const char* seed = reinterpret_cast<const char*>(&i);
|
||||
fc::sha256 h = fc::sha256::hash(seed, sizeof(i));
|
||||
priv_old.push_back(fc::ecc::private_key::generate_from_seed(h));
|
||||
}
|
||||
std::vector<fc::ecc::public_key> pub_old;
|
||||
for(auto& key: priv_old)
|
||||
pub_old.push_back(key.get_public_key());
|
||||
// old key weights
|
||||
std::vector<std::pair<fc::ecc::public_key, int> > weights_old;
|
||||
for(unsigned i = 0; i < 15; ++i)
|
||||
weights_old.push_back(std::make_pair(pub_old[i], i + 1));
|
||||
// redeem script for old PW
|
||||
bytes redeem_old =generate_redeem_script(weights_old);
|
||||
// Old PW address
|
||||
std::string old_pw = p2sh_address_from_redeem_script(redeem_old, bitcoin_network::testnet);
|
||||
// This address was filled with testnet transaction 8d8a466f6c829175a8bb747860828b59e7774be0bbf79ffdc70d5e75348180ca
|
||||
BOOST_REQUIRE(old_pw == "2NGLS3x8Vk3vN18672YmSnpASm7FxYcoWu6");
|
||||
|
||||
// key set for the new Primary Wallet
|
||||
std::vector<fc::ecc::private_key> priv_new;
|
||||
for(unsigned i = 16; i < 31; ++i)
|
||||
{
|
||||
const char* seed = reinterpret_cast<const char*>(&i);
|
||||
fc::sha256 h = fc::sha256::hash(seed, sizeof(i));
|
||||
priv_new.push_back(fc::ecc::private_key::generate_from_seed(h));
|
||||
}
|
||||
std::vector<fc::ecc::public_key> pub_new;
|
||||
for(auto& key: priv_new)
|
||||
pub_new.push_back(key.get_public_key());
|
||||
// new key weights
|
||||
std::vector<std::pair<fc::ecc::public_key, int> > weights_new;
|
||||
for(unsigned i = 0; i < 15; ++i)
|
||||
weights_new.push_back(std::make_pair(pub_new[i], 16 - i));
|
||||
// redeem script for new PW
|
||||
bytes redeem_new =generate_redeem_script(weights_new);
|
||||
// New PW address
|
||||
std::string new_pw = p2sh_address_from_redeem_script(redeem_new, bitcoin_network::testnet);
|
||||
|
||||
BOOST_REQUIRE(new_pw == "2MyzbFRwNqj1Y4Q4oWELhDwz5DCHkTndE1S");
|
||||
|
||||
// try to move funds from old wallet to new one
|
||||
|
||||
// get unspent outputs for old wallet with list_uspent (address should be
|
||||
// added to wallet with import_address before). It should return
|
||||
// 1 UTXO: [8d8a466f6c829175a8bb747860828b59e7774be0bbf79ffdc70d5e75348180ca:1]
|
||||
// with 20000 satoshis
|
||||
// So, we creating a raw transaction with 1 input and one output that gets
|
||||
// 20000 - fee satoshis with createrawtransaction call (bitcoin_rpc_client::prepare_tx)
|
||||
// Here we just serialize the transaction without scriptSig in inputs then sign it.
|
||||
btc_outpoint outpoint;
|
||||
outpoint.hash = fc::uint256("8d8a466f6c829175a8bb747860828b59e7774be0bbf79ffdc70d5e75348180ca");
|
||||
// reverse hash due to the different from_hex algo
|
||||
std::reverse(outpoint.hash.data(), outpoint.hash.data() + outpoint.hash.data_size());
|
||||
outpoint.n = 1;
|
||||
btc_in input;
|
||||
input.prevout = outpoint;
|
||||
input.nSequence = 0xffffffff;
|
||||
btc_out output;
|
||||
output.nValue = 19000;
|
||||
output.scriptPubKey = lock_script_for_redeem_script(redeem_new);
|
||||
btc_tx tx;
|
||||
tx.nVersion = 2;
|
||||
tx.nLockTime = 0;
|
||||
tx.hasWitness = false;
|
||||
tx.vin.push_back(input);
|
||||
tx.vout.push_back(output);
|
||||
bytes unsigned_tx;
|
||||
tx.to_bytes(unsigned_tx);
|
||||
std::vector<fc::optional<fc::ecc::private_key>> keys_to_sign;
|
||||
for(auto key: priv_old)
|
||||
keys_to_sign.push_back(fc::optional<fc::ecc::private_key>(key));
|
||||
bytes signed_tx =sign_pw_transfer_transaction(unsigned_tx, redeem_old, keys_to_sign);
|
||||
ilog(fc::to_hex(reinterpret_cast<char*>(&signed_tx[0]), signed_tx.size()));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue