Compare commits
14 commits
master
...
feature/SO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e66ab768ca | ||
|
|
297d7cbba2 | ||
|
|
a92071890b | ||
|
|
57a9675282 | ||
|
|
da0b3fafd2 | ||
|
|
ffeddc2a33 | ||
|
|
9dc1211bbf | ||
|
|
1625129bbe | ||
|
|
001f92127b | ||
|
|
47c10f0db0 | ||
|
|
205689378b | ||
|
|
5dcf3f9be3 | ||
|
|
6f75d811b7 | ||
|
|
e9a26de347 |
13 changed files with 1307 additions and 1241 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
#include <graphene/peerplays_sidechain/bitcoin_utils.hpp>
|
|
||||||
#include <fc/io/raw.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>
|
||||||
#include <fc/crypto/sha256.hpp>
|
#include <fc/crypto/sha256.hpp>
|
||||||
|
#include <fc/io/raw.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/bitcoin_utils.hpp>
|
||||||
#include <secp256k1.h>
|
#include <secp256k1.h>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
@ -37,7 +37,9 @@ static const unsigned char OP_CHECKSIG = 0xac;
|
||||||
|
|
||||||
class WriteBytesStream {
|
class WriteBytesStream {
|
||||||
public:
|
public:
|
||||||
WriteBytesStream(bytes& buffer) : storage_(buffer) {}
|
WriteBytesStream(bytes &buffer) :
|
||||||
|
storage_(buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
void write(const unsigned char *d, size_t s) {
|
void write(const unsigned char *d, size_t s) {
|
||||||
storage_.insert(storage_.end(), d, d + s);
|
storage_.insert(storage_.end(), d, d + s);
|
||||||
|
|
@ -48,68 +50,61 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writedata8(uint8_t obj)
|
void writedata8(uint8_t obj) {
|
||||||
{
|
|
||||||
write((unsigned char *)&obj, 1);
|
write((unsigned char *)&obj, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writedata16(uint16_t obj)
|
void writedata16(uint16_t obj) {
|
||||||
{
|
|
||||||
obj = htole16(obj);
|
obj = htole16(obj);
|
||||||
write((unsigned char *)&obj, 2);
|
write((unsigned char *)&obj, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writedata32(uint32_t obj)
|
void writedata32(uint32_t obj) {
|
||||||
{
|
|
||||||
obj = htole32(obj);
|
obj = htole32(obj);
|
||||||
write((unsigned char *)&obj, 4);
|
write((unsigned char *)&obj, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writedata64(uint64_t obj)
|
void writedata64(uint64_t obj) {
|
||||||
{
|
|
||||||
obj = htole64(obj);
|
obj = htole64(obj);
|
||||||
write((unsigned char *)&obj, 8);
|
write((unsigned char *)&obj, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_compact_int(uint64_t val)
|
void write_compact_int(uint64_t val) {
|
||||||
{
|
if (val < 253) {
|
||||||
if (val < 253)
|
|
||||||
{
|
|
||||||
writedata8(val);
|
writedata8(val);
|
||||||
}
|
} else if (val <= std::numeric_limits<unsigned short>::max()) {
|
||||||
else if (val <= std::numeric_limits<unsigned short>::max())
|
|
||||||
{
|
|
||||||
writedata8(253);
|
writedata8(253);
|
||||||
writedata16(val);
|
writedata16(val);
|
||||||
}
|
} else if (val <= std::numeric_limits<unsigned int>::max()) {
|
||||||
else if (val <= std::numeric_limits<unsigned int>::max())
|
|
||||||
{
|
|
||||||
writedata8(254);
|
writedata8(254);
|
||||||
writedata32(val);
|
writedata32(val);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
writedata8(255);
|
writedata8(255);
|
||||||
writedata64(val);
|
writedata64(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writedata(const bytes& data)
|
void writedata(const bytes &data) {
|
||||||
{
|
|
||||||
write_compact_int(data.size());
|
write_compact_int(data.size());
|
||||||
write(&data[0], data.size());
|
write(&data[0], data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bytes &storage_;
|
bytes &storage_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReadBytesStream {
|
class ReadBytesStream {
|
||||||
public:
|
public:
|
||||||
ReadBytesStream(const bytes& buffer, size_t pos = 0) : storage_(buffer), pos_(pos), end_(buffer.size()) {}
|
ReadBytesStream(const bytes &buffer, size_t pos = 0) :
|
||||||
|
storage_(buffer),
|
||||||
|
pos_(pos),
|
||||||
|
end_(buffer.size()) {
|
||||||
|
}
|
||||||
|
|
||||||
size_t current_pos() const { return pos_; }
|
size_t current_pos() const {
|
||||||
void set_pos(size_t pos)
|
return pos_;
|
||||||
{
|
}
|
||||||
|
void set_pos(size_t pos) {
|
||||||
if (pos > end_)
|
if (pos > end_)
|
||||||
FC_THROW("Invalid position in BTC tx buffer");
|
FC_THROW("Invalid position in BTC tx buffer");
|
||||||
pos_ = pos;
|
pos_ = pos;
|
||||||
|
|
@ -124,8 +119,7 @@ public:
|
||||||
FC_THROW("invalid bitcoin tx buffer");
|
FC_THROW("invalid bitcoin tx buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool get( unsigned char& c )
|
inline bool get(unsigned char &c) {
|
||||||
{
|
|
||||||
if (pos_ < end_) {
|
if (pos_ < end_) {
|
||||||
c = storage_[pos_++];
|
c = storage_[pos_++];
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -133,53 +127,41 @@ public:
|
||||||
FC_THROW("invalid bitcoin tx buffer");
|
FC_THROW("invalid bitcoin tx buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t readdata8()
|
uint8_t readdata8() {
|
||||||
{
|
|
||||||
uint8_t obj;
|
uint8_t obj;
|
||||||
read((unsigned char *)&obj, 1);
|
read((unsigned char *)&obj, 1);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
uint16_t readdata16()
|
uint16_t readdata16() {
|
||||||
{
|
|
||||||
uint16_t obj;
|
uint16_t obj;
|
||||||
read((unsigned char *)&obj, 2);
|
read((unsigned char *)&obj, 2);
|
||||||
return le16toh(obj);
|
return le16toh(obj);
|
||||||
}
|
}
|
||||||
uint32_t readdata32()
|
uint32_t readdata32() {
|
||||||
{
|
|
||||||
uint32_t obj;
|
uint32_t obj;
|
||||||
read((unsigned char *)&obj, 4);
|
read((unsigned char *)&obj, 4);
|
||||||
return le32toh(obj);
|
return le32toh(obj);
|
||||||
}
|
}
|
||||||
uint64_t readdata64()
|
uint64_t readdata64() {
|
||||||
{
|
|
||||||
uint64_t obj;
|
uint64_t obj;
|
||||||
read((unsigned char *)&obj, 8);
|
read((unsigned char *)&obj, 8);
|
||||||
return le64toh(obj);
|
return le64toh(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t read_compact_int()
|
uint64_t read_compact_int() {
|
||||||
{
|
|
||||||
uint8_t size = readdata8();
|
uint8_t size = readdata8();
|
||||||
uint64_t ret = 0;
|
uint64_t ret = 0;
|
||||||
if (size < 253)
|
if (size < 253) {
|
||||||
{
|
|
||||||
ret = size;
|
ret = size;
|
||||||
}
|
} else if (size == 253) {
|
||||||
else if (size == 253)
|
|
||||||
{
|
|
||||||
ret = readdata16();
|
ret = readdata16();
|
||||||
if (ret < 253)
|
if (ret < 253)
|
||||||
FC_THROW("non-canonical ReadCompactSize()");
|
FC_THROW("non-canonical ReadCompactSize()");
|
||||||
}
|
} else if (size == 254) {
|
||||||
else if (size == 254)
|
|
||||||
{
|
|
||||||
ret = readdata32();
|
ret = readdata32();
|
||||||
if (ret < 0x10000u)
|
if (ret < 0x10000u)
|
||||||
FC_THROW("non-canonical ReadCompactSize()");
|
FC_THROW("non-canonical ReadCompactSize()");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = readdata64();
|
ret = readdata64();
|
||||||
if (ret < 0x100000000ULL)
|
if (ret < 0x100000000ULL)
|
||||||
FC_THROW("non-canonical ReadCompactSize()");
|
FC_THROW("non-canonical ReadCompactSize()");
|
||||||
|
|
@ -189,8 +171,7 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readdata(bytes& data)
|
void readdata(bytes &data) {
|
||||||
{
|
|
||||||
size_t s = read_compact_int();
|
size_t s = read_compact_int();
|
||||||
data.clear();
|
data.clear();
|
||||||
data.resize(s);
|
data.resize(s);
|
||||||
|
|
@ -203,16 +184,14 @@ private:
|
||||||
size_t end_;
|
size_t end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void btc_outpoint::to_bytes(bytes& stream) const
|
void btc_outpoint::to_bytes(bytes &stream) const {
|
||||||
{
|
|
||||||
WriteBytesStream str(stream);
|
WriteBytesStream str(stream);
|
||||||
// TODO: write size?
|
// TODO: write size?
|
||||||
str.write((unsigned char *)hash.data(), hash.data_size());
|
str.write((unsigned char *)hash.data(), hash.data_size());
|
||||||
str.writedata32(n);
|
str.writedata32(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t btc_outpoint::fill_from_bytes(const bytes& data, size_t pos)
|
size_t btc_outpoint::fill_from_bytes(const bytes &data, size_t pos) {
|
||||||
{
|
|
||||||
ReadBytesStream str(data, pos);
|
ReadBytesStream str(data, pos);
|
||||||
// TODO: read size?
|
// TODO: read size?
|
||||||
str.read((unsigned char *)hash.data(), hash.data_size());
|
str.read((unsigned char *)hash.data(), hash.data_size());
|
||||||
|
|
@ -220,16 +199,14 @@ size_t btc_outpoint::fill_from_bytes(const bytes& data, size_t pos)
|
||||||
return str.current_pos();
|
return str.current_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
void btc_in::to_bytes(bytes& stream) const
|
void btc_in::to_bytes(bytes &stream) const {
|
||||||
{
|
|
||||||
prevout.to_bytes(stream);
|
prevout.to_bytes(stream);
|
||||||
WriteBytesStream str(stream);
|
WriteBytesStream str(stream);
|
||||||
str.writedata(scriptSig);
|
str.writedata(scriptSig);
|
||||||
str.writedata32(nSequence);
|
str.writedata32(nSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t btc_in::fill_from_bytes(const bytes& data, size_t pos)
|
size_t btc_in::fill_from_bytes(const bytes &data, size_t pos) {
|
||||||
{
|
|
||||||
pos = prevout.fill_from_bytes(data, pos);
|
pos = prevout.fill_from_bytes(data, pos);
|
||||||
ReadBytesStream str(data, pos);
|
ReadBytesStream str(data, pos);
|
||||||
str.readdata(scriptSig);
|
str.readdata(scriptSig);
|
||||||
|
|
@ -237,27 +214,23 @@ size_t btc_in::fill_from_bytes(const bytes& data, size_t pos)
|
||||||
return str.current_pos();
|
return str.current_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
void btc_out::to_bytes(bytes& stream) const
|
void btc_out::to_bytes(bytes &stream) const {
|
||||||
{
|
|
||||||
WriteBytesStream str(stream);
|
WriteBytesStream str(stream);
|
||||||
str.writedata64(nValue);
|
str.writedata64(nValue);
|
||||||
str.writedata(scriptPubKey);
|
str.writedata(scriptPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t btc_out::fill_from_bytes(const bytes& data, size_t pos)
|
size_t btc_out::fill_from_bytes(const bytes &data, size_t pos) {
|
||||||
{
|
|
||||||
ReadBytesStream str(data, pos);
|
ReadBytesStream str(data, pos);
|
||||||
nValue = str.readdata64();
|
nValue = str.readdata64();
|
||||||
str.readdata(scriptPubKey);
|
str.readdata(scriptPubKey);
|
||||||
return str.current_pos();
|
return str.current_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
void btc_tx::to_bytes(bytes& stream) const
|
void btc_tx::to_bytes(bytes &stream) const {
|
||||||
{
|
|
||||||
WriteBytesStream str(stream);
|
WriteBytesStream str(stream);
|
||||||
str.writedata32(nVersion);
|
str.writedata32(nVersion);
|
||||||
if(hasWitness)
|
if (hasWitness) {
|
||||||
{
|
|
||||||
// write dummy inputs and flag
|
// write dummy inputs and flag
|
||||||
str.write_compact_int(0);
|
str.write_compact_int(0);
|
||||||
unsigned char flags = 1;
|
unsigned char flags = 1;
|
||||||
|
|
@ -269,10 +242,8 @@ void btc_tx::to_bytes(bytes& stream) const
|
||||||
str.write_compact_int(vout.size());
|
str.write_compact_int(vout.size());
|
||||||
for (const auto &out : vout)
|
for (const auto &out : vout)
|
||||||
out.to_bytes(stream);
|
out.to_bytes(stream);
|
||||||
if(hasWitness)
|
if (hasWitness) {
|
||||||
{
|
for (const auto &in : vin) {
|
||||||
for(const auto& in: vin)
|
|
||||||
{
|
|
||||||
str.write_compact_int(in.scriptWitness.size());
|
str.write_compact_int(in.scriptWitness.size());
|
||||||
for (const auto &stack_item : in.scriptWitness)
|
for (const auto &stack_item : in.scriptWitness)
|
||||||
str.writedata(stack_item);
|
str.writedata(stack_item);
|
||||||
|
|
@ -281,8 +252,7 @@ void btc_tx::to_bytes(bytes& stream) const
|
||||||
str.writedata32(nLockTime);
|
str.writedata32(nLockTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t btc_tx::fill_from_bytes(const bytes& data, size_t pos)
|
size_t btc_tx::fill_from_bytes(const bytes &data, size_t pos) {
|
||||||
{
|
|
||||||
ReadBytesStream ds(data, pos);
|
ReadBytesStream ds(data, pos);
|
||||||
nVersion = ds.readdata32();
|
nVersion = ds.readdata32();
|
||||||
unsigned char flags = 0;
|
unsigned char flags = 0;
|
||||||
|
|
@ -325,8 +295,7 @@ size_t btc_tx::fill_from_bytes(const bytes& data, size_t pos)
|
||||||
}
|
}
|
||||||
if (hasWitness) {
|
if (hasWitness) {
|
||||||
/* The witness flag is present, and we support witnesses. */
|
/* The witness flag is present, and we support witnesses. */
|
||||||
for (auto& in: vin)
|
for (auto &in : vin) {
|
||||||
{
|
|
||||||
unsigned int size = ds.read_compact_int();
|
unsigned int size = ds.read_compact_int();
|
||||||
in.scriptWitness.resize(size);
|
in.scriptWitness.resize(size);
|
||||||
for (auto &stack_item : in.scriptWitness)
|
for (auto &stack_item : in.scriptWitness)
|
||||||
|
|
@ -337,15 +306,12 @@ size_t btc_tx::fill_from_bytes(const bytes& data, size_t pos)
|
||||||
return ds.current_pos();
|
return ds.current_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_data_to_script(bytes &script, const bytes &data) {
|
||||||
void add_data_to_script(bytes& script, const bytes& data)
|
|
||||||
{
|
|
||||||
WriteBytesStream str(script);
|
WriteBytesStream str(script);
|
||||||
str.writedata(data);
|
str.writedata(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_number_to_script(bytes& script, unsigned char data)
|
void add_number_to_script(bytes &script, unsigned char data) {
|
||||||
{
|
|
||||||
WriteBytesStream str(script);
|
WriteBytesStream str(script);
|
||||||
if (data == 0)
|
if (data == 0)
|
||||||
str.put(OP_0);
|
str.put(OP_0);
|
||||||
|
|
@ -385,13 +351,11 @@ void add_number_to_script(bytes& script, unsigned char data)
|
||||||
add_data_to_script(script, {data});
|
add_data_to_script(script, {data});
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes generate_redeem_script(std::vector<std::pair<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;
|
int total_weight = 0;
|
||||||
bytes result;
|
bytes result;
|
||||||
add_number_to_script(result, 0);
|
add_number_to_script(result, 0);
|
||||||
for(auto& p: key_data)
|
for (auto &p : key_data) {
|
||||||
{
|
|
||||||
total_weight += p.second;
|
total_weight += p.second;
|
||||||
result.push_back(OP_SWAP);
|
result.push_back(OP_SWAP);
|
||||||
auto raw_data = p.first.serialize();
|
auto raw_data = p.first.serialize();
|
||||||
|
|
@ -487,7 +451,8 @@ bool convertbits(bytes& out, const bytes& in) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pad) {
|
if (pad) {
|
||||||
if (bits) out.push_back((acc << (tobits - bits)) & maxv);
|
if (bits)
|
||||||
|
out.push_back((acc << (tobits - bits)) & maxv);
|
||||||
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
|
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -503,8 +468,7 @@ std::string segwit_addr_encode(const std::string& hrp, uint8_t witver, const byt
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string p2wsh_address_from_redeem_script(const bytes& script, bitcoin_network network)
|
std::string p2wsh_address_from_redeem_script(const bytes &script, bitcoin_network network) {
|
||||||
{
|
|
||||||
// calc script hash
|
// calc script hash
|
||||||
fc::sha256 sh = fc::sha256::hash(reinterpret_cast<const char *>(&script[0]), script.size());
|
fc::sha256 sh = fc::sha256::hash(reinterpret_cast<const char *>(&script[0]), script.size());
|
||||||
bytes wp(sh.data(), sh.data() + sh.data_size());
|
bytes wp(sh.data(), sh.data() + sh.data_size());
|
||||||
|
|
@ -520,8 +484,7 @@ std::string p2wsh_address_from_redeem_script(const bytes& script, bitcoin_networ
|
||||||
FC_THROW("Unknown bitcoin network type");
|
FC_THROW("Unknown bitcoin network type");
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes lock_script_for_redeem_script(const bytes &script)
|
bytes lock_script_for_redeem_script(const bytes &script) {
|
||||||
{
|
|
||||||
bytes result;
|
bytes result;
|
||||||
result.push_back(OP_0);
|
result.push_back(OP_0);
|
||||||
fc::sha256 h = fc::sha256::hash(reinterpret_cast<const char *>(&script[0]), script.size());
|
fc::sha256 h = fc::sha256::hash(reinterpret_cast<const char *>(&script[0]), script.size());
|
||||||
|
|
@ -530,11 +493,9 @@ bytes lock_script_for_redeem_script(const bytes &script)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes hash_prevouts(const btc_tx& unsigned_tx)
|
bytes hash_prevouts(const btc_tx &unsigned_tx) {
|
||||||
{
|
|
||||||
fc::sha256::encoder hasher;
|
fc::sha256::encoder hasher;
|
||||||
for(const auto& in: unsigned_tx.vin)
|
for (const auto &in : unsigned_tx.vin) {
|
||||||
{
|
|
||||||
bytes data;
|
bytes data;
|
||||||
in.prevout.to_bytes(data);
|
in.prevout.to_bytes(data);
|
||||||
hasher.write(reinterpret_cast<const char *>(&data[0]), data.size());
|
hasher.write(reinterpret_cast<const char *>(&data[0]), data.size());
|
||||||
|
|
@ -543,22 +504,18 @@ bytes hash_prevouts(const btc_tx& unsigned_tx)
|
||||||
return bytes(res.data(), res.data() + res.data_size());
|
return bytes(res.data(), res.data() + res.data_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes hash_sequence(const btc_tx& unsigned_tx)
|
bytes hash_sequence(const btc_tx &unsigned_tx) {
|
||||||
{
|
|
||||||
fc::sha256::encoder hasher;
|
fc::sha256::encoder hasher;
|
||||||
for(const auto& in: unsigned_tx.vin)
|
for (const auto &in : unsigned_tx.vin) {
|
||||||
{
|
|
||||||
hasher.write(reinterpret_cast<const char *>(&in.nSequence), sizeof(in.nSequence));
|
hasher.write(reinterpret_cast<const char *>(&in.nSequence), sizeof(in.nSequence));
|
||||||
}
|
}
|
||||||
fc::sha256 res = fc::sha256::hash(hasher.result());
|
fc::sha256 res = fc::sha256::hash(hasher.result());
|
||||||
return bytes(res.data(), res.data() + res.data_size());
|
return bytes(res.data(), res.data() + res.data_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes hash_outputs(const btc_tx& unsigned_tx)
|
bytes hash_outputs(const btc_tx &unsigned_tx) {
|
||||||
{
|
|
||||||
fc::sha256::encoder hasher;
|
fc::sha256::encoder hasher;
|
||||||
for(const auto& out: unsigned_tx.vout)
|
for (const auto &out : unsigned_tx.vout) {
|
||||||
{
|
|
||||||
bytes data;
|
bytes data;
|
||||||
out.to_bytes(data);
|
out.to_bytes(data);
|
||||||
hasher.write(reinterpret_cast<const char *>(&data[0]), data.size());
|
hasher.write(reinterpret_cast<const char *>(&data[0]), data.size());
|
||||||
|
|
@ -572,8 +529,7 @@ const secp256k1_context_t* btc_get_context() {
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes der_sign(const fc::ecc::private_key& priv_key, const fc::sha256& digest)
|
bytes der_sign(const fc::ecc::private_key &priv_key, const fc::sha256 &digest) {
|
||||||
{
|
|
||||||
fc::ecc::signature result;
|
fc::ecc::signature result;
|
||||||
int size = result.size();
|
int size = result.size();
|
||||||
FC_ASSERT(secp256k1_ecdsa_sign(btc_get_context(),
|
FC_ASSERT(secp256k1_ecdsa_sign(btc_get_context(),
|
||||||
|
|
@ -589,8 +545,7 @@ bytes der_sign(const fc::ecc::private_key& priv_key, const fc::sha256& digest)
|
||||||
std::vector<bytes> signatures_for_raw_transaction(const bytes &unsigned_tx,
|
std::vector<bytes> signatures_for_raw_transaction(const bytes &unsigned_tx,
|
||||||
std::vector<uint64_t> in_amounts,
|
std::vector<uint64_t> in_amounts,
|
||||||
const bytes &redeem_script,
|
const bytes &redeem_script,
|
||||||
const fc::ecc::private_key& priv_key)
|
const fc::ecc::private_key &priv_key) {
|
||||||
{
|
|
||||||
btc_tx tx;
|
btc_tx tx;
|
||||||
tx.fill_from_bytes(unsigned_tx);
|
tx.fill_from_bytes(unsigned_tx);
|
||||||
|
|
||||||
|
|
@ -604,8 +559,7 @@ std::vector<bytes> signatures_for_raw_transaction(const bytes& unsigned_tx,
|
||||||
bytes hashOutputs = hash_outputs(tx);
|
bytes hashOutputs = hash_outputs(tx);
|
||||||
// calc digest for every input according to BIP143
|
// calc digest for every input according to BIP143
|
||||||
// implement SIGHASH_ALL scheme
|
// implement SIGHASH_ALL scheme
|
||||||
for(const auto& in: tx.vin)
|
for (const auto &in : tx.vin) {
|
||||||
{
|
|
||||||
fc::sha256::encoder hasher;
|
fc::sha256::encoder hasher;
|
||||||
hasher.write(reinterpret_cast<const char *>(&tx.nVersion), sizeof(tx.nVersion));
|
hasher.write(reinterpret_cast<const char *>(&tx.nVersion), sizeof(tx.nVersion));
|
||||||
hasher.write(reinterpret_cast<const char *>(&hashPrevouts[0]), hashPrevouts.size());
|
hasher.write(reinterpret_cast<const char *>(&hashPrevouts[0]), hashPrevouts.size());
|
||||||
|
|
@ -636,30 +590,24 @@ std::vector<bytes> signatures_for_raw_transaction(const bytes& unsigned_tx,
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, std::vector<uint64_t> in_amounts, const bytes& redeem_script, const std::vector<fc::optional<fc::ecc::private_key> > &priv_keys)
|
bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, std::vector<uint64_t> in_amounts, const bytes &redeem_script, const std::vector<fc::optional<fc::ecc::private_key>> &priv_keys) {
|
||||||
{
|
|
||||||
btc_tx tx;
|
btc_tx tx;
|
||||||
tx.fill_from_bytes(unsigned_tx);
|
tx.fill_from_bytes(unsigned_tx);
|
||||||
bytes dummy_data;
|
bytes dummy_data;
|
||||||
for(auto key: priv_keys)
|
for (auto key : priv_keys) {
|
||||||
{
|
if (key) {
|
||||||
if(key)
|
|
||||||
{
|
|
||||||
std::vector<bytes> signatures = signatures_for_raw_transaction(unsigned_tx, in_amounts, redeem_script, *key);
|
std::vector<bytes> signatures = signatures_for_raw_transaction(unsigned_tx, in_amounts, redeem_script, *key);
|
||||||
FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number");
|
FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number");
|
||||||
// push signatures in reverse order because script starts to check the top signature on the stack first
|
// push signatures in reverse order because script starts to check the top signature on the stack first
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]);
|
tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
tx.vin[i].scriptWitness.push_back(dummy_data);
|
tx.vin[i].scriptWitness.push_back(dummy_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& in: tx.vin)
|
for (auto &in : tx.vin) {
|
||||||
{
|
|
||||||
in.scriptWitness.push_back(redeem_script);
|
in.scriptWitness.push_back(redeem_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -671,14 +619,12 @@ bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, std::vector<uint64_
|
||||||
|
|
||||||
bytes add_dummy_signatures_for_pw_transfer(const bytes &unsigned_tx,
|
bytes add_dummy_signatures_for_pw_transfer(const bytes &unsigned_tx,
|
||||||
const bytes &redeem_script,
|
const bytes &redeem_script,
|
||||||
unsigned int key_count)
|
unsigned int key_count) {
|
||||||
{
|
|
||||||
btc_tx tx;
|
btc_tx tx;
|
||||||
tx.fill_from_bytes(unsigned_tx);
|
tx.fill_from_bytes(unsigned_tx);
|
||||||
|
|
||||||
bytes dummy_data;
|
bytes dummy_data;
|
||||||
for(auto& in: tx.vin)
|
for (auto &in : tx.vin) {
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < key_count; i++)
|
for (unsigned i = 0; i < key_count; i++)
|
||||||
in.scriptWitness.push_back(dummy_data);
|
in.scriptWitness.push_back(dummy_data);
|
||||||
in.scriptWitness.push_back(redeem_script);
|
in.scriptWitness.push_back(redeem_script);
|
||||||
|
|
@ -693,8 +639,7 @@ bytes add_dummy_signatures_for_pw_transfer(const bytes& unsigned_tx,
|
||||||
bytes partially_sign_pw_transfer_transaction(const bytes &partially_signed_tx,
|
bytes partially_sign_pw_transfer_transaction(const bytes &partially_signed_tx,
|
||||||
std::vector<uint64_t> in_amounts,
|
std::vector<uint64_t> in_amounts,
|
||||||
const fc::ecc::private_key &priv_key,
|
const fc::ecc::private_key &priv_key,
|
||||||
unsigned int key_idx)
|
unsigned int key_idx) {
|
||||||
{
|
|
||||||
btc_tx tx;
|
btc_tx tx;
|
||||||
tx.fill_from_bytes(partially_signed_tx);
|
tx.fill_from_bytes(partially_signed_tx);
|
||||||
FC_ASSERT(tx.vin.size() > 0);
|
FC_ASSERT(tx.vin.size() > 0);
|
||||||
|
|
@ -710,13 +655,11 @@ bytes partially_sign_pw_transfer_transaction(const bytes& partially_signed_tx,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, const std::vector<std::vector<bytes> > &signature_set, const bytes &redeem_script)
|
bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, const std::vector<std::vector<bytes>> &signature_set, const bytes &redeem_script) {
|
||||||
{
|
|
||||||
btc_tx tx;
|
btc_tx tx;
|
||||||
tx.fill_from_bytes(unsigned_tx);
|
tx.fill_from_bytes(unsigned_tx);
|
||||||
bytes dummy_data;
|
bytes dummy_data;
|
||||||
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");
|
||||||
// push signatures in reverse order because script starts to check the top signature on the stack first
|
// push signatures in reverse order because script starts to check the top signature on the stack first
|
||||||
|
|
@ -724,8 +667,7 @@ bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, const std::vector<
|
||||||
tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]);
|
tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& in: tx.vin)
|
for (auto &in : tx.vin) {
|
||||||
{
|
|
||||||
in.scriptWitness.push_back(redeem_script);
|
in.scriptWitness.push_back(redeem_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -735,4 +677,4 @@ bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, const std::vector<
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <graphene/peerplays_sidechain/defs.hpp>
|
|
||||||
#include <fc/optional.hpp>
|
#include <fc/optional.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/defs.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
|
@ -14,7 +14,6 @@ bytes generate_redeem_script(std::vector<std::pair<fc::ecc::public_key, int> > k
|
||||||
std::string p2wsh_address_from_redeem_script(const bytes &script, bitcoin_network network = mainnet);
|
std::string p2wsh_address_from_redeem_script(const bytes &script, bitcoin_network network = mainnet);
|
||||||
bytes lock_script_for_redeem_script(const bytes &script);
|
bytes lock_script_for_redeem_script(const bytes &script);
|
||||||
|
|
||||||
|
|
||||||
std::vector<bytes> signatures_for_raw_transaction(const bytes &unsigned_tx,
|
std::vector<bytes> signatures_for_raw_transaction(const bytes &unsigned_tx,
|
||||||
std::vector<uint64_t> in_amounts,
|
std::vector<uint64_t> in_amounts,
|
||||||
const bytes &redeem_script,
|
const bytes &redeem_script,
|
||||||
|
|
@ -65,8 +64,7 @@ bytes add_signatures_to_unsigned_tx(const bytes& unsigned_tx,
|
||||||
const std::vector<std::vector<bytes>> &signatures,
|
const std::vector<std::vector<bytes>> &signatures,
|
||||||
const bytes &redeem_script);
|
const bytes &redeem_script);
|
||||||
|
|
||||||
struct btc_outpoint
|
struct btc_outpoint {
|
||||||
{
|
|
||||||
fc::uint256 hash;
|
fc::uint256 hash;
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
|
||||||
|
|
@ -74,8 +72,7 @@ struct btc_outpoint
|
||||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btc_in
|
struct btc_in {
|
||||||
{
|
|
||||||
btc_outpoint prevout;
|
btc_outpoint prevout;
|
||||||
bytes scriptSig;
|
bytes scriptSig;
|
||||||
uint32_t nSequence;
|
uint32_t nSequence;
|
||||||
|
|
@ -85,8 +82,7 @@ struct btc_in
|
||||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btc_out
|
struct btc_out {
|
||||||
{
|
|
||||||
int64_t nValue;
|
int64_t nValue;
|
||||||
bytes scriptPubKey;
|
bytes scriptPubKey;
|
||||||
|
|
||||||
|
|
@ -94,8 +90,7 @@ struct btc_out
|
||||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btc_tx
|
struct btc_tx {
|
||||||
{
|
|
||||||
std::vector<btc_in> vin;
|
std::vector<btc_in> vin;
|
||||||
std::vector<btc_out> vout;
|
std::vector<btc_out> vout;
|
||||||
int32_t nVersion;
|
int32_t nVersion;
|
||||||
|
|
@ -106,5 +101,4 @@ struct btc_tx
|
||||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fc/crypto/sha256.hpp>
|
||||||
#include <fc/safe.hpp>
|
#include <fc/safe.hpp>
|
||||||
#include <fc/time.hpp>
|
#include <fc/time.hpp>
|
||||||
#include <fc/crypto/sha256.hpp>
|
|
||||||
|
|
||||||
#include <graphene/chain/protocol/asset.hpp>
|
#include <graphene/chain/protocol/asset.hpp>
|
||||||
#include <graphene/chain/protocol/types.hpp>
|
#include <graphene/chain/protocol/types.hpp>
|
||||||
|
|
@ -22,14 +22,11 @@ enum class sidechain_type {
|
||||||
|
|
||||||
using bytes = std::vector<unsigned char>;
|
using bytes = std::vector<unsigned char>;
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -40,8 +37,7 @@ struct prev_out
|
||||||
uint64_t amount;
|
uint64_t amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct info_for_vin
|
struct info_for_vin {
|
||||||
{
|
|
||||||
info_for_vin() = default;
|
info_for_vin() = default;
|
||||||
|
|
||||||
info_for_vin(const prev_out &_out, const std::string &_address, bytes _script = bytes(), bool _resend = false);
|
info_for_vin(const prev_out &_out, const std::string &_address, bytes _script = bytes(), bool _resend = false);
|
||||||
|
|
@ -79,6 +75,6 @@ struct sidechain_event_data {
|
||||||
chain::asset peerplays_asset;
|
chain::asset peerplays_asset;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
FC_REFLECT_ENUM(graphene::peerplays_sidechain::sidechain_type, (bitcoin)(ethereum)(eos)(peerplays))
|
FC_REFLECT_ENUM(graphene::peerplays_sidechain::sidechain_type, (bitcoin)(ethereum)(eos)(peerplays))
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
using namespace chain;
|
using namespace chain;
|
||||||
|
|
||||||
namespace detail
|
namespace detail {
|
||||||
{
|
|
||||||
class peerplays_sidechain_plugin_impl;
|
class peerplays_sidechain_plugin_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
class peerplays_sidechain_plugin : public graphene::app::plugin
|
class peerplays_sidechain_plugin : public graphene::app::plugin {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
peerplays_sidechain_plugin();
|
peerplays_sidechain_plugin();
|
||||||
virtual ~peerplays_sidechain_plugin();
|
virtual ~peerplays_sidechain_plugin();
|
||||||
|
|
@ -31,10 +29,8 @@ class peerplays_sidechain_plugin : public graphene::app::plugin
|
||||||
son_id_type &get_current_son_id();
|
son_id_type &get_current_son_id();
|
||||||
son_object get_son_object(son_id_type son_id);
|
son_object get_son_object(son_id_type son_id);
|
||||||
bool is_active_son(son_id_type son_id);
|
bool is_active_son(son_id_type son_id);
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& get_private_keys();
|
|
||||||
fc::ecc::private_key get_private_key(son_id_type son_id);
|
fc::ecc::private_key get_private_key(son_id_type son_id);
|
||||||
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
||||||
};
|
};
|
||||||
|
|
||||||
} } //graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,14 @@ public:
|
||||||
graphene::peerplays_sidechain::sidechain_type get_sidechain();
|
graphene::peerplays_sidechain::sidechain_type get_sidechain();
|
||||||
std::vector<std::string> get_sidechain_deposit_addresses();
|
std::vector<std::string> get_sidechain_deposit_addresses();
|
||||||
std::vector<std::string> get_sidechain_withdraw_addresses();
|
std::vector<std::string> get_sidechain_withdraw_addresses();
|
||||||
|
std::string get_private_key(std::string public_key);
|
||||||
|
|
||||||
void sidechain_event_data_received(const sidechain_event_data &sed);
|
void sidechain_event_data_received(const sidechain_event_data &sed);
|
||||||
|
void process_deposits();
|
||||||
|
void process_withdrawals();
|
||||||
|
|
||||||
virtual void recreate_primary_wallet() = 0;
|
virtual void recreate_primary_wallet() = 0;
|
||||||
virtual void process_deposits() = 0;
|
|
||||||
virtual void process_deposit(const son_wallet_deposit_object &swdo) = 0;
|
virtual void process_deposit(const son_wallet_deposit_object &swdo) = 0;
|
||||||
virtual void process_withdrawals() = 0;
|
|
||||||
virtual void process_withdrawal(const son_wallet_withdraw_object &swwo) = 0;
|
virtual void process_withdrawal(const son_wallet_withdraw_object &swwo) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -32,14 +33,14 @@ protected:
|
||||||
graphene::chain::database &database;
|
graphene::chain::database &database;
|
||||||
graphene::peerplays_sidechain::sidechain_type sidechain;
|
graphene::peerplays_sidechain::sidechain_type sidechain;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> private_keys;
|
||||||
|
|
||||||
virtual std::string create_multisignature_wallet(const std::vector<std::string> public_keys) = 0;
|
virtual std::string create_multisignature_wallet(const std::vector<std::string> public_keys) = 0;
|
||||||
virtual std::string transfer(const std::string &from, const std::string &to, const uint64_t amount) = 0;
|
virtual std::string transfer(const std::string &from, const std::string &to, const uint64_t amount) = 0;
|
||||||
virtual std::string sign_transaction(const std::string &transaction) = 0;
|
virtual std::string sign_transaction(const std::string &transaction) = 0;
|
||||||
virtual std::string send_transaction(const std::string &transaction) = 0;
|
virtual std::string send_transaction(const std::string &transaction) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,14 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <zmq.hpp>
|
#include <zmq.hpp>
|
||||||
|
|
||||||
#include <fc/signals.hpp>
|
|
||||||
#include <fc/network/http/connection.hpp>
|
#include <fc/network/http/connection.hpp>
|
||||||
|
#include <fc/signals.hpp>
|
||||||
#include <graphene/chain/son_wallet_deposit_object.hpp>
|
#include <graphene/chain/son_wallet_deposit_object.hpp>
|
||||||
#include <graphene/chain/son_wallet_withdraw_object.hpp>
|
#include <graphene/chain/son_wallet_withdraw_object.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
class btc_txout
|
class btc_txout {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
std::string txid_;
|
std::string txid_;
|
||||||
unsigned int out_num_;
|
unsigned int out_num_;
|
||||||
|
|
@ -22,28 +21,35 @@ public:
|
||||||
|
|
||||||
class bitcoin_rpc_client {
|
class bitcoin_rpc_client {
|
||||||
public:
|
public:
|
||||||
bitcoin_rpc_client( std::string _ip, uint32_t _rpc, std::string _user, std::string _password) ;
|
bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password);
|
||||||
bool connection_is_not_defined() const;
|
bool connection_is_not_defined() const;
|
||||||
|
|
||||||
std::string addmultisigaddress(const std::vector<std::string> public_keys);
|
std::string addmultisigaddress(const std::vector<std::string> public_keys);
|
||||||
std::string createrawtransaction(const std::vector<btc_txout> &ins, const fc::flat_map<std::string, double> outs);
|
std::string createrawtransaction(const std::vector<btc_txout> &ins, const fc::flat_map<std::string, double> outs);
|
||||||
|
std::string createwallet(const std::string &wallet_name);
|
||||||
|
std::string encryptwallet(const std::string &passphrase);
|
||||||
uint64_t estimatesmartfee();
|
uint64_t estimatesmartfee();
|
||||||
std::string getblock(const std::string &block_hash, int32_t verbosity = 2);
|
std::string getblock(const std::string &block_hash, int32_t verbosity = 2);
|
||||||
void importaddress(const std::string &address_or_script);
|
void importaddress(const std::string &address_or_script);
|
||||||
std::vector<btc_txout> listunspent();
|
std::vector<btc_txout> listunspent();
|
||||||
std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount);
|
std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount);
|
||||||
|
std::string loadwallet(const std::string &filename);
|
||||||
void sendrawtransaction(const std::string &tx_hex);
|
void sendrawtransaction(const std::string &tx_hex);
|
||||||
std::string signrawtransactionwithkey(const std::string &tx_hash, const std::string &private_key);
|
std::string signrawtransactionwithkey(const std::string &tx_hash, const std::string &private_key);
|
||||||
std::string signrawtransactionwithwallet(const std::string &tx_hash);
|
std::string signrawtransactionwithwallet(const std::string &tx_hash);
|
||||||
|
std::string unloadwallet(const std::string &filename);
|
||||||
|
std::string walletlock();
|
||||||
|
bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
fc::http::reply send_post_request(std::string body, bool show_log = false);
|
||||||
fc::http::reply send_post_request( std::string body );
|
|
||||||
|
|
||||||
std::string ip;
|
std::string ip;
|
||||||
uint32_t rpc_port;
|
uint32_t rpc_port;
|
||||||
std::string user;
|
std::string user;
|
||||||
std::string password;
|
std::string password;
|
||||||
|
std::string wallet;
|
||||||
|
std::string wallet_password;
|
||||||
|
|
||||||
fc::http::header authorization;
|
fc::http::header authorization;
|
||||||
};
|
};
|
||||||
|
|
@ -53,9 +59,12 @@ private:
|
||||||
class zmq_listener {
|
class zmq_listener {
|
||||||
public:
|
public:
|
||||||
zmq_listener(std::string _ip, uint32_t _zmq);
|
zmq_listener(std::string _ip, uint32_t _zmq);
|
||||||
bool connection_is_not_defined() const { return zmq_port == 0; }
|
bool connection_is_not_defined() const {
|
||||||
|
return zmq_port == 0;
|
||||||
|
}
|
||||||
|
|
||||||
fc::signal<void(const std::string &)> event_received;
|
fc::signal<void(const std::string &)> event_received;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handle_zmq();
|
void handle_zmq();
|
||||||
std::vector<zmq::message_t> receive_multipart();
|
std::vector<zmq::message_t> receive_multipart();
|
||||||
|
|
@ -75,11 +84,21 @@ public:
|
||||||
virtual ~sidechain_net_handler_bitcoin();
|
virtual ~sidechain_net_handler_bitcoin();
|
||||||
|
|
||||||
void recreate_primary_wallet();
|
void recreate_primary_wallet();
|
||||||
void process_deposits();
|
|
||||||
void process_deposit(const son_wallet_deposit_object &swdo);
|
void process_deposit(const son_wallet_deposit_object &swdo);
|
||||||
void process_withdrawals();
|
|
||||||
void process_withdrawal(const son_wallet_withdraw_object &swwo);
|
void process_withdrawal(const son_wallet_withdraw_object &swwo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string ip;
|
||||||
|
uint32_t zmq_port;
|
||||||
|
uint32_t rpc_port;
|
||||||
|
std::string rpc_user;
|
||||||
|
std::string rpc_password;
|
||||||
|
std::string wallet;
|
||||||
|
std::string wallet_password;
|
||||||
|
|
||||||
|
std::unique_ptr<bitcoin_rpc_client> bitcoin_client;
|
||||||
|
std::unique_ptr<zmq_listener> listener;
|
||||||
|
|
||||||
std::string create_multisignature_wallet(const std::vector<std::string> public_keys);
|
std::string create_multisignature_wallet(const std::vector<std::string> public_keys);
|
||||||
std::string transfer(const std::string &from, const std::string &to, const uint64_t amount);
|
std::string transfer(const std::string &from, const std::string &to, const uint64_t amount);
|
||||||
std::string sign_transaction(const std::string &transaction);
|
std::string sign_transaction(const std::string &transaction);
|
||||||
|
|
@ -89,21 +108,8 @@ public:
|
||||||
std::string transfer_deposit_to_primary_wallet(const son_wallet_deposit_object &swdo);
|
std::string transfer_deposit_to_primary_wallet(const son_wallet_deposit_object &swdo);
|
||||||
std::string transfer_withdrawal_from_primary_wallet(const son_wallet_withdraw_object &swwo);
|
std::string transfer_withdrawal_from_primary_wallet(const son_wallet_withdraw_object &swwo);
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string ip;
|
|
||||||
uint32_t zmq_port;
|
|
||||||
uint32_t rpc_port;
|
|
||||||
std::string rpc_user;
|
|
||||||
std::string rpc_password;
|
|
||||||
std::map<std::string, std::string> _private_keys;
|
|
||||||
|
|
||||||
std::unique_ptr<zmq_listener> listener;
|
|
||||||
std::unique_ptr<bitcoin_rpc_client> bitcoin_client;
|
|
||||||
|
|
||||||
void handle_event(const std::string &event_data);
|
void handle_event(const std::string &event_data);
|
||||||
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
|
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,21 +14,16 @@ public:
|
||||||
virtual ~sidechain_net_handler_peerplays();
|
virtual ~sidechain_net_handler_peerplays();
|
||||||
|
|
||||||
void recreate_primary_wallet();
|
void recreate_primary_wallet();
|
||||||
void process_deposits();
|
|
||||||
void process_deposit(const son_wallet_deposit_object &swdo);
|
void process_deposit(const son_wallet_deposit_object &swdo);
|
||||||
void process_withdrawals();
|
|
||||||
void process_withdrawal(const son_wallet_withdraw_object &swwo);
|
void process_withdrawal(const son_wallet_withdraw_object &swwo);
|
||||||
|
|
||||||
|
private:
|
||||||
std::string create_multisignature_wallet(const std::vector<std::string> public_keys);
|
std::string create_multisignature_wallet(const std::vector<std::string> public_keys);
|
||||||
std::string transfer(const std::string &from, const std::string &to, const uint64_t amount);
|
std::string transfer(const std::string &from, const std::string &to, const uint64_t amount);
|
||||||
std::string sign_transaction(const std::string &transaction);
|
std::string sign_transaction(const std::string &transaction);
|
||||||
std::string send_transaction(const std::string &transaction);
|
std::string send_transaction(const std::string &transaction);
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void on_applied_block(const signed_block &b);
|
void on_applied_block(const signed_block &b);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,11 @@ public:
|
||||||
void recreate_primary_wallet();
|
void recreate_primary_wallet();
|
||||||
void process_deposits();
|
void process_deposits();
|
||||||
void process_withdrawals();
|
void process_withdrawals();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
peerplays_sidechain_plugin &plugin;
|
peerplays_sidechain_plugin &plugin;
|
||||||
graphene::chain::database &database;
|
graphene::chain::database &database;
|
||||||
std::vector<std::unique_ptr<sidechain_net_handler>> net_handlers;
|
std::vector<std::unique_ptr<sidechain_net_handler>> net_handlers;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
|
#include <graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp>
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <boost/range/algorithm_ext/insert.hpp>
|
#include <boost/range/algorithm_ext/insert.hpp>
|
||||||
|
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
#include <fc/smart_ref_impl.hpp>
|
#include <fc/smart_ref_impl.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/proposal_object.hpp>
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
|
#include <graphene/chain/protocol/transfer.hpp>
|
||||||
#include <graphene/chain/sidechain_address_object.hpp>
|
#include <graphene/chain/sidechain_address_object.hpp>
|
||||||
#include <graphene/chain/son_wallet_object.hpp>
|
#include <graphene/chain/son_wallet_object.hpp>
|
||||||
#include <graphene/chain/son_wallet_withdraw_object.hpp>
|
#include <graphene/chain/son_wallet_withdraw_object.hpp>
|
||||||
#include <graphene/chain/protocol/transfer.hpp>
|
|
||||||
#include <graphene/peerplays_sidechain/sidechain_net_manager.hpp>
|
#include <graphene/peerplays_sidechain/sidechain_net_manager.hpp>
|
||||||
#include <graphene/utilities/key_conversion.hpp>
|
#include <graphene/utilities/key_conversion.hpp>
|
||||||
|
|
||||||
|
|
@ -19,11 +19,9 @@ namespace bpo = boost::program_options;
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
namespace detail
|
namespace detail {
|
||||||
{
|
|
||||||
|
|
||||||
class peerplays_sidechain_plugin_impl
|
class peerplays_sidechain_plugin_impl {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin &_plugin);
|
peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin &_plugin);
|
||||||
virtual ~peerplays_sidechain_plugin_impl();
|
virtual ~peerplays_sidechain_plugin_impl();
|
||||||
|
|
@ -31,19 +29,21 @@ class peerplays_sidechain_plugin_impl
|
||||||
void plugin_set_program_options(
|
void plugin_set_program_options(
|
||||||
boost::program_options::options_description &cli,
|
boost::program_options::options_description &cli,
|
||||||
boost::program_options::options_description &cfg);
|
boost::program_options::options_description &cfg);
|
||||||
void plugin_initialize(const boost::program_options::variables_map& options);
|
void plugin_initialize(const boost::program_options::variables_map &opt);
|
||||||
void plugin_startup();
|
void plugin_startup();
|
||||||
|
|
||||||
std::set<chain::son_id_type> &get_sons();
|
std::set<chain::son_id_type> &get_sons();
|
||||||
son_id_type &get_current_son_id();
|
son_id_type &get_current_son_id();
|
||||||
son_object get_son_object(son_id_type son_id);
|
son_object get_son_object(son_id_type son_id);
|
||||||
bool is_active_son(son_id_type son_id);
|
bool is_active_son(son_id_type son_id);
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& get_private_keys();
|
|
||||||
fc::ecc::private_key get_private_key(son_id_type son_id);
|
fc::ecc::private_key get_private_key(son_id_type son_id);
|
||||||
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
fc::ecc::private_key get_private_key(chain::public_key_type public_key);
|
||||||
|
|
||||||
void schedule_heartbeat_loop();
|
void schedule_heartbeat_loop();
|
||||||
void heartbeat_loop();
|
void heartbeat_loop();
|
||||||
|
void schedule_son_processing();
|
||||||
|
void son_processing();
|
||||||
|
void approve_proposals();
|
||||||
void create_son_down_proposals();
|
void create_son_down_proposals();
|
||||||
void create_son_deregister_proposals();
|
void create_son_deregister_proposals();
|
||||||
void recreate_primary_wallet();
|
void recreate_primary_wallet();
|
||||||
|
|
@ -53,6 +53,8 @@ class peerplays_sidechain_plugin_impl
|
||||||
private:
|
private:
|
||||||
peerplays_sidechain_plugin &plugin;
|
peerplays_sidechain_plugin &plugin;
|
||||||
|
|
||||||
|
boost::program_options::variables_map options;
|
||||||
|
|
||||||
bool config_ready_son;
|
bool config_ready_son;
|
||||||
bool config_ready_bitcoin;
|
bool config_ready_bitcoin;
|
||||||
bool config_ready_peerplays;
|
bool config_ready_peerplays;
|
||||||
|
|
@ -60,13 +62,12 @@ class peerplays_sidechain_plugin_impl
|
||||||
son_id_type current_son_id;
|
son_id_type current_son_id;
|
||||||
|
|
||||||
std::unique_ptr<peerplays_sidechain::sidechain_net_manager> net_manager;
|
std::unique_ptr<peerplays_sidechain::sidechain_net_manager> net_manager;
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key> _private_keys;
|
std::set<chain::son_id_type> sons;
|
||||||
std::set<chain::son_id_type> _sons;
|
std::map<chain::public_key_type, fc::ecc::private_key> private_keys;
|
||||||
fc::future<void> _heartbeat_task;
|
fc::future<void> _heartbeat_task;
|
||||||
|
fc::future<void> _son_processing_task;
|
||||||
|
|
||||||
void on_applied_block(const signed_block &b);
|
void on_applied_block(const signed_block &b);
|
||||||
void on_new_objects(const vector<object_id_type>& new_object_ids);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin &_plugin) :
|
peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin &_plugin) :
|
||||||
|
|
@ -75,12 +76,10 @@ peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidec
|
||||||
config_ready_bitcoin(false),
|
config_ready_bitcoin(false),
|
||||||
config_ready_peerplays(false),
|
config_ready_peerplays(false),
|
||||||
current_son_id(son_id_type(std::numeric_limits<uint32_t>().max())),
|
current_son_id(son_id_type(std::numeric_limits<uint32_t>().max())),
|
||||||
net_manager(nullptr)
|
net_manager(nullptr) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl()
|
peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl() {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
if (_heartbeat_task.valid())
|
if (_heartbeat_task.valid())
|
||||||
_heartbeat_task.cancel_and_wait(__FUNCTION__);
|
_heartbeat_task.cancel_and_wait(__FUNCTION__);
|
||||||
|
|
@ -89,153 +88,145 @@ peerplays_sidechain_plugin_impl::~peerplays_sidechain_plugin_impl()
|
||||||
} catch (fc::exception &e) {
|
} catch (fc::exception &e) {
|
||||||
edump((e.to_detail_string()));
|
edump((e.to_detail_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (_son_processing_task.valid())
|
||||||
|
_son_processing_task.cancel_and_wait(__FUNCTION__);
|
||||||
|
} catch (fc::canceled_exception &) {
|
||||||
|
//Expected exception. Move along.
|
||||||
|
} catch (fc::exception &e) {
|
||||||
|
edump((e.to_detail_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
boost::program_options::options_description &cli,
|
boost::program_options::options_description &cli,
|
||||||
boost::program_options::options_description& cfg)
|
boost::program_options::options_description &cfg) {
|
||||||
{
|
|
||||||
auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan")));
|
auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan")));
|
||||||
string son_id_example = fc::json::to_string(chain::son_id_type(5));
|
string son_id_example = fc::json::to_string(chain::son_id_type(5));
|
||||||
string son_id_example2 = fc::json::to_string(chain::son_id_type(6));
|
string son_id_example2 = fc::json::to_string(chain::son_id_type(6));
|
||||||
|
|
||||||
cli.add_options()
|
cli.add_options()("son-id", bpo::value<vector<string>>(), ("ID of SON controlled by this node (e.g. " + son_id_example + ", quotes are required)").c_str());
|
||||||
("son-id", bpo::value<vector<string>>(), ("ID of SON controlled by this node (e.g. " + son_id_example + ", quotes are required)").c_str())
|
cli.add_options()("son-ids", bpo::value<string>(), ("IDs of multiple SONs controlled by this node (e.g. [" + son_id_example + ", " + son_id_example2 + "], quotes are required)").c_str());
|
||||||
("son-ids", bpo::value<string>(), ("IDs of multiple SONs controlled by this node (e.g. [" + son_id_example + ", " + son_id_example2 + "], quotes are required)").c_str())
|
cli.add_options()("peerplays-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))),
|
||||||
("peerplays-private-key", bpo::value<vector<string>>()->composing()->multitoken()->
|
"Tuple of [PublicKey, WIF private key] (may specify multiple times)");
|
||||||
DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))),
|
cli.add_options()("bitcoin-node-ip", bpo::value<string>()->default_value("99.79.189.95"), "IP address of Bitcoin node");
|
||||||
"Tuple of [PublicKey, WIF private key] (may specify multiple times)")
|
cli.add_options()("bitcoin-node-zmq-port", bpo::value<uint32_t>()->default_value(11111), "ZMQ port of Bitcoin node");
|
||||||
|
cli.add_options()("bitcoin-node-rpc-port", bpo::value<uint32_t>()->default_value(22222), "RPC port of Bitcoin node");
|
||||||
("bitcoin-node-ip", bpo::value<string>()->default_value("99.79.189.95"), "IP address of Bitcoin node")
|
cli.add_options()("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user");
|
||||||
("bitcoin-node-zmq-port", bpo::value<uint32_t>()->default_value(11111), "ZMQ port of Bitcoin node")
|
cli.add_options()("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password");
|
||||||
("bitcoin-node-rpc-port", bpo::value<uint32_t>()->default_value(22222), "RPC port of Bitcoin node")
|
cli.add_options()("bitcoin-wallet", bpo::value<string>(), "Bitcoin wallet");
|
||||||
("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user")
|
cli.add_options()("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password");
|
||||||
("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password")
|
cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
||||||
("bitcoin-address", bpo::value<string>()->default_value("2N911a7smwDzUGARg8s7Q1ViizFCw6gWcbR"), "Bitcoin address")
|
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
|
||||||
("bitcoin-public-key", bpo::value<string>()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key")
|
|
||||||
("bitcoin-private-key", bpo::value<string>()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key")
|
|
||||||
("bitcoin-private-keys", bpo::value<vector<string>>()->composing()->multitoken()->
|
|
||||||
DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
|
||||||
"Tuple of [Bitcoin PublicKey, Bitcoin Private key] (may specify multiple times)")
|
|
||||||
;
|
|
||||||
cfg.add(cli);
|
cfg.add(cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map& options)
|
void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map &opt) {
|
||||||
{
|
options = opt;
|
||||||
config_ready_son = (options.count("son-id") || options.count("son-ids")) && options.count("peerplays-private-key");
|
config_ready_son = (options.count("son-id") || options.count("son-ids")) && options.count("peerplays-private-key");
|
||||||
if (config_ready_son) {
|
if (config_ready_son) {
|
||||||
LOAD_VALUE_SET(options, "son-id", _sons, chain::son_id_type)
|
LOAD_VALUE_SET(options, "son-id", sons, chain::son_id_type)
|
||||||
if (options.count("son-ids"))
|
if (options.count("son-ids"))
|
||||||
boost::insert(_sons, fc::json::from_string(options.at("son-ids").as<string>()).as<vector<chain::son_id_type>>( 5 ));
|
boost::insert(sons, fc::json::from_string(options.at("son-ids").as<string>()).as<vector<chain::son_id_type>>(5));
|
||||||
config_ready_son = config_ready_son && !_sons.empty();
|
config_ready_son = config_ready_son && !sons.empty();
|
||||||
|
|
||||||
#ifndef SUPPORT_MULTIPLE_SONS
|
#ifndef SUPPORT_MULTIPLE_SONS
|
||||||
FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" );
|
FC_ASSERT(sons.size() == 1, "Multiple SONs not supported");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( options.count("peerplays-private-key") )
|
if (options.count("peerplays-private-key")) {
|
||||||
{
|
|
||||||
const std::vector<std::string> key_id_to_wif_pair_strings = options["peerplays-private-key"].as<std::vector<std::string>>();
|
const std::vector<std::string> key_id_to_wif_pair_strings = options["peerplays-private-key"].as<std::vector<std::string>>();
|
||||||
for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings)
|
for (const std::string &key_id_to_wif_pair_string : key_id_to_wif_pair_strings) {
|
||||||
{
|
|
||||||
auto key_id_to_wif_pair = graphene::app::dejsonify<std::pair<chain::public_key_type, std::string>>(key_id_to_wif_pair_string, 5);
|
auto key_id_to_wif_pair = graphene::app::dejsonify<std::pair<chain::public_key_type, std::string>>(key_id_to_wif_pair_string, 5);
|
||||||
ilog("Public Key: ${public}", ("public", key_id_to_wif_pair.first));
|
ilog("Public Key: ${public}", ("public", key_id_to_wif_pair.first));
|
||||||
fc::optional<fc::ecc::private_key> private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second);
|
fc::optional<fc::ecc::private_key> private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second);
|
||||||
if (!private_key)
|
if (!private_key) {
|
||||||
{
|
|
||||||
// the key isn't in WIF format; see if they are still passing the old native private key format. This is
|
// the key isn't in WIF format; see if they are still passing the old native private key format. This is
|
||||||
// just here to ease the transition, can be removed soon
|
// just here to ease the transition, can be removed soon
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
private_key = fc::variant(key_id_to_wif_pair.second, 2).as<fc::ecc::private_key>(1);
|
private_key = fc::variant(key_id_to_wif_pair.second, 2).as<fc::ecc::private_key>(1);
|
||||||
}
|
} catch (const fc::exception &) {
|
||||||
catch (const fc::exception&)
|
|
||||||
{
|
|
||||||
FC_THROW("Invalid WIF-format private key ${key_string}", ("key_string", key_id_to_wif_pair.second));
|
FC_THROW("Invalid WIF-format private key ${key_string}", ("key_string", key_id_to_wif_pair.second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_private_keys[key_id_to_wif_pair.first] = *private_key;
|
private_keys[key_id_to_wif_pair.first] = *private_key;
|
||||||
|
}
|
||||||
|
config_ready_son = config_ready_son && !private_keys.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (!config_ready_son) {
|
||||||
wlog("Haven't set up SON parameters");
|
wlog("Haven't set up SON parameters");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.database().applied_block.connect( [&] (const signed_block& b) { on_applied_block(b); } );
|
|
||||||
plugin.database().new_objects.connect( [&] (const vector<object_id_type>& ids, const flat_set<account_id_type>& impacted_accounts) { on_new_objects(ids); } );
|
|
||||||
|
|
||||||
net_manager = std::unique_ptr<sidechain_net_manager>(new sidechain_net_manager(plugin));
|
|
||||||
|
|
||||||
config_ready_bitcoin = options.count("bitcoin-node-ip") &&
|
config_ready_bitcoin = options.count("bitcoin-node-ip") &&
|
||||||
options.count("bitcoin-node-zmq-port") && options.count("bitcoin-node-rpc-port") &&
|
options.count("bitcoin-node-zmq-port") && options.count("bitcoin-node-rpc-port") &&
|
||||||
options.count("bitcoin-node-rpc-user") && options.count("bitcoin-node-rpc-password") &&
|
options.count("bitcoin-node-rpc-user") && options.count("bitcoin-node-rpc-password") &&
|
||||||
options.count( "bitcoin-address" ) && options.count( "bitcoin-public-key" ) && options.count( "bitcoin-private-key" );
|
/*options.count( "bitcoin-wallet" ) && options.count( "bitcoin-wallet-password" ) &&*/
|
||||||
if (config_ready_bitcoin) {
|
options.count("bitcoin-private-key");
|
||||||
net_manager->create_handler(sidechain_type::bitcoin, options);
|
if (!config_ready_bitcoin) {
|
||||||
ilog("Bitcoin sidechain handler created");
|
|
||||||
} else {
|
|
||||||
wlog("Haven't set up Bitcoin sidechain parameters");
|
wlog("Haven't set up Bitcoin sidechain parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
//config_ready_ethereum = options.count( "ethereum-node-ip" ) &&
|
//config_ready_ethereum = options.count( "ethereum-node-ip" ) &&
|
||||||
// options.count( "ethereum-address" ) && options.count( "ethereum-public-key" ) && options.count( "ethereum-private-key" );
|
// options.count( "ethereum-address" ) && options.count( "ethereum-public-key" ) && options.count( "ethereum-private-key" );
|
||||||
//if (config_ready_ethereum) {
|
//if (!config_ready_ethereum) {
|
||||||
// net_manager->create_handler(sidechain_type::ethereum, options);
|
|
||||||
// ilog("Ethereum sidechain handler created");
|
|
||||||
//} else {
|
|
||||||
// wlog("Haven't set up Ethereum sidechain parameters");
|
// wlog("Haven't set up Ethereum sidechain parameters");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
config_ready_peerplays = true;
|
config_ready_peerplays = true;
|
||||||
if (config_ready_peerplays) {
|
if (!config_ready_peerplays) {
|
||||||
net_manager->create_handler(sidechain_type::peerplays, options);
|
|
||||||
ilog("Peerplays sidechain handler created");
|
|
||||||
} else {
|
|
||||||
wlog("Haven't set up Peerplays sidechain parameters");
|
wlog("Haven't set up Peerplays sidechain parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(config_ready_bitcoin /*&& config_ready_ethereum*/)) {
|
if (!(config_ready_bitcoin /*&& config_ready_ethereum*/ && config_ready_peerplays)) {
|
||||||
wlog("Haven't set up any sidechain parameters");
|
wlog("Haven't set up any sidechain parameters");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::plugin_startup()
|
void peerplays_sidechain_plugin_impl::plugin_startup() {
|
||||||
{
|
|
||||||
if (config_ready_son) {
|
if (config_ready_son) {
|
||||||
ilog("Starting ${n} SON instances", ("n", _sons.size()));
|
ilog("Starting ${n} SON instances", ("n", sons.size()));
|
||||||
|
|
||||||
schedule_heartbeat_loop();
|
schedule_heartbeat_loop();
|
||||||
} else {
|
} else {
|
||||||
elog("No sons configured! Please add SON IDs and private keys to configuration.");
|
elog("No sons configured! Please add SON IDs and private keys to configuration.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
net_manager = std::unique_ptr<sidechain_net_manager>(new sidechain_net_manager(plugin));
|
||||||
|
|
||||||
if (config_ready_bitcoin) {
|
if (config_ready_bitcoin) {
|
||||||
|
net_manager->create_handler(sidechain_type::bitcoin, options);
|
||||||
ilog("Bitcoin sidechain handler running");
|
ilog("Bitcoin sidechain handler running");
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (config_ready_ethereum) {
|
//if (config_ready_ethereum) {
|
||||||
|
// net_manager->create_handler(sidechain_type::ethereum, options);
|
||||||
// ilog("Ethereum sidechain handler running");
|
// ilog("Ethereum sidechain handler running");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (config_ready_peerplays) {
|
if (config_ready_peerplays) {
|
||||||
|
net_manager->create_handler(sidechain_type::peerplays, options);
|
||||||
ilog("Peerplays sidechain handler running");
|
ilog("Peerplays sidechain handler running");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugin.database().applied_block.connect([&](const signed_block &b) {
|
||||||
|
on_applied_block(b);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<chain::son_id_type>& peerplays_sidechain_plugin_impl::get_sons()
|
std::set<chain::son_id_type> &peerplays_sidechain_plugin_impl::get_sons() {
|
||||||
{
|
return sons;
|
||||||
return _sons;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
son_id_type &peerplays_sidechain_plugin_impl::get_current_son_id() {
|
son_id_type &peerplays_sidechain_plugin_impl::get_current_son_id() {
|
||||||
return current_son_id;
|
return current_son_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son_id)
|
son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son_id) {
|
||||||
{
|
|
||||||
const auto &idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
const auto &idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
||||||
auto son_obj = idx.find(son_id);
|
auto son_obj = idx.find(son_id);
|
||||||
if (son_obj == idx.end())
|
if (son_obj == idx.end())
|
||||||
|
|
@ -243,8 +234,7 @@ son_object peerplays_sidechain_plugin_impl::get_son_object(son_id_type son_id)
|
||||||
return *son_obj;
|
return *son_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peerplays_sidechain_plugin_impl::is_active_son(son_id_type son_id)
|
bool peerplays_sidechain_plugin_impl::is_active_son(son_id_type son_id) {
|
||||||
{
|
|
||||||
const auto &idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
const auto &idx = plugin.database().get_index_type<chain::son_index>().indices().get<by_id>();
|
||||||
auto son_obj = idx.find(son_id);
|
auto son_obj = idx.find(son_id);
|
||||||
if (son_obj == idx.end())
|
if (son_obj == idx.end())
|
||||||
|
|
@ -264,42 +254,35 @@ bool peerplays_sidechain_plugin_impl::is_active_son(son_id_type son_id)
|
||||||
return (it != active_son_ids.end());
|
return (it != active_son_ids.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& peerplays_sidechain_plugin_impl::get_private_keys()
|
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(son_id_type son_id) {
|
||||||
{
|
|
||||||
return _private_keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(son_id_type son_id)
|
|
||||||
{
|
|
||||||
return get_private_key(get_son_object(son_id).signing_key);
|
return get_private_key(get_son_object(son_id).signing_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(chain::public_key_type public_key)
|
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(chain::public_key_type public_key) {
|
||||||
{
|
auto private_key_itr = private_keys.find(public_key);
|
||||||
auto private_key_itr = _private_keys.find( public_key );
|
if (private_key_itr != private_keys.end()) {
|
||||||
if( private_key_itr != _private_keys.end() ) {
|
|
||||||
return private_key_itr->second;
|
return private_key_itr->second;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::schedule_heartbeat_loop()
|
void peerplays_sidechain_plugin_impl::schedule_heartbeat_loop() {
|
||||||
{
|
|
||||||
fc::time_point now = fc::time_point::now();
|
fc::time_point now = fc::time_point::now();
|
||||||
int64_t time_to_next_heartbeat = plugin.database().get_global_properties().parameters.son_heartbeat_frequency();
|
int64_t time_to_next_heartbeat = plugin.database().get_global_properties().parameters.son_heartbeat_frequency();
|
||||||
|
|
||||||
fc::time_point next_wakeup(now + fc::seconds(time_to_next_heartbeat));
|
fc::time_point next_wakeup(now + fc::seconds(time_to_next_heartbeat));
|
||||||
|
|
||||||
_heartbeat_task = fc::schedule([this]{heartbeat_loop();},
|
_heartbeat_task = fc::schedule([this] {
|
||||||
|
heartbeat_loop();
|
||||||
|
},
|
||||||
next_wakeup, "SON Heartbeat Production");
|
next_wakeup, "SON Heartbeat Production");
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
void peerplays_sidechain_plugin_impl::heartbeat_loop() {
|
||||||
{
|
|
||||||
schedule_heartbeat_loop();
|
schedule_heartbeat_loop();
|
||||||
chain::database &d = plugin.database();
|
chain::database &d = plugin.database();
|
||||||
|
|
||||||
for (son_id_type son_id : _sons) {
|
for (son_id_type son_id : sons) {
|
||||||
if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) {
|
if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) {
|
||||||
|
|
||||||
ilog("peerplays_sidechain_plugin: sending heartbeat for SON ${son}", ("son", son_id));
|
ilog("peerplays_sidechain_plugin: sending heartbeat for SON ${son}", ("son", son_id));
|
||||||
|
|
@ -324,49 +307,132 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::create_son_deregister_proposals()
|
void peerplays_sidechain_plugin_impl::schedule_son_processing() {
|
||||||
{
|
fc::time_point now = fc::time_point::now();
|
||||||
chain::database& d = plugin.database();
|
int64_t time_to_next_son_processing = 500000;
|
||||||
std::set<son_id_type> sons_to_be_dereg = d.get_sons_to_be_deregistered();
|
|
||||||
chain::son_id_type my_son_id = get_current_son_id();
|
|
||||||
|
|
||||||
if(sons_to_be_dereg.size() > 0)
|
fc::time_point next_wakeup(now + fc::microseconds(time_to_next_son_processing));
|
||||||
{
|
|
||||||
// We shouldn't raise proposals for the SONs for which a de-reg
|
_son_processing_task = fc::schedule([this] {
|
||||||
// proposal is already raised.
|
son_processing();
|
||||||
std::set<son_id_type> sons_being_dereg = d.get_sons_being_deregistered();
|
},
|
||||||
for( auto& son : sons_to_be_dereg)
|
next_wakeup, "SON Processing");
|
||||||
{
|
}
|
||||||
// New SON to be deregistered
|
|
||||||
if(sons_being_dereg.find(son) == sons_being_dereg.end() && my_son_id != son)
|
void peerplays_sidechain_plugin_impl::son_processing() {
|
||||||
{
|
if (plugin.database().get_global_properties().active_sons.size() <= 0) {
|
||||||
// Creating the de-reg proposal
|
return;
|
||||||
auto op = d.create_son_deregister_proposal(son, get_son_object(my_son_id).son_account);
|
}
|
||||||
if(op.valid())
|
|
||||||
{
|
chain::son_id_type next_son_id = plugin.database().get_scheduled_son(1);
|
||||||
// Signing and pushing into the txs to be included in the block
|
ilog("peerplays_sidechain_plugin_impl: Scheduled SON ${son}", ("son", next_son_id));
|
||||||
ilog("peerplays_sidechain_plugin: sending son deregister proposal for ${p} from ${s}", ("p", son) ("s", my_son_id));
|
|
||||||
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(get_son_object(my_son_id).signing_key), *op);
|
// Tasks that are executed by all active SONs, no matter if scheduled
|
||||||
|
// E.g. sending approvals and signing
|
||||||
|
approve_proposals();
|
||||||
|
|
||||||
|
// Tasks that are executed by scheduled and active SON
|
||||||
|
if (sons.find(next_son_id) != sons.end()) {
|
||||||
|
|
||||||
|
current_son_id = next_son_id;
|
||||||
|
|
||||||
|
create_son_down_proposals();
|
||||||
|
|
||||||
|
create_son_deregister_proposals();
|
||||||
|
|
||||||
|
recreate_primary_wallet();
|
||||||
|
|
||||||
|
process_deposits();
|
||||||
|
|
||||||
|
process_withdrawals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void peerplays_sidechain_plugin_impl::approve_proposals() {
|
||||||
|
|
||||||
|
auto approve_proposal = [&](const chain::son_id_type &son_id, const chain::proposal_id_type &proposal_id) {
|
||||||
|
ilog("peerplays_sidechain_plugin: sending approval for ${p} from ${s}", ("p", proposal_id)("s", son_id));
|
||||||
|
chain::proposal_update_operation puo;
|
||||||
|
puo.fee_paying_account = get_son_object(son_id).son_account;
|
||||||
|
puo.proposal = proposal_id;
|
||||||
|
puo.active_approvals_to_add = {get_son_object(son_id).son_account};
|
||||||
|
chain::signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), puo);
|
||||||
fc::future<bool> fut = fc::async([&]() {
|
fc::future<bool> fut = fc::async([&]() {
|
||||||
try {
|
try {
|
||||||
d.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
if (plugin.app().p2p_node())
|
if (plugin.app().p2p_node())
|
||||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
return true;
|
return true;
|
||||||
} catch (fc::exception e) {
|
} catch (fc::exception e) {
|
||||||
ilog("peerplays_sidechain_plugin_impl: sending son dereg proposal failed with exception ${e}",("e", e.what()));
|
ilog("peerplays_sidechain_plugin_impl: sending approval failed with exception ${e}", ("e", e.what()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fut.wait(fc::seconds(10));
|
fut.wait(fc::seconds(10));
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto &idx = plugin.database().get_index_type<proposal_index>().indices().get<by_id>();
|
||||||
|
vector<proposal_id_type> proposals;
|
||||||
|
for (const auto &proposal : idx) {
|
||||||
|
proposals.push_back(proposal.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto proposal_id : proposals) {
|
||||||
|
for (son_id_type son_id : sons) {
|
||||||
|
if (!is_active_son(son_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const object *obj = plugin.database().find_object(proposal_id);
|
||||||
|
const chain::proposal_object *proposal_ptr = dynamic_cast<const chain::proposal_object *>(obj);
|
||||||
|
if (proposal_ptr == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const proposal_object proposal = *proposal_ptr;
|
||||||
|
|
||||||
|
if (proposal.available_active_approvals.find(get_son_object(son_id).son_account) != proposal.available_active_approvals.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_report_down_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_delete_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_update_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_deposit_create_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_deposit_process_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_withdraw_create_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value) {
|
||||||
|
approve_proposal(son_id, proposal.id);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
void peerplays_sidechain_plugin_impl::create_son_down_proposals() {
|
||||||
{
|
|
||||||
auto create_son_down_proposal = [&](chain::son_id_type son_id, fc::time_point_sec last_active_ts) {
|
auto create_son_down_proposal = [&](chain::son_id_type son_id, fc::time_point_sec last_active_ts) {
|
||||||
chain::database &d = plugin.database();
|
chain::database &d = plugin.database();
|
||||||
const chain::global_property_object &gpo = d.get_global_properties();
|
const chain::global_property_object &gpo = d.get_global_properties();
|
||||||
|
|
@ -420,176 +486,89 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::recreate_primary_wallet()
|
void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() {
|
||||||
{
|
|
||||||
net_manager->recreate_primary_wallet();
|
|
||||||
}
|
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::process_deposits()
|
|
||||||
{
|
|
||||||
net_manager->process_deposits();
|
|
||||||
}
|
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::process_withdrawals()
|
|
||||||
{
|
|
||||||
net_manager->process_withdrawals();
|
|
||||||
}
|
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::on_applied_block( const signed_block& b )
|
|
||||||
{
|
|
||||||
chain::database &d = plugin.database();
|
chain::database &d = plugin.database();
|
||||||
const chain::global_property_object& gpo = d.get_global_properties();
|
std::set<son_id_type> sons_to_be_dereg = d.get_sons_to_be_deregistered();
|
||||||
bool latest_block = ((fc::time_point::now() - b.timestamp) < fc::microseconds(gpo.parameters.block_interval * 1000000));
|
chain::son_id_type my_son_id = get_current_son_id();
|
||||||
if(gpo.active_sons.size() <= 0 || !latest_block) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
chain::son_id_type next_son_id = d.get_scheduled_son(1);
|
if (sons_to_be_dereg.size() > 0) {
|
||||||
ilog("peerplays_sidechain_plugin_impl: Scheduled SON ${son}",("son", next_son_id));
|
// We shouldn't raise proposals for the SONs for which a de-reg
|
||||||
|
// proposal is already raised.
|
||||||
// check if we control scheduled SON
|
std::set<son_id_type> sons_being_dereg = d.get_sons_being_deregistered();
|
||||||
if( _sons.find( next_son_id ) != _sons.end() ) {
|
for (auto &son : sons_to_be_dereg) {
|
||||||
|
// New SON to be deregistered
|
||||||
current_son_id = next_son_id;
|
if (sons_being_dereg.find(son) == sons_being_dereg.end() && my_son_id != son) {
|
||||||
|
// Creating the de-reg proposal
|
||||||
create_son_down_proposals();
|
auto op = d.create_son_deregister_proposal(son, get_son_object(my_son_id).son_account);
|
||||||
|
if (op.valid()) {
|
||||||
create_son_deregister_proposals();
|
// Signing and pushing into the txs to be included in the block
|
||||||
|
ilog("peerplays_sidechain_plugin: sending son deregister proposal for ${p} from ${s}", ("p", son)("s", my_son_id));
|
||||||
recreate_primary_wallet();
|
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(get_son_object(my_son_id).signing_key), *op);
|
||||||
|
|
||||||
process_deposits();
|
|
||||||
|
|
||||||
process_withdrawals();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void peerplays_sidechain_plugin_impl::on_new_objects(const vector<object_id_type>& new_object_ids)
|
|
||||||
{
|
|
||||||
|
|
||||||
auto approve_proposal = [ & ]( const chain::son_id_type& son_id, const chain::proposal_id_type& proposal_id )
|
|
||||||
{
|
|
||||||
ilog("peerplays_sidechain_plugin: sending approval for ${p} from ${s}", ("p", proposal_id) ("s", son_id));
|
|
||||||
chain::proposal_update_operation puo;
|
|
||||||
puo.fee_paying_account = get_son_object(son_id).son_account;
|
|
||||||
puo.proposal = proposal_id;
|
|
||||||
puo.active_approvals_to_add = { get_son_object(son_id).son_account };
|
|
||||||
chain::signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), puo);
|
|
||||||
fc::future<bool> fut = fc::async([&]() {
|
fc::future<bool> fut = fc::async([&]() {
|
||||||
try {
|
try {
|
||||||
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
d.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
if (plugin.app().p2p_node())
|
if (plugin.app().p2p_node())
|
||||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
return true;
|
return true;
|
||||||
} catch (fc::exception e) {
|
} catch (fc::exception e) {
|
||||||
ilog("peerplays_sidechain_plugin_impl: sending approval failed with exception ${e}",("e", e.what()));
|
ilog("peerplays_sidechain_plugin_impl: sending son dereg proposal failed with exception ${e}", ("e", e.what()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fut.wait(fc::seconds(10));
|
fut.wait(fc::seconds(10));
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(auto object_id: new_object_ids) {
|
void peerplays_sidechain_plugin_impl::recreate_primary_wallet() {
|
||||||
if( object_id.is<chain::proposal_object>() ) {
|
net_manager->recreate_primary_wallet();
|
||||||
|
|
||||||
for (son_id_type son_id : _sons) {
|
|
||||||
if (!is_active_son(son_id)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const object* obj = plugin.database().find_object(object_id);
|
void peerplays_sidechain_plugin_impl::process_deposits() {
|
||||||
const chain::proposal_object* proposal = dynamic_cast<const chain::proposal_object*>(obj);
|
net_manager->process_deposits();
|
||||||
|
|
||||||
if(proposal == nullptr || (proposal->available_active_approvals.find(get_son_object(son_id).son_account) != proposal->available_active_approvals.end())) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
void peerplays_sidechain_plugin_impl::process_withdrawals() {
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_report_down_operation>::value) {
|
net_manager->process_withdrawals();
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
void peerplays_sidechain_plugin_impl::on_applied_block(const signed_block &b) {
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_delete_operation>::value) {
|
schedule_son_processing();
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_update_operation>::value) {
|
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_deposit_create_operation>::value) {
|
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_deposit_process_operation>::value) {
|
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_withdraw_create_operation>::value) {
|
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(proposal->proposed_transaction.operations.size() == 1
|
|
||||||
&& proposal->proposed_transaction.operations[0].which() == chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value) {
|
|
||||||
approve_proposal( son_id, proposal->id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace detail
|
} // end namespace detail
|
||||||
|
|
||||||
peerplays_sidechain_plugin::peerplays_sidechain_plugin() :
|
peerplays_sidechain_plugin::peerplays_sidechain_plugin() :
|
||||||
my( new detail::peerplays_sidechain_plugin_impl(*this) )
|
my(new detail::peerplays_sidechain_plugin_impl(*this)) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
peerplays_sidechain_plugin::~peerplays_sidechain_plugin()
|
peerplays_sidechain_plugin::~peerplays_sidechain_plugin() {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string peerplays_sidechain_plugin::plugin_name()const
|
std::string peerplays_sidechain_plugin::plugin_name() const {
|
||||||
{
|
|
||||||
return "peerplays_sidechain";
|
return "peerplays_sidechain";
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin::plugin_set_program_options(
|
void peerplays_sidechain_plugin::plugin_set_program_options(
|
||||||
boost::program_options::options_description &cli,
|
boost::program_options::options_description &cli,
|
||||||
boost::program_options::options_description& cfg)
|
boost::program_options::options_description &cfg) {
|
||||||
{
|
|
||||||
ilog("peerplays sidechain plugin: plugin_set_program_options()");
|
|
||||||
my->plugin_set_program_options(cli, cfg);
|
my->plugin_set_program_options(cli, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin::plugin_initialize(const boost::program_options::variables_map& options)
|
void peerplays_sidechain_plugin::plugin_initialize(const boost::program_options::variables_map &options) {
|
||||||
{
|
|
||||||
ilog("peerplays sidechain plugin: plugin_initialize()");
|
ilog("peerplays sidechain plugin: plugin_initialize()");
|
||||||
my->plugin_initialize(options);
|
my->plugin_initialize(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void peerplays_sidechain_plugin::plugin_startup()
|
void peerplays_sidechain_plugin::plugin_startup() {
|
||||||
{
|
|
||||||
ilog("peerplays sidechain plugin: plugin_startup()");
|
ilog("peerplays sidechain plugin: plugin_startup()");
|
||||||
my->plugin_startup();
|
my->plugin_startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<chain::son_id_type>& peerplays_sidechain_plugin::get_sons()
|
std::set<chain::son_id_type> &peerplays_sidechain_plugin::get_sons() {
|
||||||
{
|
|
||||||
return my->get_sons();
|
return my->get_sons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -597,30 +576,20 @@ son_id_type& peerplays_sidechain_plugin::get_current_son_id() {
|
||||||
return my->get_current_son_id();
|
return my->get_current_son_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
son_object peerplays_sidechain_plugin::get_son_object(son_id_type son_id)
|
son_object peerplays_sidechain_plugin::get_son_object(son_id_type son_id) {
|
||||||
{
|
|
||||||
return my->get_son_object(son_id);
|
return my->get_son_object(son_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peerplays_sidechain_plugin::is_active_son(son_id_type son_id)
|
bool peerplays_sidechain_plugin::is_active_son(son_id_type son_id) {
|
||||||
{
|
|
||||||
return my->is_active_son(son_id);
|
return my->is_active_son(son_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<chain::public_key_type, fc::ecc::private_key>& peerplays_sidechain_plugin::get_private_keys()
|
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(son_id_type son_id) {
|
||||||
{
|
|
||||||
return my->get_private_keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(son_id_type son_id)
|
|
||||||
{
|
|
||||||
return my->get_private_key(son_id);
|
return my->get_private_key(son_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(chain::public_key_type public_key)
|
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(chain::public_key_type public_key) {
|
||||||
{
|
|
||||||
return my->get_private_key(public_key);
|
return my->get_private_key(public_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
||||||
plugin(_plugin),
|
plugin(_plugin),
|
||||||
database(_plugin.database())
|
database(_plugin.database()) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sidechain_net_handler::~sidechain_net_handler() {
|
sidechain_net_handler::~sidechain_net_handler() {
|
||||||
|
|
@ -47,6 +46,14 @@ std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string sidechain_net_handler::get_private_key(std::string public_key) {
|
||||||
|
auto private_key_itr = private_keys.find(public_key);
|
||||||
|
if (private_key_itr != private_keys.end()) {
|
||||||
|
return private_key_itr->second;
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_data &sed) {
|
void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_data &sed) {
|
||||||
ilog("sidechain_event_data:");
|
ilog("sidechain_event_data:");
|
||||||
ilog(" timestamp: ${timestamp}", ("timestamp", sed.timestamp));
|
ilog(" timestamp: ${timestamp}", ("timestamp", sed.timestamp));
|
||||||
|
|
@ -87,7 +94,6 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
||||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||||
|
|
||||||
//ilog("sidechain_net_handler: sending proposal for son wallet deposit create operation by ${son}", ("son", son_id));
|
|
||||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||||
try {
|
try {
|
||||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
|
|
@ -130,7 +136,6 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
||||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||||
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime);
|
||||||
|
|
||||||
//ilog("sidechain_net_handler: sending proposal for son wallet withdraw create operation by ${son}", ("son", son_id));
|
|
||||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||||
try {
|
try {
|
||||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
|
|
@ -147,17 +152,12 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
||||||
FC_ASSERT(false, "Invalid sidechain event");
|
FC_ASSERT(false, "Invalid sidechain event");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler::recreate_primary_wallet() {
|
|
||||||
FC_ASSERT(false, "recreate_primary_wallet not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
void sidechain_net_handler::process_deposits() {
|
void sidechain_net_handler::process_deposits() {
|
||||||
const auto &idx = plugin.database().get_index_type<son_wallet_deposit_index>().indices().get<by_sidechain_and_processed>();
|
const auto &idx = plugin.database().get_index_type<son_wallet_deposit_index>().indices().get<by_sidechain_and_processed>();
|
||||||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false));
|
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false));
|
||||||
|
|
||||||
std::for_each(idx_range.first, idx_range.second,
|
std::for_each(idx_range.first, idx_range.second,
|
||||||
[&](const son_wallet_deposit_object &swdo) {
|
[&](const son_wallet_deposit_object &swdo) {
|
||||||
|
|
||||||
ilog("Deposit to process: ${swdo}", ("swdo", swdo));
|
ilog("Deposit to process: ${swdo}", ("swdo", swdo));
|
||||||
|
|
||||||
process_deposit(swdo);
|
process_deposit(swdo);
|
||||||
|
|
@ -192,7 +192,6 @@ void sidechain_net_handler::process_withdrawals() {
|
||||||
|
|
||||||
std::for_each(idx_range.first, idx_range.second,
|
std::for_each(idx_range.first, idx_range.second,
|
||||||
[&](const son_wallet_withdraw_object &swwo) {
|
[&](const son_wallet_withdraw_object &swwo) {
|
||||||
|
|
||||||
ilog("Withdraw to process: ${swwo}", ("swwo", swwo));
|
ilog("Withdraw to process: ${swwo}", ("swwo", swwo));
|
||||||
|
|
||||||
process_withdrawal(swwo);
|
process_withdrawal(swwo);
|
||||||
|
|
@ -221,5 +220,16 @@ void sidechain_net_handler::process_withdrawals() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
void sidechain_net_handler::recreate_primary_wallet() {
|
||||||
|
FC_ASSERT(false, "recreate_primary_wallet not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sidechain_net_handler::process_deposit(const son_wallet_deposit_object &swdo) {
|
||||||
|
FC_ASSERT(false, "process_deposit not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sidechain_net_handler::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
||||||
|
FC_ASSERT(false, "process_withdrawal not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,30 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/algorithm/hex.hpp>
|
#include <boost/algorithm/hex.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
#include <fc/crypto/base64.hpp>
|
#include <fc/crypto/base64.hpp>
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
#include <fc/network/ip.hpp>
|
#include <fc/network/ip.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
|
#include <graphene/chain/protocol/son_wallet.hpp>
|
||||||
#include <graphene/chain/sidechain_address_object.hpp>
|
#include <graphene/chain/sidechain_address_object.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_info.hpp>
|
||||||
#include <graphene/chain/son_wallet_object.hpp>
|
#include <graphene/chain/son_wallet_object.hpp>
|
||||||
#include <graphene/chain/protocol/son_wallet.hpp>
|
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
bitcoin_rpc_client::bitcoin_rpc_client( std::string _ip, uint32_t _rpc, std::string _user, std::string _password ):
|
bitcoin_rpc_client::bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password) :
|
||||||
ip( _ip ), rpc_port( _rpc ), user( _user ), password( _password )
|
ip(_ip),
|
||||||
{
|
rpc_port(_rpc),
|
||||||
|
user(_user),
|
||||||
|
password(_password),
|
||||||
|
wallet(_wallet),
|
||||||
|
wallet_password(_wallet_password) {
|
||||||
authorization.key = "Authorization";
|
authorization.key = "Authorization";
|
||||||
authorization.val = "Basic " + fc::base64_encode(user + ":" + password);
|
authorization.val = "Basic " + fc::base64_encode(user + ":" + password);
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +66,7 @@ std::string bitcoin_rpc_client::addmultisigaddress(const std::vector<std::string
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.count("error") && !json.get_child("error").empty()) {
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("BTC multisig address creation failed! Reply: ${msg}", ("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +92,6 @@ std::string bitcoin_rpc_client::createrawtransaction(const std::vector<btc_txout
|
||||||
}
|
}
|
||||||
body += std::string("]] }");
|
body += std::string("]] }");
|
||||||
|
|
||||||
ilog(body);
|
|
||||||
|
|
||||||
const auto reply = send_post_request(body);
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
if (reply.body.empty()) {
|
if (reply.body.empty()) {
|
||||||
|
|
@ -105,11 +107,67 @@ std::string bitcoin_rpc_client::createrawtransaction(const std::vector<btc_txout
|
||||||
if (json.count("result"))
|
if (json.count("result"))
|
||||||
return ss.str();
|
return ss.str();
|
||||||
} else if (json.count("error") && !json.get_child("error").empty()) {
|
} else if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("Failed to create raw transaction: [${body}]! Reply: ${msg}", ("body", body)("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string bitcoin_rpc_client::createwallet(const std::string &wallet_name) {
|
||||||
|
std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"createwallet\", \"method\": "
|
||||||
|
"\"createwallet\", \"params\": [\"" +
|
||||||
|
wallet_name + "\"] }");
|
||||||
|
|
||||||
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
|
if (reply.body.empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (reply.status == 200) {
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, json.get_child("result"));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bitcoin_rpc_client::encryptwallet(const std::string &passphrase) {
|
||||||
|
std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"encryptwallet\", \"method\": "
|
||||||
|
"\"encryptwallet\", \"params\": [\"" +
|
||||||
|
passphrase + "\"] }");
|
||||||
|
|
||||||
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
|
if (reply.body.empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (reply.status == 200) {
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, json.get_child("result"));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t bitcoin_rpc_client::estimatesmartfee() {
|
uint64_t bitcoin_rpc_client::estimatesmartfee() {
|
||||||
static const auto confirmation_target_blocks = 6;
|
static const auto confirmation_target_blocks = 6;
|
||||||
|
|
||||||
|
|
@ -160,7 +218,7 @@ std::string bitcoin_rpc_client::getblock(const std::string &block_hash, int32_t
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.count("error") && !json.get_child("error").empty()) {
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("Bitcoin RPC call ${function} failed with reply '${msg}'", ("function", __FUNCTION__)("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +243,7 @@ void bitcoin_rpc_client::importaddress(const std::string &address_or_script) {
|
||||||
idump((address_or_script)(ss.str()));
|
idump((address_or_script)(ss.str()));
|
||||||
return;
|
return;
|
||||||
} else if (json.count("error") && !json.get_child("error").empty()) {
|
} else if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("Failed to import address [${addr}]! Reply: ${msg}", ("addr", address_or_script)("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,7 +275,7 @@ std::vector<btc_txout> bitcoin_rpc_client::listunspent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (json.count("error") && !json.get_child("error").empty()) {
|
} else if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("Failed to list unspent txo! Reply: ${msg}", ("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -254,18 +312,44 @@ std::vector<btc_txout> bitcoin_rpc_client::listunspent_by_address_and_amount(con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (json.count("error") && !json.get_child("error").empty()) {
|
} else if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("Failed to list unspent txo! Reply: ${msg}", ("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string bitcoin_rpc_client::loadwallet(const std::string &filename) {
|
||||||
|
std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"loadwallet\", \"method\": "
|
||||||
|
"\"loadwallet\", \"params\": [\"" +
|
||||||
|
filename + "\"] }");
|
||||||
|
|
||||||
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
|
if (reply.body.empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (reply.status == 200) {
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, json.get_child("result"));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void bitcoin_rpc_client::sendrawtransaction(const std::string &tx_hex) {
|
void bitcoin_rpc_client::sendrawtransaction(const std::string &tx_hex) {
|
||||||
const auto body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"sendrawtransaction\", "
|
const auto body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"sendrawtransaction\", "
|
||||||
"\"method\": \"sendrawtransaction\", \"params\": [") +
|
"\"method\": \"sendrawtransaction\", \"params\": [") +
|
||||||
std::string("\"") + tx_hex + std::string("\"") + std::string("] }");
|
std::string("\"") + tx_hex + std::string("\"") + std::string("] }");
|
||||||
|
|
||||||
ilog(body);
|
|
||||||
|
|
||||||
const auto reply = send_post_request(body);
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
if (reply.body.empty()) {
|
if (reply.body.empty()) {
|
||||||
|
|
@ -284,7 +368,7 @@ void bitcoin_rpc_client::sendrawtransaction(const std::string &tx_hex) {
|
||||||
if (error_code == -27) // transaction already in block chain
|
if (error_code == -27) // transaction already in block chain
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wlog("BTC tx is not sent! Reply: ${msg}", ("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,8 +382,6 @@ std::string bitcoin_rpc_client::signrawtransactionwithwallet(const std::string &
|
||||||
std::string params = "\"" + tx_hash + "\"";
|
std::string params = "\"" + tx_hash + "\"";
|
||||||
body = body + params + std::string("]}");
|
body = body + params + std::string("]}");
|
||||||
|
|
||||||
ilog(body);
|
|
||||||
|
|
||||||
const auto reply = send_post_request(body);
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
if (reply.body.empty()) {
|
if (reply.body.empty()) {
|
||||||
|
|
@ -316,24 +398,121 @@ std::string bitcoin_rpc_client::signrawtransactionwithwallet(const std::string &
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.count("error") && !json.get_child("error").empty()) {
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
wlog("BTC sign_raw_transaction_with_wallet failed! Reply: ${msg}", ("msg", ss.str()));
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
fc::http::reply bitcoin_rpc_client::send_post_request( std::string body )
|
std::string bitcoin_rpc_client::unloadwallet(const std::string &filename) {
|
||||||
{
|
std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"unloadwallet\", \"method\": "
|
||||||
|
"\"unloadwallet\", \"params\": [\"" +
|
||||||
|
filename + "\"] }");
|
||||||
|
|
||||||
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
|
if (reply.body.empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (reply.status == 200) {
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, json.get_child("result"));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bitcoin_rpc_client::walletlock() {
|
||||||
|
std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletlock\", \"method\": "
|
||||||
|
"\"walletlock\", \"params\": [] }");
|
||||||
|
|
||||||
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
|
if (reply.body.empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (reply.status == 200) {
|
||||||
|
std::stringstream ss;
|
||||||
|
boost::property_tree::json_parser::write_json(ss, json.get_child("result"));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_t timeout) {
|
||||||
|
std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletpassphrase\", \"method\": "
|
||||||
|
"\"walletpassphrase\", \"params\": [\"" +
|
||||||
|
passphrase + "\", " + std::to_string(timeout) + "] }");
|
||||||
|
|
||||||
|
const auto reply = send_post_request(body);
|
||||||
|
|
||||||
|
if (reply.body.empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
|
if (reply.status == 200) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.count("error") && !json.get_child("error").empty()) {
|
||||||
|
wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fc::http::reply bitcoin_rpc_client::send_post_request(std::string body, bool show_log) {
|
||||||
fc::http::connection conn;
|
fc::http::connection conn;
|
||||||
conn.connect_to(fc::ip::endpoint(fc::ip::address(ip), rpc_port));
|
conn.connect_to(fc::ip::endpoint(fc::ip::address(ip), rpc_port));
|
||||||
|
|
||||||
const auto url = "http://" + ip + ":" + std::to_string( rpc_port );
|
std::string url = "http://" + ip + ":" + std::to_string(rpc_port);
|
||||||
|
|
||||||
return conn.request( "POST", url, body, fc::http::headers{authorization} );
|
if (wallet.length() > 0) {
|
||||||
|
url = url + "/wallet/" + wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
fc::http::reply reply = conn.request("POST", url, body, fc::http::headers{authorization});
|
||||||
|
|
||||||
|
if (show_log) {
|
||||||
|
ilog("Request URL: ${url}", ("url", url));
|
||||||
|
ilog("Request: ${body}", ("body", body));
|
||||||
|
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
ilog("Response: ${ss}", ("ss", ss.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
zmq_listener::zmq_listener( std::string _ip, uint32_t _zmq ): ip( _ip ), zmq_port( _zmq ), ctx( 1 ), socket( ctx, ZMQ_SUB ) {
|
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) :
|
||||||
|
ip(_ip),
|
||||||
|
zmq_port(_zmq),
|
||||||
|
ctx(1),
|
||||||
|
socket(ctx, ZMQ_SUB) {
|
||||||
std::thread(&zmq_listener::handle_zmq, this).detach();
|
std::thread(&zmq_listener::handle_zmq, this).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,19 +561,24 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
|
||||||
rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>();
|
rpc_port = options.at("bitcoin-node-rpc-port").as<uint32_t>();
|
||||||
rpc_user = options.at("bitcoin-node-rpc-user").as<std::string>();
|
rpc_user = options.at("bitcoin-node-rpc-user").as<std::string>();
|
||||||
rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
|
rpc_password = options.at("bitcoin-node-rpc-password").as<std::string>();
|
||||||
|
wallet = "";
|
||||||
|
if (options.count("bitcoin-wallet")) {
|
||||||
|
wallet = options.at("bitcoin-wallet").as<std::string>();
|
||||||
|
}
|
||||||
|
wallet_password = "";
|
||||||
|
if (options.count("bitcoin-wallet-password")) {
|
||||||
|
wallet_password = options.at("bitcoin-wallet-password").as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
if( options.count("bitcoin-private-keys") )
|
if (options.count("bitcoin-private-key")) {
|
||||||
{
|
const std::vector<std::string> pub_priv_keys = options["bitcoin-private-key"].as<std::vector<std::string>>();
|
||||||
const std::vector<std::string> pub_priv_keys = options["bitcoin-private-keys"].as<std::vector<std::string>>();
|
for (const std::string &itr_key_pair : pub_priv_keys) {
|
||||||
for (const std::string& itr_key_pair : pub_priv_keys)
|
|
||||||
{
|
|
||||||
auto key_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr_key_pair, 5);
|
auto key_pair = graphene::app::dejsonify<std::pair<std::string, std::string>>(itr_key_pair, 5);
|
||||||
ilog("Public Key: ${public}", ("public", key_pair.first));
|
ilog("Bitcoin Public Key: ${public}", ("public", key_pair.first));
|
||||||
if(!key_pair.first.length() || !key_pair.second.length())
|
if (!key_pair.first.length() || !key_pair.second.length()) {
|
||||||
{
|
|
||||||
FC_THROW("Invalid public private key pair.");
|
FC_THROW("Invalid public private key pair.");
|
||||||
}
|
}
|
||||||
_private_keys[key_pair.first] = key_pair.second;
|
private_keys[key_pair.first] = key_pair.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,9 +590,12 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
|
||||||
FC_ASSERT(false);
|
FC_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
listener = std::unique_ptr<zmq_listener>( new zmq_listener( ip, zmq_port ) );
|
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(ip, rpc_port, rpc_user, rpc_password, wallet, wallet_password));
|
||||||
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>( new bitcoin_rpc_client( ip, rpc_port, rpc_user, rpc_password ) );
|
if (!wallet.empty()) {
|
||||||
|
bitcoin_client->loadwallet(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
listener = std::unique_ptr<zmq_listener>(new zmq_listener(ip, zmq_port));
|
||||||
listener->event_received.connect([this](const std::string &event_data) {
|
listener->event_received.connect([this](const std::string &event_data) {
|
||||||
std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach();
|
std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach();
|
||||||
});
|
});
|
||||||
|
|
@ -434,8 +621,6 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
||||||
}
|
}
|
||||||
string reply_str = create_multisignature_wallet(son_pubkeys_bitcoin);
|
string reply_str = create_multisignature_wallet(son_pubkeys_bitcoin);
|
||||||
|
|
||||||
ilog(reply_str);
|
|
||||||
|
|
||||||
std::stringstream active_pw_ss(reply_str);
|
std::stringstream active_pw_ss(reply_str);
|
||||||
boost::property_tree::ptree active_pw_pt;
|
boost::property_tree::ptree active_pw_pt;
|
||||||
boost::property_tree::read_json(active_pw_ss, active_pw_pt);
|
boost::property_tree::read_json(active_pw_ss, active_pw_pt);
|
||||||
|
|
@ -482,21 +667,11 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::process_deposits() {
|
|
||||||
sidechain_net_handler::process_deposits();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_object &swdo) {
|
void sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_object &swdo) {
|
||||||
ilog(__FUNCTION__);
|
|
||||||
transfer_deposit_to_primary_wallet(swdo);
|
transfer_deposit_to_primary_wallet(swdo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::process_withdrawals() {
|
|
||||||
sidechain_net_handler::process_withdrawals();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
void sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
||||||
ilog(__FUNCTION__);
|
|
||||||
transfer_withdrawal_from_primary_wallet(swwo);
|
transfer_withdrawal_from_primary_wallet(swwo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -516,12 +691,9 @@ std::string sidechain_net_handler_bitcoin::send_transaction( const std::string&
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet ( const std::string& tx_json )
|
std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet(const std::string &tx_json) {
|
||||||
{
|
|
||||||
std::string reply_str = tx_json;
|
std::string reply_str = tx_json;
|
||||||
|
|
||||||
ilog(reply_str);
|
|
||||||
|
|
||||||
std::stringstream ss_utx(reply_str);
|
std::stringstream ss_utx(reply_str);
|
||||||
boost::property_tree::ptree pt;
|
boost::property_tree::ptree pt;
|
||||||
boost::property_tree::read_json(ss_utx, pt);
|
boost::property_tree::read_json(ss_utx, pt);
|
||||||
|
|
@ -530,14 +702,21 @@ std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wallet_password.empty()) {
|
||||||
|
bitcoin_client->walletpassphrase(wallet_password, 60);
|
||||||
|
}
|
||||||
|
|
||||||
std::string unsigned_tx_hex = pt.get<std::string>("result");
|
std::string unsigned_tx_hex = pt.get<std::string>("result");
|
||||||
|
|
||||||
reply_str = bitcoin_client->signrawtransactionwithwallet(unsigned_tx_hex);
|
reply_str = bitcoin_client->signrawtransactionwithwallet(unsigned_tx_hex);
|
||||||
ilog(reply_str);
|
|
||||||
std::stringstream ss_stx(reply_str);
|
std::stringstream ss_stx(reply_str);
|
||||||
boost::property_tree::ptree stx_json;
|
boost::property_tree::ptree stx_json;
|
||||||
boost::property_tree::read_json(ss_stx, stx_json);
|
boost::property_tree::read_json(ss_stx, stx_json);
|
||||||
|
|
||||||
|
//if (!wallet_password.empty()) {
|
||||||
|
// bitcoin_client->walletlock();
|
||||||
|
//}
|
||||||
|
|
||||||
if (!(stx_json.count("error") && stx_json.get_child("error").empty()) || !stx_json.count("result") || !stx_json.get_child("result").count("hex")) {
|
if (!(stx_json.count("error") && stx_json.get_child("error").empty()) || !stx_json.count("result") || !stx_json.get_child("result").count("hex")) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -549,8 +728,7 @@ std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet
|
||||||
return reply_str;
|
return reply_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_bitcoin::transfer_all_btc(const std::string& from_address, const std::string& to_address)
|
std::string sidechain_net_handler_bitcoin::transfer_all_btc(const std::string &from_address, const std::string &to_address) {
|
||||||
{
|
|
||||||
uint64_t fee_rate = bitcoin_client->estimatesmartfee();
|
uint64_t fee_rate = bitcoin_client->estimatesmartfee();
|
||||||
uint64_t min_fee_rate = 1000;
|
uint64_t min_fee_rate = 1000;
|
||||||
fee_rate = std::max(fee_rate, min_fee_rate);
|
fee_rate = std::max(fee_rate, min_fee_rate);
|
||||||
|
|
@ -559,20 +737,15 @@ std::string sidechain_net_handler_bitcoin::transfer_all_btc(const std::string& f
|
||||||
double total_amount = 0.0;
|
double total_amount = 0.0;
|
||||||
std::vector<btc_txout> unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(from_address, 0);
|
std::vector<btc_txout> unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(from_address, 0);
|
||||||
|
|
||||||
if(unspent_utxo.size() == 0)
|
if (unspent_utxo.size() == 0) {
|
||||||
{
|
|
||||||
wlog("Failed to find UTXOs to spend for ${pw}", ("pw", from_address));
|
wlog("Failed to find UTXOs to spend for ${pw}", ("pw", from_address));
|
||||||
return "";
|
return "";
|
||||||
}
|
} else {
|
||||||
else
|
for (const auto &utx : unspent_utxo) {
|
||||||
{
|
|
||||||
for(const auto& utx: unspent_utxo)
|
|
||||||
{
|
|
||||||
total_amount += utx.amount_;
|
total_amount += utx.amount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(min_amount >= total_amount)
|
if (min_amount >= total_amount) {
|
||||||
{
|
|
||||||
wlog("Failed not enough BTC to transfer from ${fa}", ("fa", from_address));
|
wlog("Failed not enough BTC to transfer from ${fa}", ("fa", from_address));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -585,8 +758,7 @@ std::string sidechain_net_handler_bitcoin::transfer_all_btc(const std::string& f
|
||||||
return sign_and_send_transaction_with_wallet(reply_str);
|
return sign_and_send_transaction_with_wallet(reply_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet (const son_wallet_deposit_object &swdo)
|
std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet(const son_wallet_deposit_object &swdo) {
|
||||||
{
|
|
||||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto obj = idx.rbegin();
|
auto obj = idx.rbegin();
|
||||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
||||||
|
|
@ -629,8 +801,7 @@ std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet (c
|
||||||
std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wallet(const son_wallet_withdraw_object &swwo) {
|
std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wallet(const son_wallet_withdraw_object &swwo) {
|
||||||
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto obj = idx.rbegin();
|
auto obj = idx.rbegin();
|
||||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end())
|
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
||||||
{
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -650,20 +821,15 @@ std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wall
|
||||||
double total_amount = 0.0;
|
double total_amount = 0.0;
|
||||||
std::vector<btc_txout> unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0);
|
std::vector<btc_txout> unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0);
|
||||||
|
|
||||||
if(unspent_utxo.size() == 0)
|
if (unspent_utxo.size() == 0) {
|
||||||
{
|
|
||||||
wlog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address));
|
wlog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address));
|
||||||
return "";
|
return "";
|
||||||
}
|
} else {
|
||||||
else
|
for (const auto &utx : unspent_utxo) {
|
||||||
{
|
|
||||||
for(const auto& utx: unspent_utxo)
|
|
||||||
{
|
|
||||||
total_amount += utx.amount_;
|
total_amount += utx.amount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(min_amount > total_amount)
|
if (min_amount > total_amount) {
|
||||||
{
|
|
||||||
wlog("Failed not enough BTC to spend for ${pw}", ("pw", pw_address));
|
wlog("Failed not enough BTC to spend for ${pw}", ("pw", pw_address));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -671,8 +837,7 @@ std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wall
|
||||||
|
|
||||||
fc::flat_map<std::string, double> outs;
|
fc::flat_map<std::string, double> outs;
|
||||||
outs[swwo.withdraw_address] = swwo.withdraw_amount.value / 100000000.0;
|
outs[swwo.withdraw_address] = swwo.withdraw_amount.value / 100000000.0;
|
||||||
if((total_amount - min_amount) > 0.0)
|
if ((total_amount - min_amount) > 0.0) {
|
||||||
{
|
|
||||||
outs[pw_address] = total_amount - min_amount;
|
outs[pw_address] = total_amount - min_amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -693,7 +858,8 @@ void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "bitcoin" << "-" << v.out.hash_tx << "-" << v.out.n_vout;
|
ss << "bitcoin"
|
||||||
|
<< "-" << v.out.hash_tx << "-" << v.out.n_vout;
|
||||||
std::string sidechain_uid = ss.str();
|
std::string sidechain_uid = ss.str();
|
||||||
|
|
||||||
sidechain_event_data sed;
|
sidechain_event_data sed;
|
||||||
|
|
@ -726,7 +892,8 @@ std::vector<info_for_vin> sidechain_net_handler_bitcoin::extract_info_from_block
|
||||||
for (const auto &o : tx.get_child("vout")) {
|
for (const auto &o : tx.get_child("vout")) {
|
||||||
const auto script = o.second.get_child("scriptPubKey");
|
const auto script = o.second.get_child("scriptPubKey");
|
||||||
|
|
||||||
if( !script.count("addresses") ) continue;
|
if (!script.count("addresses"))
|
||||||
|
continue;
|
||||||
|
|
||||||
for (const auto &addr : script.get_child("addresses")) { // in which cases there can be more addresses?
|
for (const auto &addr : script.get_child("addresses")) { // in which cases there can be more addresses?
|
||||||
const auto address_base58 = addr.second.get_value<std::string>();
|
const auto address_base58 = addr.second.get_value<std::string>();
|
||||||
|
|
@ -747,5 +914,4 @@ std::vector<info_for_vin> sidechain_net_handler_bitcoin::extract_info_from_block
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,27 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <boost/algorithm/hex.hpp>
|
#include <boost/algorithm/hex.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
#include <fc/crypto/base64.hpp>
|
#include <fc/crypto/base64.hpp>
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
#include <fc/network/ip.hpp>
|
#include <fc/network/ip.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
|
#include <graphene/chain/protocol/son_wallet.hpp>
|
||||||
#include <graphene/chain/sidechain_address_object.hpp>
|
#include <graphene/chain/sidechain_address_object.hpp>
|
||||||
#include <graphene/chain/son_info.hpp>
|
#include <graphene/chain/son_info.hpp>
|
||||||
#include <graphene/chain/son_wallet_object.hpp>
|
#include <graphene/chain/son_wallet_object.hpp>
|
||||||
#include <graphene/chain/protocol/son_wallet.hpp>
|
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
sidechain_net_handler_peerplays::sidechain_net_handler_peerplays(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
sidechain_net_handler_peerplays::sidechain_net_handler_peerplays(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
||||||
sidechain_net_handler(_plugin, options) {
|
sidechain_net_handler(_plugin, options) {
|
||||||
sidechain = sidechain_type::peerplays;
|
sidechain = sidechain_type::peerplays;
|
||||||
plugin.database().applied_block.connect( [&] (const signed_block& b) { on_applied_block(b); } );
|
plugin.database().applied_block.connect([&](const signed_block &b) {
|
||||||
|
on_applied_block(b);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() {
|
sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() {
|
||||||
|
|
@ -31,17 +33,9 @@ sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() {
|
||||||
void sidechain_net_handler_peerplays::recreate_primary_wallet() {
|
void sidechain_net_handler_peerplays::recreate_primary_wallet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_peerplays::process_deposits() {
|
|
||||||
sidechain_net_handler::process_deposits();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_object &swdo) {
|
void sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_object &swdo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_peerplays::process_withdrawals() {
|
|
||||||
sidechain_net_handler::process_withdrawals();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sidechain_net_handler_peerplays::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
void sidechain_net_handler_peerplays::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +67,8 @@ void sidechain_net_handler_peerplays::on_applied_block(const signed_block& b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "peerplays" << "-" << trx.id().str() << "-" << operation_index;
|
ss << "peerplays"
|
||||||
|
<< "-" << trx.id().str() << "-" << operation_index;
|
||||||
std::string sidechain_uid = ss.str();
|
std::string sidechain_uid = ss.str();
|
||||||
|
|
||||||
sidechain_event_data sed;
|
sidechain_event_data sed;
|
||||||
|
|
@ -95,5 +90,4 @@ void sidechain_net_handler_peerplays::on_applied_block(const signed_block& b) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,7 @@ namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin) :
|
sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin) :
|
||||||
plugin(_plugin),
|
plugin(_plugin),
|
||||||
database(_plugin.database())
|
database(_plugin.database()) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sidechain_net_manager::~sidechain_net_manager() {
|
sidechain_net_manager::~sidechain_net_manager() {
|
||||||
|
|
@ -58,5 +57,4 @@ void sidechain_net_manager::process_withdrawals() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} } // graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue