signing PW spending transaction
This commit is contained in:
parent
7e61feb2be
commit
866e9b6158
2 changed files with 196 additions and 4 deletions
|
|
@ -16,13 +16,33 @@ static const unsigned char OP_CHECKSIG = 0xac;
|
|||
|
||||
class WriteBytesStream{
|
||||
public:
|
||||
WriteBytesStream(bytes& buffer);
|
||||
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 ) {
|
||||
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) {
|
||||
storage_.push_back(c);
|
||||
return true;
|
||||
|
|
@ -31,6 +51,59 @@ private:
|
|||
bytes& storage_;
|
||||
};
|
||||
|
||||
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 ) {
|
||||
if( end_ - pos_ >= s ) {
|
||||
memcpy( d, &storage_[pos_], s );
|
||||
pos_ += s;
|
||||
return true;
|
||||
}
|
||||
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 )
|
||||
{
|
||||
if( pos_ < end_ ) {
|
||||
c = storage_[pos_++];
|
||||
return true;
|
||||
}
|
||||
FC_THROW( "invalid bitcoin tx buffer" );
|
||||
}
|
||||
private:
|
||||
const bytes& storage_;
|
||||
size_t pos_;
|
||||
size_t end_;
|
||||
};
|
||||
|
||||
void add_data_to_script(bytes& script, const bytes& data)
|
||||
{
|
||||
|
|
@ -89,9 +162,123 @@ 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 sign_raw_transaction(const bytes& unsigned_tx, const fc::ecc::private_key& priv_key)
|
||||
bytes signature_for_raw_transaction(const bytes& unsigned_tx, const fc::ecc::private_key& priv_key)
|
||||
{
|
||||
return bytes();
|
||||
fc::sha256 digest = fc::sha256::hash(fc::sha256::hash(reinterpret_cast<const char*>(&unsigned_tx[0]), unsigned_tx.size()));
|
||||
fc::ecc::compact_signature res = priv_key.sign_compact(digest);
|
||||
return bytes(res.begin(), res.begin() + res.size());
|
||||
}
|
||||
|
||||
struct btc_outpoint
|
||||
{
|
||||
fc::uint256 hash;
|
||||
uint32_t n;
|
||||
};
|
||||
|
||||
struct btc_in
|
||||
{
|
||||
btc_outpoint prevout;
|
||||
bytes scriptSig;
|
||||
uint32_t nSequence;
|
||||
bytes scriptWitness;
|
||||
};
|
||||
|
||||
struct btc_out
|
||||
{
|
||||
int64_t nValue;
|
||||
bytes scriptPubKey;
|
||||
};
|
||||
|
||||
struct btc_tx
|
||||
{
|
||||
std::vector<btc_in> vin;
|
||||
std::vector<btc_out> vout;
|
||||
int32_t nVersion;
|
||||
uint32_t nLockTime;
|
||||
bool hasWitness;
|
||||
|
||||
bytes 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 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;
|
||||
for(auto& in: tx.vin)
|
||||
{
|
||||
WriteBytesStream script(in.scriptSig);
|
||||
for(auto key: priv_keys)
|
||||
{
|
||||
if(key)
|
||||
{
|
||||
bytes signature = signature_for_raw_transaction(unsigned_tx, *key);
|
||||
script.add(signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
script.add(dummy.begin(), dummy.size());
|
||||
}
|
||||
}
|
||||
script.add(redeem_script);
|
||||
}
|
||||
return tx.to_bytes();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
FC_REFLECT(graphene::peerplays_sidechain::btc_outpoint, (hash)(n))
|
||||
FC_REFLECT(graphene::peerplays_sidechain::btc_in, (prevout)(scriptSig)(nSequence))
|
||||
FC_REFLECT(graphene::peerplays_sidechain::btc_out, (nValue)(scriptPubKey))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <graphene/peerplays_sidechain/defs.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
|
|
@ -11,6 +12,10 @@ enum bitcoin_network {
|
|||
|
||||
bytes generate_redeem_script(fc::flat_map<fc::ecc::public_key, int> key_data);
|
||||
std::string p2sh_address_from_redeem_script(const bytes& script, bitcoin_network network = mainnet);
|
||||
bytes sign_raw_transaction(const bytes& unsigned_tx, const fc::ecc::private_key& priv_key);
|
||||
/*
|
||||
* unsigned_tx - tx, all inputs of which are spends of the PW P2SH address
|
||||
* returns signed transaction
|
||||
*/
|
||||
bytes sign_pw_transfer_transaction(const bytes& unsigned_tx, const bytes& redeem_script, const std::vector<fc::optional<fc::ecc::private_key>>& priv_keys);
|
||||
|
||||
}}
|
||||
|
|
|
|||
Loading…
Reference in a new issue