clang-format formatting
This commit is contained in:
parent
47c10f0db0
commit
001f92127b
13 changed files with 911 additions and 1064 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/elliptic.hpp>
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <graphene/peerplays_sidechain/bitcoin_utils.hpp>
|
||||
#include <secp256k1.h>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
|
@ -35,11 +35,13 @@ static const unsigned char OP_GREATERTHAN = 0xa0;
|
|||
static const unsigned char OP_HASH160 = 0xa9;
|
||||
static const unsigned char OP_CHECKSIG = 0xac;
|
||||
|
||||
class WriteBytesStream{
|
||||
class WriteBytesStream {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -48,149 +50,128 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void writedata8(uint8_t obj)
|
||||
{
|
||||
write((unsigned char*)&obj, 1);
|
||||
void writedata8(uint8_t obj) {
|
||||
write((unsigned char *)&obj, 1);
|
||||
}
|
||||
|
||||
void writedata16(uint16_t obj)
|
||||
{
|
||||
obj = htole16(obj);
|
||||
write((unsigned char*)&obj, 2);
|
||||
void writedata16(uint16_t obj) {
|
||||
obj = htole16(obj);
|
||||
write((unsigned char *)&obj, 2);
|
||||
}
|
||||
|
||||
void writedata32(uint32_t obj)
|
||||
{
|
||||
obj = htole32(obj);
|
||||
write((unsigned char*)&obj, 4);
|
||||
void writedata32(uint32_t obj) {
|
||||
obj = htole32(obj);
|
||||
write((unsigned char *)&obj, 4);
|
||||
}
|
||||
|
||||
void writedata64(uint64_t obj)
|
||||
{
|
||||
obj = htole64(obj);
|
||||
write((unsigned char*)&obj, 8);
|
||||
void writedata64(uint64_t obj) {
|
||||
obj = htole64(obj);
|
||||
write((unsigned char *)&obj, 8);
|
||||
}
|
||||
|
||||
void write_compact_int(uint64_t val)
|
||||
{
|
||||
if (val < 253)
|
||||
{
|
||||
writedata8(val);
|
||||
}
|
||||
else if (val <= std::numeric_limits<unsigned short>::max())
|
||||
{
|
||||
writedata8(253);
|
||||
writedata16(val);
|
||||
}
|
||||
else if (val <= std::numeric_limits<unsigned int>::max())
|
||||
{
|
||||
writedata8(254);
|
||||
writedata32(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
writedata8(255);
|
||||
writedata64(val);
|
||||
void write_compact_int(uint64_t val) {
|
||||
if (val < 253) {
|
||||
writedata8(val);
|
||||
} else if (val <= std::numeric_limits<unsigned short>::max()) {
|
||||
writedata8(253);
|
||||
writedata16(val);
|
||||
} else if (val <= std::numeric_limits<unsigned int>::max()) {
|
||||
writedata8(254);
|
||||
writedata32(val);
|
||||
} else {
|
||||
writedata8(255);
|
||||
writedata64(val);
|
||||
}
|
||||
}
|
||||
|
||||
void writedata(const bytes& data)
|
||||
{
|
||||
void writedata(const bytes &data) {
|
||||
write_compact_int(data.size());
|
||||
write(&data[0], data.size());
|
||||
}
|
||||
|
||||
private:
|
||||
bytes& storage_;
|
||||
bytes &storage_;
|
||||
};
|
||||
|
||||
class ReadBytesStream{
|
||||
class ReadBytesStream {
|
||||
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_; }
|
||||
void set_pos(size_t pos)
|
||||
{
|
||||
if(pos > end_)
|
||||
size_t current_pos() const {
|
||||
return pos_;
|
||||
}
|
||||
void set_pos(size_t pos) {
|
||||
if (pos > end_)
|
||||
FC_THROW("Invalid position in BTC tx buffer");
|
||||
pos_ = pos;
|
||||
}
|
||||
|
||||
inline bool read( unsigned char* d, size_t s ) {
|
||||
if( end_ - pos_ >= s ) {
|
||||
memcpy( d, &storage_[pos_], s );
|
||||
pos_ += s;
|
||||
return true;
|
||||
}
|
||||
FC_THROW( "invalid bitcoin tx buffer" );
|
||||
inline bool read(unsigned char *d, size_t s) {
|
||||
if (end_ - pos_ >= s) {
|
||||
memcpy(d, &storage_[pos_], s);
|
||||
pos_ += s;
|
||||
return true;
|
||||
}
|
||||
FC_THROW("invalid bitcoin tx buffer");
|
||||
}
|
||||
|
||||
inline bool get( unsigned char& c )
|
||||
{
|
||||
if( pos_ < end_ ) {
|
||||
c = storage_[pos_++];
|
||||
return true;
|
||||
}
|
||||
FC_THROW( "invalid bitcoin tx buffer" );
|
||||
inline bool get(unsigned char &c) {
|
||||
if (pos_ < end_) {
|
||||
c = storage_[pos_++];
|
||||
return true;
|
||||
}
|
||||
FC_THROW("invalid bitcoin tx buffer");
|
||||
}
|
||||
|
||||
uint8_t readdata8()
|
||||
{
|
||||
uint8_t obj;
|
||||
read((unsigned char*)&obj, 1);
|
||||
return obj;
|
||||
uint8_t readdata8() {
|
||||
uint8_t obj;
|
||||
read((unsigned char *)&obj, 1);
|
||||
return obj;
|
||||
}
|
||||
uint16_t readdata16()
|
||||
{
|
||||
uint16_t obj;
|
||||
read((unsigned char*)&obj, 2);
|
||||
return le16toh(obj);
|
||||
uint16_t readdata16() {
|
||||
uint16_t obj;
|
||||
read((unsigned char *)&obj, 2);
|
||||
return le16toh(obj);
|
||||
}
|
||||
uint32_t readdata32()
|
||||
{
|
||||
uint32_t obj;
|
||||
read((unsigned char*)&obj, 4);
|
||||
return le32toh(obj);
|
||||
uint32_t readdata32() {
|
||||
uint32_t obj;
|
||||
read((unsigned char *)&obj, 4);
|
||||
return le32toh(obj);
|
||||
}
|
||||
uint64_t readdata64()
|
||||
{
|
||||
uint64_t obj;
|
||||
read((unsigned char*)&obj, 8);
|
||||
return le64toh(obj);
|
||||
uint64_t readdata64() {
|
||||
uint64_t obj;
|
||||
read((unsigned char *)&obj, 8);
|
||||
return le64toh(obj);
|
||||
}
|
||||
|
||||
uint64_t read_compact_int()
|
||||
{
|
||||
uint8_t size = readdata8();
|
||||
uint64_t ret = 0;
|
||||
if (size < 253)
|
||||
{
|
||||
ret = size;
|
||||
}
|
||||
else if (size == 253)
|
||||
{
|
||||
ret = readdata16();
|
||||
if (ret < 253)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
else if (size == 254)
|
||||
{
|
||||
ret = readdata32();
|
||||
if (ret < 0x10000u)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = readdata64();
|
||||
if (ret < 0x100000000ULL)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
if (ret > (uint64_t)0x02000000)
|
||||
FC_THROW("ReadCompactSize(): size too large");
|
||||
return ret;
|
||||
uint64_t read_compact_int() {
|
||||
uint8_t size = readdata8();
|
||||
uint64_t ret = 0;
|
||||
if (size < 253) {
|
||||
ret = size;
|
||||
} else if (size == 253) {
|
||||
ret = readdata16();
|
||||
if (ret < 253)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
} else if (size == 254) {
|
||||
ret = readdata32();
|
||||
if (ret < 0x10000u)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
} else {
|
||||
ret = readdata64();
|
||||
if (ret < 0x100000000ULL)
|
||||
FC_THROW("non-canonical ReadCompactSize()");
|
||||
}
|
||||
if (ret > (uint64_t)0x02000000)
|
||||
FC_THROW("ReadCompactSize(): size too large");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void readdata(bytes& data)
|
||||
{
|
||||
void readdata(bytes &data) {
|
||||
size_t s = read_compact_int();
|
||||
data.clear();
|
||||
data.resize(s);
|
||||
|
|
@ -198,38 +179,34 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
const bytes& storage_;
|
||||
const bytes &storage_;
|
||||
size_t pos_;
|
||||
size_t end_;
|
||||
};
|
||||
|
||||
void btc_outpoint::to_bytes(bytes& stream) const
|
||||
{
|
||||
void btc_outpoint::to_bytes(bytes &stream) const {
|
||||
WriteBytesStream str(stream);
|
||||
// TODO: write size?
|
||||
str.write((unsigned char*)hash.data(), hash.data_size());
|
||||
str.write((unsigned char *)hash.data(), hash.data_size());
|
||||
str.writedata32(n);
|
||||
}
|
||||
|
||||
size_t btc_outpoint::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
size_t btc_outpoint::fill_from_bytes(const bytes &data, size_t pos) {
|
||||
ReadBytesStream str(data, pos);
|
||||
// TODO: read size?
|
||||
str.read((unsigned char*)hash.data(), hash.data_size());
|
||||
str.read((unsigned char *)hash.data(), hash.data_size());
|
||||
n = str.readdata32();
|
||||
return str.current_pos();
|
||||
}
|
||||
|
||||
void btc_in::to_bytes(bytes& stream) const
|
||||
{
|
||||
void btc_in::to_bytes(bytes &stream) const {
|
||||
prevout.to_bytes(stream);
|
||||
WriteBytesStream str(stream);
|
||||
str.writedata(scriptSig);
|
||||
str.writedata32(nSequence);
|
||||
}
|
||||
|
||||
size_t btc_in::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
size_t btc_in::fill_from_bytes(const bytes &data, size_t pos) {
|
||||
pos = prevout.fill_from_bytes(data, pos);
|
||||
ReadBytesStream str(data, pos);
|
||||
str.readdata(scriptSig);
|
||||
|
|
@ -237,53 +214,46 @@ size_t btc_in::fill_from_bytes(const bytes& data, size_t pos)
|
|||
return str.current_pos();
|
||||
}
|
||||
|
||||
void btc_out::to_bytes(bytes& stream) const
|
||||
{
|
||||
void btc_out::to_bytes(bytes &stream) const {
|
||||
WriteBytesStream str(stream);
|
||||
str.writedata64(nValue);
|
||||
str.writedata(scriptPubKey);
|
||||
}
|
||||
|
||||
size_t btc_out::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
size_t btc_out::fill_from_bytes(const bytes &data, size_t pos) {
|
||||
ReadBytesStream str(data, pos);
|
||||
nValue = str.readdata64();
|
||||
str.readdata(scriptPubKey);
|
||||
return str.current_pos();
|
||||
}
|
||||
|
||||
void btc_tx::to_bytes(bytes& stream) const
|
||||
{
|
||||
void btc_tx::to_bytes(bytes &stream) const {
|
||||
WriteBytesStream str(stream);
|
||||
str.writedata32(nVersion);
|
||||
if(hasWitness)
|
||||
{
|
||||
if (hasWitness) {
|
||||
// write dummy inputs and flag
|
||||
str.write_compact_int(0);
|
||||
unsigned char flags = 1;
|
||||
str.put(flags);
|
||||
}
|
||||
str.write_compact_int(vin.size());
|
||||
for(const auto& in: vin)
|
||||
for (const auto &in : vin)
|
||||
in.to_bytes(stream);
|
||||
str.write_compact_int(vout.size());
|
||||
for(const auto& out: vout)
|
||||
for (const auto &out : vout)
|
||||
out.to_bytes(stream);
|
||||
if(hasWitness)
|
||||
{
|
||||
for(const auto& in: vin)
|
||||
{
|
||||
if (hasWitness) {
|
||||
for (const auto &in : vin) {
|
||||
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.writedata32(nLockTime);
|
||||
}
|
||||
|
||||
size_t btc_tx::fill_from_bytes(const bytes& data, size_t pos)
|
||||
{
|
||||
ReadBytesStream ds( data, pos );
|
||||
size_t btc_tx::fill_from_bytes(const bytes &data, size_t pos) {
|
||||
ReadBytesStream ds(data, pos);
|
||||
nVersion = ds.readdata32();
|
||||
unsigned char flags = 0;
|
||||
vin.clear();
|
||||
|
|
@ -293,43 +263,42 @@ size_t btc_tx::fill_from_bytes(const bytes& data, size_t pos)
|
|||
size_t vin_size = ds.read_compact_int();
|
||||
vin.resize(vin_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& in: vin)
|
||||
for (auto &in : vin)
|
||||
pos = in.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
if (vin_size == 0) {
|
||||
/* We read a dummy or an empty vin. */
|
||||
ds.get(flags);
|
||||
if (flags != 0) {
|
||||
size_t vin_size = ds.read_compact_int();
|
||||
vin.resize(vin_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& in: vin)
|
||||
pos = in.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
size_t vout_size = ds.read_compact_int();
|
||||
vout.resize(vout_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& out: vout)
|
||||
pos = out.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
hasWitness = true;
|
||||
}
|
||||
/* We read a dummy or an empty vin. */
|
||||
ds.get(flags);
|
||||
if (flags != 0) {
|
||||
size_t vin_size = ds.read_compact_int();
|
||||
vin.resize(vin_size);
|
||||
pos = ds.current_pos();
|
||||
for (auto &in : vin)
|
||||
pos = in.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
size_t vout_size = ds.read_compact_int();
|
||||
vout.resize(vout_size);
|
||||
pos = ds.current_pos();
|
||||
for (auto &out : vout)
|
||||
pos = out.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
hasWitness = true;
|
||||
}
|
||||
} else {
|
||||
/* We read a non-empty vin. Assume a normal vout follows. */
|
||||
/* We read a non-empty vin. Assume a normal vout follows. */
|
||||
size_t vout_size = ds.read_compact_int();
|
||||
vout.resize(vout_size);
|
||||
pos = ds.current_pos();
|
||||
for(auto& out: vout)
|
||||
for (auto &out : vout)
|
||||
pos = out.fill_from_bytes(data, pos);
|
||||
ds.set_pos(pos);
|
||||
}
|
||||
if (hasWitness) {
|
||||
/* The witness flag is present, and we support witnesses. */
|
||||
for (auto& in: vin)
|
||||
{
|
||||
for (auto &in : vin) {
|
||||
unsigned int size = ds.read_compact_int();
|
||||
in.scriptWitness.resize(size);
|
||||
for(auto& stack_item: in.scriptWitness)
|
||||
for (auto &stack_item : in.scriptWitness)
|
||||
ds.readdata(stack_item);
|
||||
}
|
||||
}
|
||||
|
|
@ -337,61 +306,56 @@ size_t btc_tx::fill_from_bytes(const bytes& data, size_t 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);
|
||||
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);
|
||||
if(data == 0)
|
||||
if (data == 0)
|
||||
str.put(OP_0);
|
||||
else if(data == 1)
|
||||
else if (data == 1)
|
||||
str.put(OP_1);
|
||||
else if(data == 2)
|
||||
else if (data == 2)
|
||||
str.put(OP_2);
|
||||
else if(data == 3)
|
||||
else if (data == 3)
|
||||
str.put(OP_3);
|
||||
else if(data == 4)
|
||||
else if (data == 4)
|
||||
str.put(OP_4);
|
||||
else if(data == 5)
|
||||
else if (data == 5)
|
||||
str.put(OP_5);
|
||||
else if(data == 6)
|
||||
else if (data == 6)
|
||||
str.put(OP_6);
|
||||
else if(data == 7)
|
||||
else if (data == 7)
|
||||
str.put(OP_7);
|
||||
else if(data == 8)
|
||||
else if (data == 8)
|
||||
str.put(OP_8);
|
||||
else if(data == 9)
|
||||
else if (data == 9)
|
||||
str.put(OP_9);
|
||||
else if(data == 10)
|
||||
else if (data == 10)
|
||||
str.put(OP_10);
|
||||
else if(data == 11)
|
||||
else if (data == 11)
|
||||
str.put(OP_11);
|
||||
else if(data == 12)
|
||||
else if (data == 12)
|
||||
str.put(OP_12);
|
||||
else if(data == 13)
|
||||
else if (data == 13)
|
||||
str.put(OP_13);
|
||||
else if(data == 14)
|
||||
else if (data == 14)
|
||||
str.put(OP_14);
|
||||
else if(data == 15)
|
||||
else if (data == 15)
|
||||
str.put(OP_15);
|
||||
else if(data == 16)
|
||||
else if (data == 16)
|
||||
str.put(OP_16);
|
||||
else
|
||||
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;
|
||||
bytes result;
|
||||
add_number_to_script(result, 0);
|
||||
for(auto& p: key_data)
|
||||
{
|
||||
for (auto &p : key_data) {
|
||||
total_weight += p.second;
|
||||
result.push_back(OP_SWAP);
|
||||
auto raw_data = p.first.serialize();
|
||||
|
|
@ -409,110 +373,110 @@ bytes generate_redeem_script(std::vector<std::pair<fc::ecc::public_key, int> > k
|
|||
}
|
||||
|
||||
/** The Bech32 character set for encoding. */
|
||||
const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
|
||||
/** Concatenate two byte arrays. */
|
||||
bytes cat(bytes x, const bytes& y) {
|
||||
x.insert(x.end(), y.begin(), y.end());
|
||||
return x;
|
||||
bytes cat(bytes x, const bytes &y) {
|
||||
x.insert(x.end(), y.begin(), y.end());
|
||||
return x;
|
||||
}
|
||||
|
||||
/** Expand a HRP for use in checksum computation. */
|
||||
bytes expand_hrp(const std::string& hrp) {
|
||||
bytes ret;
|
||||
ret.resize(hrp.size() * 2 + 1);
|
||||
for (size_t i = 0; i < hrp.size(); ++i) {
|
||||
unsigned char c = hrp[i];
|
||||
ret[i] = c >> 5;
|
||||
ret[i + hrp.size() + 1] = c & 0x1f;
|
||||
}
|
||||
ret[hrp.size()] = 0;
|
||||
return ret;
|
||||
bytes expand_hrp(const std::string &hrp) {
|
||||
bytes ret;
|
||||
ret.resize(hrp.size() * 2 + 1);
|
||||
for (size_t i = 0; i < hrp.size(); ++i) {
|
||||
unsigned char c = hrp[i];
|
||||
ret[i] = c >> 5;
|
||||
ret[i + hrp.size() + 1] = c & 0x1f;
|
||||
}
|
||||
ret[hrp.size()] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Find the polynomial with value coefficients mod the generator as 30-bit. */
|
||||
uint32_t polymod(const bytes& values) {
|
||||
uint32_t chk = 1;
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
uint8_t top = chk >> 25;
|
||||
chk = (chk & 0x1ffffff) << 5 ^ values[i] ^
|
||||
uint32_t polymod(const bytes &values) {
|
||||
uint32_t chk = 1;
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
uint8_t top = chk >> 25;
|
||||
chk = (chk & 0x1ffffff) << 5 ^ values[i] ^
|
||||
(-((top >> 0) & 1) & 0x3b6a57b2UL) ^
|
||||
(-((top >> 1) & 1) & 0x26508e6dUL) ^
|
||||
(-((top >> 2) & 1) & 0x1ea119faUL) ^
|
||||
(-((top >> 3) & 1) & 0x3d4233ddUL) ^
|
||||
(-((top >> 4) & 1) & 0x2a1462b3UL);
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
return chk;
|
||||
}
|
||||
|
||||
/** Create a checksum. */
|
||||
bytes bech32_checksum(const std::string& hrp, const bytes& values) {
|
||||
bytes enc = cat(expand_hrp(hrp), values);
|
||||
enc.resize(enc.size() + 6);
|
||||
uint32_t mod = polymod(enc) ^ 1;
|
||||
bytes ret;
|
||||
ret.resize(6);
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
ret[i] = (mod >> (5 * (5 - i))) & 31;
|
||||
}
|
||||
return ret;
|
||||
bytes bech32_checksum(const std::string &hrp, const bytes &values) {
|
||||
bytes enc = cat(expand_hrp(hrp), values);
|
||||
enc.resize(enc.size() + 6);
|
||||
uint32_t mod = polymod(enc) ^ 1;
|
||||
bytes ret;
|
||||
ret.resize(6);
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
ret[i] = (mod >> (5 * (5 - i))) & 31;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Encode a Bech32 string. */
|
||||
std::string bech32(const std::string& hrp, const bytes& values) {
|
||||
bytes checksum = bech32_checksum(hrp, values);
|
||||
bytes combined = cat(values, checksum);
|
||||
std::string ret = hrp + '1';
|
||||
ret.reserve(ret.size() + combined.size());
|
||||
for (size_t i = 0; i < combined.size(); ++i) {
|
||||
ret += charset[combined[i]];
|
||||
}
|
||||
return ret;
|
||||
std::string bech32(const std::string &hrp, const bytes &values) {
|
||||
bytes checksum = bech32_checksum(hrp, values);
|
||||
bytes combined = cat(values, checksum);
|
||||
std::string ret = hrp + '1';
|
||||
ret.reserve(ret.size() + combined.size());
|
||||
for (size_t i = 0; i < combined.size(); ++i) {
|
||||
ret += charset[combined[i]];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Convert from one power-of-2 number base to another. */
|
||||
template<int frombits, int tobits, bool pad>
|
||||
bool convertbits(bytes& out, const bytes& in) {
|
||||
int acc = 0;
|
||||
int bits = 0;
|
||||
const int maxv = (1 << tobits) - 1;
|
||||
const int max_acc = (1 << (frombits + tobits - 1)) - 1;
|
||||
for (size_t i = 0; i < in.size(); ++i) {
|
||||
int value = in[i];
|
||||
acc = ((acc << frombits) | value) & max_acc;
|
||||
bits += frombits;
|
||||
while (bits >= tobits) {
|
||||
bits -= tobits;
|
||||
out.push_back((acc >> bits) & maxv);
|
||||
}
|
||||
}
|
||||
if (pad) {
|
||||
if (bits) out.push_back((acc << (tobits - bits)) & maxv);
|
||||
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
template <int frombits, int tobits, bool pad>
|
||||
bool convertbits(bytes &out, const bytes &in) {
|
||||
int acc = 0;
|
||||
int bits = 0;
|
||||
const int maxv = (1 << tobits) - 1;
|
||||
const int max_acc = (1 << (frombits + tobits - 1)) - 1;
|
||||
for (size_t i = 0; i < in.size(); ++i) {
|
||||
int value = in[i];
|
||||
acc = ((acc << frombits) | value) & max_acc;
|
||||
bits += frombits;
|
||||
while (bits >= tobits) {
|
||||
bits -= tobits;
|
||||
out.push_back((acc >> bits) & maxv);
|
||||
}
|
||||
}
|
||||
if (pad) {
|
||||
if (bits)
|
||||
out.push_back((acc << (tobits - bits)) & maxv);
|
||||
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Encode a SegWit address. */
|
||||
std::string segwit_addr_encode(const std::string& hrp, uint8_t witver, const bytes& witprog) {
|
||||
bytes enc;
|
||||
enc.push_back(witver);
|
||||
convertbits<8, 5, true>(enc, witprog);
|
||||
std::string ret = bech32(hrp, enc);
|
||||
return ret;
|
||||
std::string segwit_addr_encode(const std::string &hrp, uint8_t witver, const bytes &witprog) {
|
||||
bytes enc;
|
||||
enc.push_back(witver);
|
||||
convertbits<8, 5, true>(enc, witprog);
|
||||
std::string ret = bech32(hrp, enc);
|
||||
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
|
||||
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());
|
||||
switch (network) {
|
||||
case(mainnet):
|
||||
case (mainnet):
|
||||
return segwit_addr_encode("bc", 0, wp);
|
||||
case(testnet):
|
||||
case(regtest):
|
||||
case (testnet):
|
||||
case (regtest):
|
||||
return segwit_addr_encode("tb", 0, wp);
|
||||
default:
|
||||
FC_THROW("Unknown bitcoin network type");
|
||||
|
|
@ -520,77 +484,68 @@ std::string p2wsh_address_from_redeem_script(const bytes& script, bitcoin_networ
|
|||
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;
|
||||
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());
|
||||
bytes shash(h.data(), h.data() + h.data_size());
|
||||
add_data_to_script(result, shash);
|
||||
return result;
|
||||
}
|
||||
|
||||
bytes hash_prevouts(const btc_tx& unsigned_tx)
|
||||
{
|
||||
bytes hash_prevouts(const btc_tx &unsigned_tx) {
|
||||
fc::sha256::encoder hasher;
|
||||
for(const auto& in: unsigned_tx.vin)
|
||||
{
|
||||
for (const auto &in : unsigned_tx.vin) {
|
||||
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());
|
||||
}
|
||||
fc::sha256 res = fc::sha256::hash(hasher.result());
|
||||
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;
|
||||
for(const auto& in: unsigned_tx.vin)
|
||||
{
|
||||
hasher.write(reinterpret_cast<const char*>(&in.nSequence), sizeof(in.nSequence));
|
||||
for (const auto &in : unsigned_tx.vin) {
|
||||
hasher.write(reinterpret_cast<const char *>(&in.nSequence), sizeof(in.nSequence));
|
||||
}
|
||||
fc::sha256 res = fc::sha256::hash(hasher.result());
|
||||
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;
|
||||
for(const auto& out: unsigned_tx.vout)
|
||||
{
|
||||
for (const auto &out : unsigned_tx.vout) {
|
||||
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());
|
||||
}
|
||||
fc::sha256 res = fc::sha256::hash(hasher.result());
|
||||
return bytes(res.data(), res.data() + res.data_size());
|
||||
}
|
||||
|
||||
const secp256k1_context_t* btc_get_context() {
|
||||
static secp256k1_context_t* ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN );
|
||||
return ctx;
|
||||
const secp256k1_context_t *btc_get_context() {
|
||||
static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||
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;
|
||||
int size = result.size();
|
||||
FC_ASSERT( secp256k1_ecdsa_sign( btc_get_context(),
|
||||
(unsigned char*) digest.data(),
|
||||
(unsigned char*) result.begin(),
|
||||
&size,
|
||||
(unsigned char*) priv_key.get_secret().data(),
|
||||
secp256k1_nonce_function_rfc6979,
|
||||
nullptr));
|
||||
FC_ASSERT(secp256k1_ecdsa_sign(btc_get_context(),
|
||||
(unsigned char *)digest.data(),
|
||||
(unsigned char *)result.begin(),
|
||||
&size,
|
||||
(unsigned char *)priv_key.get_secret().data(),
|
||||
secp256k1_nonce_function_rfc6979,
|
||||
nullptr));
|
||||
return bytes(result.begin(), result.begin() + size);
|
||||
}
|
||||
|
||||
std::vector<bytes> signatures_for_raw_transaction(const bytes& unsigned_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const bytes& redeem_script,
|
||||
const fc::ecc::private_key& priv_key)
|
||||
{
|
||||
std::vector<bytes> signatures_for_raw_transaction(const bytes &unsigned_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const bytes &redeem_script,
|
||||
const fc::ecc::private_key &priv_key) {
|
||||
btc_tx tx;
|
||||
tx.fill_from_bytes(unsigned_tx);
|
||||
|
||||
|
|
@ -604,27 +559,26 @@ std::vector<bytes> signatures_for_raw_transaction(const bytes& unsigned_tx,
|
|||
bytes hashOutputs = hash_outputs(tx);
|
||||
// calc digest for every input according to BIP143
|
||||
// implement SIGHASH_ALL scheme
|
||||
for(const auto& in: tx.vin)
|
||||
{
|
||||
for (const auto &in : tx.vin) {
|
||||
fc::sha256::encoder hasher;
|
||||
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*>(&hashSequence[0]), hashSequence.size());
|
||||
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 *>(&hashSequence[0]), hashSequence.size());
|
||||
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());
|
||||
bytes serializedScript;
|
||||
WriteBytesStream stream(serializedScript);
|
||||
stream.writedata(redeem_script);
|
||||
hasher.write(reinterpret_cast<const char*>(&serializedScript[0]), serializedScript.size());
|
||||
hasher.write(reinterpret_cast<const char *>(&serializedScript[0]), serializedScript.size());
|
||||
uint64_t amount = *cur_amount++;
|
||||
hasher.write(reinterpret_cast<const char*>(&amount), sizeof(amount));
|
||||
hasher.write(reinterpret_cast<const char*>(&in.nSequence), sizeof(in.nSequence));
|
||||
hasher.write(reinterpret_cast<const char*>(&hashOutputs[0]), hashOutputs.size());
|
||||
hasher.write(reinterpret_cast<const char*>(&tx.nLockTime), sizeof(tx.nLockTime));
|
||||
hasher.write(reinterpret_cast<const char *>(&amount), sizeof(amount));
|
||||
hasher.write(reinterpret_cast<const char *>(&in.nSequence), sizeof(in.nSequence));
|
||||
hasher.write(reinterpret_cast<const char *>(&hashOutputs[0]), hashOutputs.size());
|
||||
hasher.write(reinterpret_cast<const char *>(&tx.nLockTime), sizeof(tx.nLockTime));
|
||||
// add sigtype SIGHASH_ALL
|
||||
uint32_t sigtype = 1;
|
||||
hasher.write(reinterpret_cast<const char*>(&sigtype), sizeof(sigtype));
|
||||
hasher.write(reinterpret_cast<const char *>(&sigtype), sizeof(sigtype));
|
||||
|
||||
fc::sha256 digest = fc::sha256::hash(hasher.result());
|
||||
//std::vector<char> res = priv_key.sign(digest);
|
||||
|
|
@ -636,30 +590,24 @@ std::vector<bytes> signatures_for_raw_transaction(const bytes& unsigned_tx,
|
|||
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;
|
||||
tx.fill_from_bytes(unsigned_tx);
|
||||
bytes dummy_data;
|
||||
for(auto key: priv_keys)
|
||||
{
|
||||
if(key)
|
||||
{
|
||||
for (auto key : priv_keys) {
|
||||
if (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");
|
||||
// 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]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
} else {
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
tx.vin[i].scriptWitness.push_back(dummy_data);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& in: tx.vin)
|
||||
{
|
||||
for (auto &in : tx.vin) {
|
||||
in.scriptWitness.push_back(redeem_script);
|
||||
}
|
||||
|
||||
|
|
@ -669,17 +617,15 @@ bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, std::vector<uint64_
|
|||
return ret;
|
||||
}
|
||||
|
||||
bytes add_dummy_signatures_for_pw_transfer(const bytes& unsigned_tx,
|
||||
const bytes& redeem_script,
|
||||
unsigned int key_count)
|
||||
{
|
||||
bytes add_dummy_signatures_for_pw_transfer(const bytes &unsigned_tx,
|
||||
const bytes &redeem_script,
|
||||
unsigned int key_count) {
|
||||
btc_tx tx;
|
||||
tx.fill_from_bytes(unsigned_tx);
|
||||
|
||||
bytes dummy_data;
|
||||
for(auto& in: tx.vin)
|
||||
{
|
||||
for(unsigned i = 0; i < key_count; i++)
|
||||
for (auto &in : tx.vin) {
|
||||
for (unsigned i = 0; i < key_count; i++)
|
||||
in.scriptWitness.push_back(dummy_data);
|
||||
in.scriptWitness.push_back(redeem_script);
|
||||
}
|
||||
|
|
@ -690,11 +636,10 @@ bytes add_dummy_signatures_for_pw_transfer(const bytes& unsigned_tx,
|
|||
return ret;
|
||||
}
|
||||
|
||||
bytes partially_sign_pw_transfer_transaction(const bytes& partially_signed_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const fc::ecc::private_key& priv_key,
|
||||
unsigned int key_idx)
|
||||
{
|
||||
bytes partially_sign_pw_transfer_transaction(const bytes &partially_signed_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const fc::ecc::private_key &priv_key,
|
||||
unsigned int key_idx) {
|
||||
btc_tx tx;
|
||||
tx.fill_from_bytes(partially_signed_tx);
|
||||
FC_ASSERT(tx.vin.size() > 0);
|
||||
|
|
@ -703,29 +648,26 @@ bytes partially_sign_pw_transfer_transaction(const bytes& partially_signed_tx,
|
|||
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
|
||||
unsigned witness_idx = tx.vin[0].scriptWitness.size() - 2 - key_idx;
|
||||
for(unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
tx.vin[i].scriptWitness[witness_idx] = signatures[i];
|
||||
bytes ret;
|
||||
tx.to_bytes(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;
|
||||
tx.fill_from_bytes(unsigned_tx);
|
||||
bytes dummy_data;
|
||||
for(unsigned int i = 0; i < signature_set.size(); i++)
|
||||
{
|
||||
std::vector<bytes> signatures = signature_set[i];
|
||||
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
|
||||
for(unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]);
|
||||
for (unsigned int i = 0; i < signature_set.size(); i++) {
|
||||
std::vector<bytes> signatures = signature_set[i];
|
||||
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
|
||||
for (unsigned int i = 0; i < tx.vin.size(); 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);
|
||||
}
|
||||
|
||||
|
|
@ -735,4 +677,4 @@ bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx, const std::vector<
|
|||
return ret;
|
||||
}
|
||||
|
||||
}}
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include <graphene/peerplays_sidechain/defs.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <graphene/peerplays_sidechain/defs.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
|
|
@ -10,24 +10,23 @@ enum bitcoin_network {
|
|||
regtest
|
||||
};
|
||||
|
||||
bytes generate_redeem_script(std::vector<std::pair<fc::ecc::public_key, int> > key_data);
|
||||
std::string p2wsh_address_from_redeem_script(const bytes& script, bitcoin_network network = mainnet);
|
||||
bytes lock_script_for_redeem_script(const bytes& script);
|
||||
bytes generate_redeem_script(std::vector<std::pair<fc::ecc::public_key, int>> key_data);
|
||||
std::string p2wsh_address_from_redeem_script(const bytes &script, bitcoin_network network = mainnet);
|
||||
bytes lock_script_for_redeem_script(const bytes &script);
|
||||
|
||||
|
||||
std::vector<bytes> signatures_for_raw_transaction(const bytes& unsigned_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const bytes& redeem_script,
|
||||
const fc::ecc::private_key& priv_key);
|
||||
std::vector<bytes> signatures_for_raw_transaction(const bytes &unsigned_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const bytes &redeem_script,
|
||||
const fc::ecc::private_key &priv_key);
|
||||
|
||||
/*
|
||||
* unsigned_tx - tx, all inputs of which are spends of the PW P2SH address
|
||||
* returns signed transaction
|
||||
*/
|
||||
bytes sign_pw_transfer_transaction(const bytes& unsigned_tx,
|
||||
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);
|
||||
const bytes &redeem_script,
|
||||
const std::vector<fc::optional<fc::ecc::private_key>> &priv_keys);
|
||||
|
||||
///
|
||||
////// \brief Adds dummy signatures instead of real signatures
|
||||
|
|
@ -35,8 +34,8 @@ bytes sign_pw_transfer_transaction(const bytes& unsigned_tx,
|
|||
////// \param redeem_script
|
||||
////// \param key_count
|
||||
////// \return can be used as partially signed tx
|
||||
bytes add_dummy_signatures_for_pw_transfer(const bytes& unsigned_tx,
|
||||
const bytes& redeem_script,
|
||||
bytes add_dummy_signatures_for_pw_transfer(const bytes &unsigned_tx,
|
||||
const bytes &redeem_script,
|
||||
unsigned int key_count);
|
||||
|
||||
///
|
||||
|
|
@ -47,10 +46,10 @@ bytes add_dummy_signatures_for_pw_transfer(const bytes& unsigned_tx,
|
|||
/// \param key_idx
|
||||
/// \return
|
||||
///
|
||||
bytes partially_sign_pw_transfer_transaction(const bytes& partially_signed_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const fc::ecc::private_key& priv_key,
|
||||
unsigned int key_idx);
|
||||
bytes partially_sign_pw_transfer_transaction(const bytes &partially_signed_tx,
|
||||
std::vector<uint64_t> in_amounts,
|
||||
const fc::ecc::private_key &priv_key,
|
||||
unsigned int key_idx);
|
||||
|
||||
///
|
||||
/// \brief Creates ready to publish bitcoin transaction from unsigned tx and
|
||||
|
|
@ -61,50 +60,45 @@ bytes partially_sign_pw_transfer_transaction(const bytes& partially_signed_tx,
|
|||
/// \param redeem_script
|
||||
/// \return
|
||||
///
|
||||
bytes add_signatures_to_unsigned_tx(const bytes& unsigned_tx,
|
||||
const std::vector<std::vector<bytes> >& signatures,
|
||||
const bytes& redeem_script);
|
||||
bytes add_signatures_to_unsigned_tx(const bytes &unsigned_tx,
|
||||
const std::vector<std::vector<bytes>> &signatures,
|
||||
const bytes &redeem_script);
|
||||
|
||||
struct btc_outpoint
|
||||
{
|
||||
struct btc_outpoint {
|
||||
fc::uint256 hash;
|
||||
uint32_t n;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
void to_bytes(bytes &stream) const;
|
||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||
};
|
||||
|
||||
struct btc_in
|
||||
{
|
||||
struct btc_in {
|
||||
btc_outpoint prevout;
|
||||
bytes scriptSig;
|
||||
uint32_t nSequence;
|
||||
std::vector<bytes> scriptWitness;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
void to_bytes(bytes &stream) const;
|
||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||
};
|
||||
|
||||
struct btc_out
|
||||
{
|
||||
struct btc_out {
|
||||
int64_t nValue;
|
||||
bytes scriptPubKey;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
void to_bytes(bytes &stream) const;
|
||||
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_out> vout;
|
||||
int32_t nVersion;
|
||||
uint32_t nLockTime;
|
||||
bool hasWitness;
|
||||
|
||||
void to_bytes(bytes& stream) const;
|
||||
size_t fill_from_bytes(const bytes& data, size_t pos = 0);
|
||||
void to_bytes(bytes &stream) const;
|
||||
size_t fill_from_bytes(const bytes &data, size_t pos = 0);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/safe.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/asset.hpp>
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
|
|
@ -22,14 +22,11 @@ enum class sidechain_type {
|
|||
|
||||
using bytes = std::vector<unsigned char>;
|
||||
|
||||
struct prev_out
|
||||
{
|
||||
bool operator!=( const prev_out& obj ) const
|
||||
{
|
||||
if( this->hash_tx != obj.hash_tx ||
|
||||
struct prev_out {
|
||||
bool operator!=(const prev_out &obj) const {
|
||||
if (this->hash_tx != obj.hash_tx ||
|
||||
this->n_vout != obj.n_vout ||
|
||||
this->amount != obj.amount )
|
||||
{
|
||||
this->amount != obj.amount) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -40,16 +37,15 @@ struct prev_out
|
|||
uint64_t amount;
|
||||
};
|
||||
|
||||
struct info_for_vin
|
||||
{
|
||||
struct info_for_vin {
|
||||
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);
|
||||
|
||||
bool operator!=( const info_for_vin& obj ) const;
|
||||
bool operator!=(const info_for_vin &obj) const;
|
||||
|
||||
struct comparer {
|
||||
bool operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const;
|
||||
bool operator()(const info_for_vin &lhs, const info_for_vin &rhs) const;
|
||||
};
|
||||
|
||||
static uint64_t count_id_info_for_vin;
|
||||
|
|
@ -66,19 +62,19 @@ struct info_for_vin
|
|||
};
|
||||
|
||||
struct sidechain_event_data {
|
||||
fc::time_point_sec timestamp;
|
||||
sidechain_type sidechain;
|
||||
std::string sidechain_uid;
|
||||
std::string sidechain_transaction_id;
|
||||
std::string sidechain_from;
|
||||
std::string sidechain_to;
|
||||
std::string sidechain_currency;
|
||||
fc::safe<int64_t> sidechain_amount;
|
||||
chain::account_id_type peerplays_from;
|
||||
chain::account_id_type peerplays_to;
|
||||
chain::asset peerplays_asset;
|
||||
fc::time_point_sec timestamp;
|
||||
sidechain_type sidechain;
|
||||
std::string sidechain_uid;
|
||||
std::string sidechain_transaction_id;
|
||||
std::string sidechain_from;
|
||||
std::string sidechain_to;
|
||||
std::string sidechain_currency;
|
||||
fc::safe<int64_t> sidechain_amount;
|
||||
chain::account_id_type peerplays_from;
|
||||
chain::account_id_type peerplays_to;
|
||||
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,33 +7,30 @@
|
|||
namespace graphene { namespace peerplays_sidechain {
|
||||
using namespace chain;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class peerplays_sidechain_plugin_impl;
|
||||
namespace detail {
|
||||
class peerplays_sidechain_plugin_impl;
|
||||
}
|
||||
|
||||
class peerplays_sidechain_plugin : public graphene::app::plugin
|
||||
{
|
||||
public:
|
||||
peerplays_sidechain_plugin();
|
||||
virtual ~peerplays_sidechain_plugin();
|
||||
class peerplays_sidechain_plugin : public graphene::app::plugin {
|
||||
public:
|
||||
peerplays_sidechain_plugin();
|
||||
virtual ~peerplays_sidechain_plugin();
|
||||
|
||||
std::string plugin_name()const override;
|
||||
virtual void plugin_set_program_options(
|
||||
boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg) override;
|
||||
virtual void plugin_initialize(const boost::program_options::variables_map& options) override;
|
||||
virtual void plugin_startup() override;
|
||||
std::string plugin_name() const override;
|
||||
virtual void plugin_set_program_options(
|
||||
boost::program_options::options_description &cli,
|
||||
boost::program_options::options_description &cfg) override;
|
||||
virtual void plugin_initialize(const boost::program_options::variables_map &options) override;
|
||||
virtual void plugin_startup() override;
|
||||
|
||||
std::unique_ptr<detail::peerplays_sidechain_plugin_impl> my;
|
||||
std::unique_ptr<detail::peerplays_sidechain_plugin_impl> my;
|
||||
|
||||
std::set<chain::son_id_type>& get_sons();
|
||||
son_id_type& get_current_son_id();
|
||||
son_object get_son_object(son_id_type son_id);
|
||||
bool is_active_son(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);
|
||||
std::set<chain::son_id_type> &get_sons();
|
||||
son_id_type &get_current_son_id();
|
||||
son_object get_son_object(son_id_type son_id);
|
||||
bool is_active_son(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);
|
||||
};
|
||||
|
||||
} } //graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -12,37 +12,35 @@ namespace graphene { namespace peerplays_sidechain {
|
|||
|
||||
class sidechain_net_handler {
|
||||
public:
|
||||
sidechain_net_handler(peerplays_sidechain_plugin& _plugin, const boost::program_options::variables_map& options);
|
||||
virtual ~sidechain_net_handler();
|
||||
sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
|
||||
virtual ~sidechain_net_handler();
|
||||
|
||||
graphene::peerplays_sidechain::sidechain_type get_sidechain();
|
||||
std::vector<std::string> get_sidechain_deposit_addresses();
|
||||
std::vector<std::string> get_sidechain_withdraw_addresses();
|
||||
std::string get_private_key(std::string public_key);
|
||||
graphene::peerplays_sidechain::sidechain_type get_sidechain();
|
||||
std::vector<std::string> get_sidechain_deposit_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 process_deposits();
|
||||
void process_withdrawals();
|
||||
void sidechain_event_data_received(const sidechain_event_data &sed);
|
||||
void process_deposits();
|
||||
void process_withdrawals();
|
||||
|
||||
virtual void recreate_primary_wallet() = 0;
|
||||
virtual void process_deposit(const son_wallet_deposit_object& swdo) = 0;
|
||||
virtual void process_withdrawal(const son_wallet_withdraw_object& swwo) = 0;
|
||||
virtual void recreate_primary_wallet() = 0;
|
||||
virtual void process_deposit(const son_wallet_deposit_object &swdo) = 0;
|
||||
virtual void process_withdrawal(const son_wallet_withdraw_object &swwo) = 0;
|
||||
|
||||
protected:
|
||||
peerplays_sidechain_plugin& plugin;
|
||||
graphene::chain::database& database;
|
||||
graphene::peerplays_sidechain::sidechain_type sidechain;
|
||||
peerplays_sidechain_plugin &plugin;
|
||||
graphene::chain::database &database;
|
||||
graphene::peerplays_sidechain::sidechain_type sidechain;
|
||||
|
||||
std::map<std::string, std::string> private_keys;
|
||||
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 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 send_transaction( const std::string& transaction ) = 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 sign_transaction(const std::string &transaction) = 0;
|
||||
virtual std::string send_transaction(const std::string &transaction) = 0;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@
|
|||
#include <string>
|
||||
#include <zmq.hpp>
|
||||
|
||||
#include <fc/signals.hpp>
|
||||
#include <fc/network/http/connection.hpp>
|
||||
#include <fc/signals.hpp>
|
||||
#include <graphene/chain/son_wallet_deposit_object.hpp>
|
||||
#include <graphene/chain/son_wallet_withdraw_object.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
class btc_txout
|
||||
{
|
||||
class btc_txout {
|
||||
public:
|
||||
std::string txid_;
|
||||
unsigned int out_num_;
|
||||
|
|
@ -22,23 +21,22 @@ public:
|
|||
|
||||
class bitcoin_rpc_client {
|
||||
public:
|
||||
bitcoin_rpc_client( std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_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;
|
||||
|
||||
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 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);
|
||||
uint64_t estimatesmartfee();
|
||||
std::string getblock( const std::string& block_hash, int32_t verbosity = 2 );
|
||||
void importaddress( const std::string& address_or_script);
|
||||
std::string getblock(const std::string &block_hash, int32_t verbosity = 2);
|
||||
void importaddress(const std::string &address_or_script);
|
||||
std::vector<btc_txout> listunspent();
|
||||
std::vector<btc_txout> listunspent_by_address_and_amount(const std::string& address, double transfer_amount);
|
||||
void sendrawtransaction( const std::string& tx_hex );
|
||||
std::string signrawtransactionwithkey(const std::string& tx_hash, const std::string& private_key);
|
||||
std::string signrawtransactionwithwallet(const std::string& tx_hash);
|
||||
std::vector<btc_txout> listunspent_by_address_and_amount(const std::string &address, double transfer_amount);
|
||||
void sendrawtransaction(const std::string &tx_hex);
|
||||
std::string signrawtransactionwithkey(const std::string &tx_hash, const std::string &private_key);
|
||||
std::string signrawtransactionwithwallet(const std::string &tx_hash);
|
||||
|
||||
private:
|
||||
|
||||
fc::http::reply send_post_request( std::string body );
|
||||
fc::http::reply send_post_request(std::string body);
|
||||
|
||||
std::string ip;
|
||||
uint32_t rpc_port;
|
||||
|
|
@ -54,10 +52,13 @@ private:
|
|||
|
||||
class zmq_listener {
|
||||
public:
|
||||
zmq_listener( std::string _ip, uint32_t _zmq );
|
||||
bool connection_is_not_defined() const { return zmq_port == 0; }
|
||||
zmq_listener(std::string _ip, uint32_t _zmq);
|
||||
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:
|
||||
void handle_zmq();
|
||||
std::vector<zmq::message_t> receive_multipart();
|
||||
|
|
@ -73,12 +74,12 @@ private:
|
|||
|
||||
class sidechain_net_handler_bitcoin : public sidechain_net_handler {
|
||||
public:
|
||||
sidechain_net_handler_bitcoin(peerplays_sidechain_plugin& _plugin, const boost::program_options::variables_map& options);
|
||||
sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
|
||||
virtual ~sidechain_net_handler_bitcoin();
|
||||
|
||||
void recreate_primary_wallet();
|
||||
void process_deposit(const son_wallet_deposit_object& swdo);
|
||||
void process_withdrawal(const son_wallet_withdraw_object& swwo);
|
||||
void process_deposit(const son_wallet_deposit_object &swdo);
|
||||
void process_withdrawal(const son_wallet_withdraw_object &swwo);
|
||||
|
||||
private:
|
||||
std::string ip;
|
||||
|
|
@ -92,18 +93,17 @@ private:
|
|||
std::unique_ptr<zmq_listener> listener;
|
||||
std::unique_ptr<bitcoin_rpc_client> bitcoin_client;
|
||||
|
||||
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 sign_transaction( const std::string& transaction );
|
||||
std::string send_transaction( const std::string& transaction );
|
||||
std::string sign_and_send_transaction_with_wallet ( const std::string& tx_json );
|
||||
std::string transfer_all_btc(const std::string& from_address, const std::string& to_address);
|
||||
std::string transfer_deposit_to_primary_wallet (const son_wallet_deposit_object &swdo);
|
||||
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 sign_transaction(const std::string &transaction);
|
||||
std::string send_transaction(const std::string &transaction);
|
||||
std::string sign_and_send_transaction_with_wallet(const std::string &tx_json);
|
||||
std::string transfer_all_btc(const std::string &from_address, const std::string &to_address);
|
||||
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);
|
||||
|
||||
void handle_event( const std::string& event_data);
|
||||
std::vector<info_for_vin> extract_info_from_block( const std::string& _block );
|
||||
void handle_event(const std::string &event_data);
|
||||
std::vector<info_for_vin> extract_info_from_block(const std::string &_block);
|
||||
};
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -10,23 +10,20 @@ namespace graphene { namespace peerplays_sidechain {
|
|||
|
||||
class sidechain_net_handler_peerplays : public sidechain_net_handler {
|
||||
public:
|
||||
sidechain_net_handler_peerplays(peerplays_sidechain_plugin& _plugin, const boost::program_options::variables_map& options);
|
||||
virtual ~sidechain_net_handler_peerplays();
|
||||
sidechain_net_handler_peerplays(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options);
|
||||
virtual ~sidechain_net_handler_peerplays();
|
||||
|
||||
void recreate_primary_wallet();
|
||||
void process_deposit(const son_wallet_deposit_object& swdo);
|
||||
void process_withdrawal(const son_wallet_withdraw_object& swwo);
|
||||
void recreate_primary_wallet();
|
||||
void process_deposit(const son_wallet_deposit_object &swdo);
|
||||
void process_withdrawal(const son_wallet_withdraw_object &swwo);
|
||||
|
||||
private:
|
||||
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 sign_transaction(const std::string &transaction);
|
||||
std::string send_transaction(const std::string &transaction);
|
||||
|
||||
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 sign_transaction( const std::string& transaction );
|
||||
std::string send_transaction( const std::string& transaction );
|
||||
|
||||
void on_applied_block(const signed_block& b);
|
||||
|
||||
void on_applied_block(const signed_block &b);
|
||||
};
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -12,19 +12,18 @@ namespace graphene { namespace peerplays_sidechain {
|
|||
|
||||
class sidechain_net_manager {
|
||||
public:
|
||||
sidechain_net_manager(peerplays_sidechain_plugin& _plugin);
|
||||
sidechain_net_manager(peerplays_sidechain_plugin &_plugin);
|
||||
virtual ~sidechain_net_manager();
|
||||
|
||||
bool create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map& options);
|
||||
bool create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map &options);
|
||||
void recreate_primary_wallet();
|
||||
void process_deposits();
|
||||
void process_withdrawals();
|
||||
private:
|
||||
peerplays_sidechain_plugin& plugin;
|
||||
graphene::chain::database& database;
|
||||
std::vector<std::unique_ptr<sidechain_net_handler>> net_handlers;
|
||||
|
||||
private:
|
||||
peerplays_sidechain_plugin &plugin;
|
||||
graphene::chain::database &database;
|
||||
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 <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/range/algorithm_ext/insert.hpp>
|
||||
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/protocol/transfer.hpp>
|
||||
#include <graphene/chain/sidechain_address_object.hpp>
|
||||
#include <graphene/chain/son_wallet_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/utilities/key_conversion.hpp>
|
||||
|
||||
|
|
@ -19,157 +19,131 @@ namespace bpo = boost::program_options;
|
|||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
class peerplays_sidechain_plugin_impl
|
||||
{
|
||||
public:
|
||||
peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin& _plugin);
|
||||
virtual ~peerplays_sidechain_plugin_impl();
|
||||
class peerplays_sidechain_plugin_impl {
|
||||
public:
|
||||
peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin &_plugin);
|
||||
virtual ~peerplays_sidechain_plugin_impl();
|
||||
|
||||
void plugin_set_program_options(
|
||||
boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg);
|
||||
void plugin_initialize(const boost::program_options::variables_map& options);
|
||||
void plugin_startup();
|
||||
void plugin_set_program_options(
|
||||
boost::program_options::options_description &cli,
|
||||
boost::program_options::options_description &cfg);
|
||||
void plugin_initialize(const boost::program_options::variables_map &options);
|
||||
void plugin_startup();
|
||||
|
||||
std::set<chain::son_id_type>& get_sons();
|
||||
son_id_type& get_current_son_id();
|
||||
son_object get_son_object(son_id_type son_id);
|
||||
bool is_active_son(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);
|
||||
std::set<chain::son_id_type> &get_sons();
|
||||
son_id_type &get_current_son_id();
|
||||
son_object get_son_object(son_id_type son_id);
|
||||
bool is_active_son(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);
|
||||
|
||||
void schedule_heartbeat_loop();
|
||||
void heartbeat_loop();
|
||||
void schedule_son_processing();
|
||||
void son_processing();
|
||||
void approve_proposals();
|
||||
void create_son_down_proposals();
|
||||
void create_son_deregister_proposals();
|
||||
void recreate_primary_wallet();
|
||||
void process_deposits();
|
||||
void process_withdrawals();
|
||||
void schedule_heartbeat_loop();
|
||||
void heartbeat_loop();
|
||||
void schedule_son_processing();
|
||||
void son_processing();
|
||||
void approve_proposals();
|
||||
void create_son_down_proposals();
|
||||
void create_son_deregister_proposals();
|
||||
void recreate_primary_wallet();
|
||||
void process_deposits();
|
||||
void process_withdrawals();
|
||||
|
||||
private:
|
||||
peerplays_sidechain_plugin& plugin;
|
||||
private:
|
||||
peerplays_sidechain_plugin &plugin;
|
||||
|
||||
bool config_ready_son;
|
||||
bool config_ready_bitcoin;
|
||||
bool config_ready_peerplays;
|
||||
bool config_ready_son;
|
||||
bool config_ready_bitcoin;
|
||||
bool config_ready_peerplays;
|
||||
|
||||
son_id_type current_son_id;
|
||||
son_id_type current_son_id;
|
||||
|
||||
std::unique_ptr<peerplays_sidechain::sidechain_net_manager> net_manager;
|
||||
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> _son_processing_task;
|
||||
|
||||
void on_applied_block( const signed_block& b );
|
||||
std::unique_ptr<peerplays_sidechain::sidechain_net_manager> net_manager;
|
||||
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> _son_processing_task;
|
||||
|
||||
void on_applied_block(const signed_block &b);
|
||||
};
|
||||
|
||||
peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin& _plugin) :
|
||||
peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidechain_plugin &_plugin) :
|
||||
plugin(_plugin),
|
||||
config_ready_son(false),
|
||||
config_ready_bitcoin(false),
|
||||
config_ready_peerplays(false),
|
||||
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 {
|
||||
if( _heartbeat_task.valid() )
|
||||
if (_heartbeat_task.valid())
|
||||
_heartbeat_task.cancel_and_wait(__FUNCTION__);
|
||||
} catch(fc::canceled_exception&) {
|
||||
} catch (fc::canceled_exception &) {
|
||||
//Expected exception. Move along.
|
||||
} catch(fc::exception& e) {
|
||||
} catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
}
|
||||
|
||||
try {
|
||||
if( _son_processing_task.valid() )
|
||||
if (_son_processing_task.valid())
|
||||
_son_processing_task.cancel_and_wait(__FUNCTION__);
|
||||
} catch(fc::canceled_exception&) {
|
||||
} catch (fc::canceled_exception &) {
|
||||
//Expected exception. Move along.
|
||||
} catch(fc::exception& e) {
|
||||
} catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||
boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg)
|
||||
{
|
||||
boost::program_options::options_description &cli,
|
||||
boost::program_options::options_description &cfg) {
|
||||
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_example2 = fc::json::to_string(chain::son_id_type(6));
|
||||
|
||||
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());
|
||||
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());
|
||||
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))),
|
||||
"Tuple of [PublicKey, WIF private key] (may specify multiple times)");
|
||||
cli.add_options()
|
||||
("bitcoin-node-ip", bpo::value<string>()->default_value("99.79.189.95"), "IP address of Bitcoin node");
|
||||
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");
|
||||
cli.add_options()
|
||||
("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user");
|
||||
cli.add_options()
|
||||
("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password");
|
||||
cli.add_options()
|
||||
("bitcoin-wallet", bpo::value<string>(), "Bitcoin wallet");
|
||||
cli.add_options()
|
||||
("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password");
|
||||
cli.add_options()
|
||||
("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->
|
||||
DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
||||
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
|
||||
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());
|
||||
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());
|
||||
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))),
|
||||
"Tuple of [PublicKey, WIF private key] (may specify multiple times)");
|
||||
cli.add_options()("bitcoin-node-ip", bpo::value<string>()->default_value("99.79.189.95"), "IP address of Bitcoin node");
|
||||
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");
|
||||
cli.add_options()("bitcoin-node-rpc-user", bpo::value<string>()->default_value("1"), "Bitcoin RPC user");
|
||||
cli.add_options()("bitcoin-node-rpc-password", bpo::value<string>()->default_value("1"), "Bitcoin RPC password");
|
||||
cli.add_options()("bitcoin-wallet", bpo::value<string>(), "Bitcoin wallet");
|
||||
cli.add_options()("bitcoin-wallet-password", bpo::value<string>(), "Bitcoin wallet password");
|
||||
cli.add_options()("bitcoin-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
||||
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
|
||||
cfg.add(cli);
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map& options)
|
||||
{
|
||||
config_ready_son = (options.count( "son-id" ) || options.count( "son-ids" )) && options.count( "peerplays-private-key" );
|
||||
void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_options::variables_map &options) {
|
||||
config_ready_son = (options.count("son-id") || options.count("son-ids")) && options.count("peerplays-private-key");
|
||||
if (config_ready_son) {
|
||||
LOAD_VALUE_SET(options, "son-id", _sons, chain::son_id_type)
|
||||
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();
|
||||
|
||||
#ifndef SUPPORT_MULTIPLE_SONS
|
||||
FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" );
|
||||
FC_ASSERT(_sons.size() == 1, "Multiple SONs not supported");
|
||||
#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>>();
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -181,15 +155,17 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
|||
throw;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
net_manager = std::unique_ptr<sidechain_net_manager>(new sidechain_net_manager(plugin));
|
||||
|
||||
config_ready_bitcoin = options.count( "bitcoin-node-ip" ) &&
|
||||
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-wallet" ) && options.count( "bitcoin-wallet-password" ) &&*/
|
||||
options.count( "bitcoin-private-key" );
|
||||
config_ready_bitcoin = options.count("bitcoin-node-ip") &&
|
||||
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-wallet" ) && options.count( "bitcoin-wallet-password" ) &&*/
|
||||
options.count("bitcoin-private-key");
|
||||
if (config_ready_bitcoin) {
|
||||
net_manager->create_handler(sidechain_type::bitcoin, options);
|
||||
ilog("Bitcoin sidechain handler created");
|
||||
|
|
@ -220,8 +196,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
|||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::plugin_startup()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::plugin_startup() {
|
||||
if (config_ready_son) {
|
||||
ilog("Starting ${n} SON instances", ("n", _sons.size()));
|
||||
|
||||
|
|
@ -243,74 +218,69 @@ void peerplays_sidechain_plugin_impl::plugin_startup()
|
|||
}
|
||||
}
|
||||
|
||||
std::set<chain::son_id_type>& peerplays_sidechain_plugin_impl::get_sons()
|
||||
{
|
||||
return _sons;
|
||||
std::set<chain::son_id_type> &peerplays_sidechain_plugin_impl::get_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;
|
||||
}
|
||||
|
||||
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>();
|
||||
auto son_obj = idx.find( 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>();
|
||||
auto son_obj = idx.find(son_id);
|
||||
if (son_obj == idx.end())
|
||||
return {};
|
||||
return *son_obj;
|
||||
}
|
||||
|
||||
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>();
|
||||
auto son_obj = idx.find( 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>();
|
||||
auto son_obj = idx.find(son_id);
|
||||
if (son_obj == idx.end())
|
||||
return false;
|
||||
|
||||
const chain::global_property_object& gpo = plugin.database().get_global_properties();
|
||||
const chain::global_property_object &gpo = plugin.database().get_global_properties();
|
||||
vector<son_id_type> active_son_ids;
|
||||
active_son_ids.reserve(gpo.active_sons.size());
|
||||
std::transform(gpo.active_sons.begin(), gpo.active_sons.end(),
|
||||
std::inserter(active_son_ids, active_son_ids.end()),
|
||||
[](const son_info& swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
[](const son_info &swi) {
|
||||
return swi.son_id;
|
||||
});
|
||||
|
||||
auto it = std::find(active_son_ids.begin(), active_son_ids.end(), son_id);
|
||||
|
||||
return (it != active_son_ids.end());
|
||||
}
|
||||
|
||||
fc::ecc::private_key peerplays_sidechain_plugin_impl::get_private_key(son_id_type son_id)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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 );
|
||||
if( private_key_itr != private_keys.end() ) {
|
||||
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);
|
||||
if (private_key_itr != private_keys.end()) {
|
||||
return private_key_itr->second;
|
||||
}
|
||||
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();
|
||||
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();},
|
||||
next_wakeup, "SON Heartbeat Production");
|
||||
_heartbeat_task = fc::schedule([this] {
|
||||
heartbeat_loop();
|
||||
},
|
||||
next_wakeup, "SON Heartbeat Production");
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::heartbeat_loop() {
|
||||
schedule_heartbeat_loop();
|
||||
chain::database& d = plugin.database();
|
||||
chain::database &d = plugin.database();
|
||||
|
||||
for (son_id_type son_id : _sons) {
|
||||
if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) {
|
||||
|
|
@ -321,14 +291,14 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
|||
op.son_id = son_id;
|
||||
op.ts = fc::time_point::now() + fc::seconds(0);
|
||||
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(son_id), op);
|
||||
fc::future<bool> fut = fc::async( [&](){
|
||||
fc::future<bool> fut = fc::async([&]() {
|
||||
try {
|
||||
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));
|
||||
return true;
|
||||
} catch(fc::exception e){
|
||||
ilog("peerplays_sidechain_plugin_impl: sending heartbeat failed with exception ${e}",("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("peerplays_sidechain_plugin_impl: sending heartbeat failed with exception ${e}", ("e", e.what()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
@ -337,32 +307,32 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop()
|
|||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::schedule_son_processing()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::schedule_son_processing() {
|
||||
fc::time_point now = fc::time_point::now();
|
||||
int64_t time_to_next_son_processing = 500000;
|
||||
|
||||
fc::time_point next_wakeup( now + fc::microseconds( time_to_next_son_processing ) );
|
||||
fc::time_point next_wakeup(now + fc::microseconds(time_to_next_son_processing));
|
||||
|
||||
_son_processing_task = fc::schedule([this]{son_processing();},
|
||||
next_wakeup, "SON Processing");
|
||||
_son_processing_task = fc::schedule([this] {
|
||||
son_processing();
|
||||
},
|
||||
next_wakeup, "SON Processing");
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::son_processing()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::son_processing() {
|
||||
if (plugin.database().get_global_properties().active_sons.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
chain::son_id_type next_son_id = plugin.database().get_scheduled_son(1);
|
||||
ilog("peerplays_sidechain_plugin_impl: Scheduled SON ${son}",("son", next_son_id));
|
||||
ilog("peerplays_sidechain_plugin_impl: Scheduled SON ${son}", ("son", next_son_id));
|
||||
|
||||
// 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() ) {
|
||||
if (_sons.find(next_son_id) != _sons.end()) {
|
||||
|
||||
current_son_id = next_son_id;
|
||||
|
||||
|
|
@ -373,36 +343,33 @@ void peerplays_sidechain_plugin_impl::son_processing()
|
|||
process_deposits();
|
||||
|
||||
process_withdrawals();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::approve_proposals()
|
||||
{
|
||||
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));
|
||||
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 };
|
||||
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 {
|
||||
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));
|
||||
return true;
|
||||
} catch(fc::exception e){
|
||||
ilog("peerplays_sidechain_plugin_impl: sending approval failed with exception ${e}",("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("peerplays_sidechain_plugin_impl: sending approval failed with exception ${e}", ("e", e.what()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
fut.wait(fc::seconds(10));
|
||||
};
|
||||
|
||||
const auto& idx = plugin.database().get_index_type<proposal_index>().indices().get<by_id>();
|
||||
const auto &idx = plugin.database().get_index_type<proposal_index>().indices().get<by_id>();
|
||||
for (const auto &proposal : idx) {
|
||||
for (son_id_type son_id : _sons) {
|
||||
if (!is_active_son(son_id)) {
|
||||
|
|
@ -413,76 +380,65 @@ void peerplays_sidechain_plugin_impl::approve_proposals()
|
|||
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 );
|
||||
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_wallet_update_operation>::value) {
|
||||
approve_proposal( son_id, proposal.id );
|
||||
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 );
|
||||
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 );
|
||||
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 );
|
||||
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 );
|
||||
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_deregister_proposals()
|
||||
{
|
||||
chain::database& d = plugin.database();
|
||||
void peerplays_sidechain_plugin_impl::create_son_deregister_proposals() {
|
||||
chain::database &d = plugin.database();
|
||||
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)
|
||||
{
|
||||
if (sons_to_be_dereg.size() > 0) {
|
||||
// We shouldn't raise proposals for the SONs for which a de-reg
|
||||
// proposal is already raised.
|
||||
std::set<son_id_type> sons_being_dereg = d.get_sons_being_deregistered();
|
||||
for( auto& son : sons_to_be_dereg)
|
||||
{
|
||||
for (auto &son : sons_to_be_dereg) {
|
||||
// New SON to be deregistered
|
||||
if(sons_being_dereg.find(son) == sons_being_dereg.end() && my_son_id != son)
|
||||
{
|
||||
if (sons_being_dereg.find(son) == sons_being_dereg.end() && my_son_id != son) {
|
||||
// Creating the de-reg proposal
|
||||
auto op = d.create_son_deregister_proposal(son, get_son_object(my_son_id).son_account);
|
||||
if(op.valid())
|
||||
{
|
||||
if (op.valid()) {
|
||||
// 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));
|
||||
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);
|
||||
fc::future<bool> fut = fc::async( [&](){
|
||||
fc::future<bool> fut = fc::async([&]() {
|
||||
try {
|
||||
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));
|
||||
return true;
|
||||
} catch(fc::exception e){
|
||||
ilog("peerplays_sidechain_plugin_impl: sending son dereg proposal failed with exception ${e}",("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("peerplays_sidechain_plugin_impl: sending son dereg proposal failed with exception ${e}", ("e", e.what()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
@ -493,11 +449,10 @@ void peerplays_sidechain_plugin_impl::create_son_deregister_proposals()
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
chain::database& d = plugin.database();
|
||||
const chain::global_property_object& gpo = d.get_global_properties();
|
||||
chain::database &d = plugin.database();
|
||||
const chain::global_property_object &gpo = d.get_global_properties();
|
||||
|
||||
chain::son_report_down_operation son_down_op;
|
||||
son_down_op.payer = GRAPHENE_SON_ACCOUNT;
|
||||
|
|
@ -506,40 +461,40 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
|||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = get_son_object(plugin.get_current_son_id()).son_account;
|
||||
proposal_op.proposed_ops.push_back( op_wrapper( son_down_op ) );
|
||||
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
||||
proposal_op.expiration_time = time_point_sec( d.head_block_time().sec_since_epoch() + lifetime );
|
||||
proposal_op.proposed_ops.push_back(op_wrapper(son_down_op));
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(d.head_block_time().sec_since_epoch() + lifetime);
|
||||
return proposal_op;
|
||||
};
|
||||
|
||||
chain::database& d = plugin.database();
|
||||
const chain::global_property_object& gpo = d.get_global_properties();
|
||||
const chain::dynamic_global_property_object& dgpo = d.get_dynamic_global_properties();
|
||||
const auto& idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
|
||||
chain::database &d = plugin.database();
|
||||
const chain::global_property_object &gpo = d.get_global_properties();
|
||||
const chain::dynamic_global_property_object &dgpo = d.get_dynamic_global_properties();
|
||||
const auto &idx = d.get_index_type<chain::son_index>().indices().get<by_id>();
|
||||
std::set<son_id_type> sons_being_reported_down = d.get_sons_being_reported_down();
|
||||
chain::son_id_type my_son_id = get_current_son_id();
|
||||
for(auto son_inf: gpo.active_sons) {
|
||||
if(my_son_id == son_inf.son_id || (sons_being_reported_down.find(son_inf.son_id) != sons_being_reported_down.end())){
|
||||
for (auto son_inf : gpo.active_sons) {
|
||||
if (my_son_id == son_inf.son_id || (sons_being_reported_down.find(son_inf.son_id) != sons_being_reported_down.end())) {
|
||||
continue;
|
||||
}
|
||||
auto son_obj = idx.find( son_inf.son_id );
|
||||
auto son_obj = idx.find(son_inf.son_id);
|
||||
auto stats = son_obj->statistics(d);
|
||||
fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval;
|
||||
fc::time_point_sec last_active_ts = ((stats.last_active_timestamp > last_maintenance_time) ? stats.last_active_timestamp : last_maintenance_time);
|
||||
int64_t down_threshold = gpo.parameters.son_down_time();
|
||||
if(((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) &&
|
||||
((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
|
||||
ilog("peerplays_sidechain_plugin: sending son down proposal for ${t} from ${s}",("t",std::string(object_id_type(son_obj->id)))("s",std::string(object_id_type(my_son_id))));
|
||||
if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) &&
|
||||
((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
|
||||
ilog("peerplays_sidechain_plugin: sending son down proposal for ${t} from ${s}", ("t", std::string(object_id_type(son_obj->id)))("s", std::string(object_id_type(my_son_id))));
|
||||
chain::proposal_create_operation op = create_son_down_proposal(son_inf.son_id, last_active_ts);
|
||||
chain::signed_transaction trx = d.create_signed_transaction(plugin.get_private_key(get_son_object(my_son_id).signing_key), op);
|
||||
fc::future<bool> fut = fc::async( [&](){
|
||||
fc::future<bool> fut = fc::async([&]() {
|
||||
try {
|
||||
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));
|
||||
return true;
|
||||
} catch(fc::exception e){
|
||||
ilog("peerplays_sidechain_plugin_impl: sending son down proposal failed with exception ${e}",("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("peerplays_sidechain_plugin_impl: sending son down proposal failed with exception ${e}", ("e", e.what()));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
@ -548,90 +503,74 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals()
|
|||
}
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::recreate_primary_wallet()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::recreate_primary_wallet() {
|
||||
net_manager->recreate_primary_wallet();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_deposits()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::process_deposits() {
|
||||
net_manager->process_deposits();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::process_withdrawals()
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::process_withdrawals() {
|
||||
net_manager->process_withdrawals();
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin_impl::on_applied_block( const signed_block& b )
|
||||
{
|
||||
void peerplays_sidechain_plugin_impl::on_applied_block(const signed_block &b) {
|
||||
schedule_son_processing();
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::string peerplays_sidechain_plugin::plugin_name()const
|
||||
{
|
||||
std::string peerplays_sidechain_plugin::plugin_name() const {
|
||||
return "peerplays_sidechain";
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin::plugin_set_program_options(
|
||||
boost::program_options::options_description& cli,
|
||||
boost::program_options::options_description& cfg)
|
||||
{
|
||||
my->plugin_set_program_options(cli, cfg);
|
||||
boost::program_options::options_description &cli,
|
||||
boost::program_options::options_description &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()");
|
||||
my->plugin_initialize(options);
|
||||
}
|
||||
|
||||
void peerplays_sidechain_plugin::plugin_startup()
|
||||
{
|
||||
void peerplays_sidechain_plugin::plugin_startup() {
|
||||
ilog("peerplays sidechain plugin: plugin_startup()");
|
||||
my->plugin_startup();
|
||||
}
|
||||
|
||||
std::set<chain::son_id_type>& peerplays_sidechain_plugin::get_sons()
|
||||
{
|
||||
return my->get_sons();
|
||||
std::set<chain::son_id_type> &peerplays_sidechain_plugin::get_sons() {
|
||||
return my->get_sons();
|
||||
}
|
||||
|
||||
son_id_type& peerplays_sidechain_plugin::get_current_son_id() {
|
||||
return my->get_current_son_id();
|
||||
son_id_type &peerplays_sidechain_plugin::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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(son_id_type son_id)
|
||||
{
|
||||
fc::ecc::private_key peerplays_sidechain_plugin::get_private_key(son_id_type 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)
|
||||
{
|
||||
return my->get_private_key(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);
|
||||
}
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@
|
|||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin& _plugin, const boost::program_options::variables_map& options) :
|
||||
plugin(_plugin),
|
||||
database(_plugin.database())
|
||||
{
|
||||
sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
||||
plugin(_plugin),
|
||||
database(_plugin.database()) {
|
||||
}
|
||||
|
||||
sidechain_net_handler::~sidechain_net_handler() {
|
||||
|
|
@ -24,52 +23,52 @@ graphene::peerplays_sidechain::sidechain_type sidechain_net_handler::get_sidecha
|
|||
std::vector<std::string> sidechain_net_handler::get_sidechain_deposit_addresses() {
|
||||
std::vector<std::string> result;
|
||||
|
||||
const auto& sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
|
||||
const auto& sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get<by_sidechain>();
|
||||
const auto& sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain);
|
||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
|
||||
const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get<by_sidechain>();
|
||||
const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain);
|
||||
std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second,
|
||||
[&result] (const sidechain_address_object& sao) {
|
||||
result.push_back(sao.deposit_address);
|
||||
});
|
||||
[&result](const sidechain_address_object &sao) {
|
||||
result.push_back(sao.deposit_address);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> sidechain_net_handler::get_sidechain_withdraw_addresses() {
|
||||
std::vector<std::string> result;
|
||||
|
||||
const auto& sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
|
||||
const auto& sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get<by_sidechain>();
|
||||
const auto& sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain);
|
||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>();
|
||||
const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get<by_sidechain>();
|
||||
const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain);
|
||||
std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second,
|
||||
[&result] (const sidechain_address_object& sao) {
|
||||
result.push_back(sao.withdraw_address);
|
||||
});
|
||||
[&result](const sidechain_address_object &sao) {
|
||||
result.push_back(sao.withdraw_address);
|
||||
});
|
||||
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() ) {
|
||||
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) {
|
||||
ilog( "sidechain_event_data:" );
|
||||
ilog( " timestamp: ${timestamp}", ( "timestamp", sed.timestamp ) );
|
||||
ilog( " sidechain: ${sidechain}", ( "sidechain", sed.sidechain ) );
|
||||
ilog( " sidechain_uid: ${uid}", ( "uid", sed.sidechain_uid ) );
|
||||
ilog( " sidechain_transaction_id: ${transaction_id}", ( "transaction_id", sed.sidechain_transaction_id ) );
|
||||
ilog( " sidechain_from: ${from}", ( "from", sed.sidechain_from ) );
|
||||
ilog( " sidechain_to: ${to}", ( "to", sed.sidechain_to ) );
|
||||
ilog( " sidechain_currency: ${currency}", ( "currency", sed.sidechain_currency ) );
|
||||
ilog( " sidechain_amount: ${amount}", ( "amount", sed.sidechain_amount ) );
|
||||
ilog( " peerplays_from: ${peerplays_from}", ( "peerplays_from", sed.peerplays_from ) );
|
||||
ilog( " peerplays_to: ${peerplays_to}", ( "peerplays_to", sed.peerplays_to ) );
|
||||
ilog( " peerplays_asset: ${peerplays_asset}", ( "peerplays_asset", sed.peerplays_asset ) );
|
||||
void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_data &sed) {
|
||||
ilog("sidechain_event_data:");
|
||||
ilog(" timestamp: ${timestamp}", ("timestamp", sed.timestamp));
|
||||
ilog(" sidechain: ${sidechain}", ("sidechain", sed.sidechain));
|
||||
ilog(" sidechain_uid: ${uid}", ("uid", sed.sidechain_uid));
|
||||
ilog(" sidechain_transaction_id: ${transaction_id}", ("transaction_id", sed.sidechain_transaction_id));
|
||||
ilog(" sidechain_from: ${from}", ("from", sed.sidechain_from));
|
||||
ilog(" sidechain_to: ${to}", ("to", sed.sidechain_to));
|
||||
ilog(" sidechain_currency: ${currency}", ("currency", sed.sidechain_currency));
|
||||
ilog(" sidechain_amount: ${amount}", ("amount", sed.sidechain_amount));
|
||||
ilog(" peerplays_from: ${peerplays_from}", ("peerplays_from", sed.peerplays_from));
|
||||
ilog(" peerplays_to: ${peerplays_to}", ("peerplays_to", sed.peerplays_to));
|
||||
ilog(" peerplays_asset: ${peerplays_asset}", ("peerplays_asset", sed.peerplays_asset));
|
||||
|
||||
const chain::global_property_object& gpo = database.get_global_properties();
|
||||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
// Deposit request
|
||||
if ((sed.peerplays_to == GRAPHENE_SON_ACCOUNT) && (sed.sidechain_currency.compare("1.3.0") != 0)) {
|
||||
|
|
@ -91,17 +90,17 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
if (plugin.is_active_son(son_id)) {
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(son_id).son_account;
|
||||
proposal_op.proposed_ops.emplace_back( op_wrapper( op ) );
|
||||
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.proposed_ops.emplace_back(op_wrapper(op));
|
||||
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);
|
||||
|
||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||
try {
|
||||
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));
|
||||
} catch(fc::exception e){
|
||||
ilog("sidechain_net_handler: sending proposal for son wallet deposit create operation by ${son} failed with exception ${e}", ("son", son_id) ("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("sidechain_net_handler: sending proposal for son wallet deposit create operation by ${son} failed with exception ${e}", ("son", son_id)("e", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,9 +110,9 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
// Withdrawal request
|
||||
if ((sed.peerplays_to == GRAPHENE_SON_ACCOUNT) && (sed.sidechain_currency.compare("1.3.0") == 0)) {
|
||||
// BTC Payout only (for now)
|
||||
const auto& sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_account_and_sidechain>();
|
||||
const auto& addr_itr = sidechain_addresses_idx.find(std::make_tuple(sed.peerplays_from, sidechain_type::bitcoin));
|
||||
if ( addr_itr == sidechain_addresses_idx.end() )
|
||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_account_and_sidechain>();
|
||||
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sed.peerplays_from, sidechain_type::bitcoin));
|
||||
if (addr_itr == sidechain_addresses_idx.end())
|
||||
return;
|
||||
|
||||
son_wallet_withdraw_create_operation op;
|
||||
|
|
@ -124,26 +123,26 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
op.peerplays_transaction_id = sed.sidechain_transaction_id;
|
||||
op.peerplays_from = sed.peerplays_from;
|
||||
op.peerplays_asset = sed.peerplays_asset;
|
||||
op.withdraw_sidechain = sidechain_type::bitcoin; // BTC payout only (for now)
|
||||
op.withdraw_address = addr_itr->withdraw_address; // BTC payout only (for now)
|
||||
op.withdraw_currency = "BTC"; // BTC payout only (for now)
|
||||
op.withdraw_sidechain = sidechain_type::bitcoin; // BTC payout only (for now)
|
||||
op.withdraw_address = addr_itr->withdraw_address; // BTC payout only (for now)
|
||||
op.withdraw_currency = "BTC"; // BTC payout only (for now)
|
||||
op.withdraw_amount = sed.peerplays_asset.amount * 1000; // BTC payout only (for now)
|
||||
|
||||
for (son_id_type son_id : plugin.get_sons()) {
|
||||
if (plugin.is_active_son(son_id)) {
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(son_id).son_account;
|
||||
proposal_op.proposed_ops.emplace_back( op_wrapper( op ) );
|
||||
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.proposed_ops.emplace_back(op_wrapper(op));
|
||||
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);
|
||||
|
||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op);
|
||||
try {
|
||||
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));
|
||||
} catch(fc::exception e){
|
||||
ilog("sidechain_net_handler: sending proposal for son wallet withdraw create operation by ${son} failed with exception ${e}", ("son", son_id) ("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("sidechain_net_handler: sending proposal for son wallet withdraw create operation by ${son} failed with exception ${e}", ("son", son_id)("e", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -154,87 +153,83 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_
|
|||
}
|
||||
|
||||
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_range = idx.equal_range(std::make_tuple(sidechain, false));
|
||||
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));
|
||||
|
||||
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);
|
||||
const chain::global_property_object &gpo = plugin.database().get_global_properties();
|
||||
|
||||
const chain::global_property_object& gpo = plugin.database().get_global_properties();
|
||||
son_wallet_deposit_process_operation p_op;
|
||||
p_op.payer = GRAPHENE_SON_ACCOUNT;
|
||||
p_op.son_wallet_deposit_id = swdo.id;
|
||||
|
||||
son_wallet_deposit_process_operation p_op;
|
||||
p_op.payer = GRAPHENE_SON_ACCOUNT;
|
||||
p_op.son_wallet_deposit_id = swdo.id;
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account;
|
||||
proposal_op.proposed_ops.emplace_back(op_wrapper(p_op));
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(plugin.database().head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account;
|
||||
proposal_op.proposed_ops.emplace_back( op_wrapper( p_op ) );
|
||||
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
||||
proposal_op.expiration_time = time_point_sec( plugin.database().head_block_time().sec_since_epoch() + lifetime );
|
||||
|
||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
trx.validate();
|
||||
try {
|
||||
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if(plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
} catch(fc::exception e){
|
||||
ilog("sidechain_net_handler: sending proposal for transfer operation failed with exception ${e}",("e", e.what()));
|
||||
}
|
||||
});
|
||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
trx.validate();
|
||||
try {
|
||||
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
} catch (fc::exception e) {
|
||||
ilog("sidechain_net_handler: sending proposal for transfer operation failed with exception ${e}", ("e", e.what()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void sidechain_net_handler::process_withdrawals() {
|
||||
const auto& idx = plugin.database().get_index_type<son_wallet_withdraw_index>().indices().get<by_withdraw_sidechain_and_processed>();
|
||||
const auto& idx_range = idx.equal_range(std::make_tuple(sidechain, false));
|
||||
const auto &idx = plugin.database().get_index_type<son_wallet_withdraw_index>().indices().get<by_withdraw_sidechain_and_processed>();
|
||||
const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false));
|
||||
|
||||
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);
|
||||
const chain::global_property_object &gpo = plugin.database().get_global_properties();
|
||||
|
||||
const chain::global_property_object& gpo = plugin.database().get_global_properties();
|
||||
son_wallet_withdraw_process_operation p_op;
|
||||
p_op.payer = GRAPHENE_SON_ACCOUNT;
|
||||
p_op.son_wallet_withdraw_id = swwo.id;
|
||||
|
||||
son_wallet_withdraw_process_operation p_op;
|
||||
p_op.payer = GRAPHENE_SON_ACCOUNT;
|
||||
p_op.son_wallet_withdraw_id = swwo.id;
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account;
|
||||
proposal_op.proposed_ops.emplace_back(op_wrapper(p_op));
|
||||
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||
proposal_op.expiration_time = time_point_sec(plugin.database().head_block_time().sec_since_epoch() + lifetime);
|
||||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account;
|
||||
proposal_op.proposed_ops.emplace_back( op_wrapper( p_op ) );
|
||||
uint32_t lifetime = ( gpo.parameters.block_interval * gpo.active_witnesses.size() ) * 3;
|
||||
proposal_op.expiration_time = time_point_sec( plugin.database().head_block_time().sec_since_epoch() + lifetime );
|
||||
|
||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
trx.validate();
|
||||
try {
|
||||
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if(plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
} catch(fc::exception e){
|
||||
ilog("sidechain_net_handler: sending proposal for transfer operation failed with exception ${e}",("e", e.what()));
|
||||
}
|
||||
});
|
||||
signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
trx.validate();
|
||||
try {
|
||||
plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||
if (plugin.app().p2p_node())
|
||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||
} catch (fc::exception e) {
|
||||
ilog("sidechain_net_handler: sending proposal for transfer operation failed with exception ${e}", ("e", e.what()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
void sidechain_net_handler::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
||||
FC_ASSERT(false, "process_withdrawal not implemented");
|
||||
}
|
||||
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -4,28 +4,32 @@
|
|||
#include <thread>
|
||||
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <fc/crypto/base64.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/protocol/son_wallet.hpp>
|
||||
#include <graphene/chain/sidechain_address_object.hpp>
|
||||
#include <graphene/chain/son_info.hpp>
|
||||
#include <graphene/chain/son_wallet_object.hpp>
|
||||
#include <graphene/chain/protocol/son_wallet.hpp>
|
||||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
// =============================================================================
|
||||
|
||||
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 ), wallet( _wallet ), wallet_password( _wallet_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),
|
||||
wallet(_wallet),
|
||||
wallet_password(_wallet_password) {
|
||||
authorization.key = "Authorization";
|
||||
authorization.val = "Basic " + fc::base64_encode( user + ":" + password );
|
||||
authorization.val = "Basic " + fc::base64_encode(user + ":" + password);
|
||||
}
|
||||
|
||||
bool bitcoin_rpc_client::connection_is_not_defined() const {
|
||||
|
|
@ -321,63 +325,66 @@ std::string bitcoin_rpc_client::signrawtransactionwithwallet(const std::string &
|
|||
return "";
|
||||
}
|
||||
|
||||
fc::http::reply bitcoin_rpc_client::send_post_request( std::string body )
|
||||
{
|
||||
fc::http::reply bitcoin_rpc_client::send_post_request(std::string body) {
|
||||
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));
|
||||
|
||||
std::string url = "http://" + ip + ":" + std::to_string( rpc_port );
|
||||
std::string url = "http://" + ip + ":" + std::to_string(rpc_port);
|
||||
|
||||
if (wallet.length() > 0) {
|
||||
url = url + "/wallet/" + wallet;
|
||||
}
|
||||
|
||||
return conn.request( "POST", url, body, fc::http::headers{authorization} );
|
||||
return conn.request("POST", url, body, fc::http::headers{authorization});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
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();
|
||||
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::vector<zmq::message_t> zmq_listener::receive_multipart() {
|
||||
std::vector<zmq::message_t> msgs;
|
||||
|
||||
int32_t more;
|
||||
size_t more_size = sizeof( more );
|
||||
while ( true ) {
|
||||
size_t more_size = sizeof(more);
|
||||
while (true) {
|
||||
zmq::message_t msg;
|
||||
socket.recv( &msg, 0 );
|
||||
socket.getsockopt( ZMQ_RCVMORE, &more, &more_size );
|
||||
socket.recv(&msg, 0);
|
||||
socket.getsockopt(ZMQ_RCVMORE, &more, &more_size);
|
||||
|
||||
if ( !more )
|
||||
if (!more)
|
||||
break;
|
||||
msgs.push_back( std::move(msg) );
|
||||
msgs.push_back(std::move(msg));
|
||||
}
|
||||
|
||||
return msgs;
|
||||
}
|
||||
|
||||
void zmq_listener::handle_zmq() {
|
||||
socket.setsockopt( ZMQ_SUBSCRIBE, "hashblock", 9 );
|
||||
socket.setsockopt(ZMQ_SUBSCRIBE, "hashblock", 9);
|
||||
//socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 );
|
||||
//socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 );
|
||||
//socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 );
|
||||
socket.connect( "tcp://" + ip + ":" + std::to_string( zmq_port ) );
|
||||
socket.connect("tcp://" + ip + ":" + std::to_string(zmq_port));
|
||||
|
||||
while ( true ) {
|
||||
while (true) {
|
||||
auto msg = receive_multipart();
|
||||
const auto header = std::string( static_cast<char*>( msg[0].data() ), msg[0].size() );
|
||||
const auto block_hash = boost::algorithm::hex( std::string( static_cast<char*>( msg[1].data() ), msg[1].size() ) );
|
||||
const auto header = std::string(static_cast<char *>(msg[0].data()), msg[0].size());
|
||||
const auto block_hash = boost::algorithm::hex(std::string(static_cast<char *>(msg[1].data()), msg[1].size()));
|
||||
|
||||
event_received( block_hash );
|
||||
event_received(block_hash);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin& _plugin, const boost::program_options::variables_map& options) :
|
||||
sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
|
||||
sidechain_net_handler(_plugin, options) {
|
||||
sidechain = sidechain_type::bitcoin;
|
||||
|
||||
|
|
@ -395,15 +402,12 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
|
|||
wallet_password = options.at("bitcoin-wallet-password").as<std::string>();
|
||||
}
|
||||
|
||||
if( options.count("bitcoin-private-key") )
|
||||
{
|
||||
if (options.count("bitcoin-private-key")) {
|
||||
const std::vector<std::string> pub_priv_keys = options["bitcoin-private-key"].as<std::vector<std::string>>();
|
||||
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);
|
||||
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);
|
||||
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.");
|
||||
}
|
||||
private_keys[key_pair.first] = key_pair.second;
|
||||
|
|
@ -412,36 +416,36 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
|
|||
|
||||
fc::http::connection conn;
|
||||
try {
|
||||
conn.connect_to( fc::ip::endpoint( fc::ip::address( ip ), rpc_port ) );
|
||||
} catch ( fc::exception e ) {
|
||||
elog( "No BTC node running at ${ip} or wrong rpc port: ${port}", ("ip", ip) ("port", rpc_port) );
|
||||
FC_ASSERT( false );
|
||||
conn.connect_to(fc::ip::endpoint(fc::ip::address(ip), rpc_port));
|
||||
} catch (fc::exception e) {
|
||||
elog("No BTC node running at ${ip} or wrong rpc port: ${port}", ("ip", ip)("port", rpc_port));
|
||||
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 ) );
|
||||
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));
|
||||
|
||||
listener->event_received.connect([this]( const std::string& event_data ) {
|
||||
std::thread( &sidechain_net_handler_bitcoin::handle_event, this, event_data ).detach();
|
||||
} );
|
||||
listener->event_received.connect([this](const std::string &event_data) {
|
||||
std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach();
|
||||
});
|
||||
}
|
||||
|
||||
sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() {
|
||||
}
|
||||
|
||||
void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
||||
const auto& swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||
const auto &swi = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||
const auto &active_sw = swi.rbegin();
|
||||
if (active_sw != swi.rend()) {
|
||||
|
||||
if ((active_sw->addresses.find(sidechain_type::bitcoin) == active_sw->addresses.end()) ||
|
||||
(active_sw->addresses.at(sidechain_type::bitcoin).empty())) {
|
||||
|
||||
const chain::global_property_object& gpo = database.get_global_properties();
|
||||
const chain::global_property_object &gpo = database.get_global_properties();
|
||||
|
||||
auto active_sons = gpo.active_sons;
|
||||
vector<string> son_pubkeys_bitcoin;
|
||||
for ( const son_info& si : active_sons ) {
|
||||
for (const son_info &si : active_sons) {
|
||||
son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin));
|
||||
}
|
||||
string reply_str = create_multisignature_wallet(son_pubkeys_bitcoin);
|
||||
|
|
@ -450,8 +454,8 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
|||
|
||||
std::stringstream active_pw_ss(reply_str);
|
||||
boost::property_tree::ptree active_pw_pt;
|
||||
boost::property_tree::read_json( active_pw_ss, active_pw_pt );
|
||||
if( active_pw_pt.count( "error" ) && active_pw_pt.get_child( "error" ).empty() ) {
|
||||
boost::property_tree::read_json(active_pw_ss, active_pw_pt);
|
||||
if (active_pw_pt.count("error") && active_pw_pt.get_child("error").empty()) {
|
||||
|
||||
std::stringstream res;
|
||||
boost::property_tree::json_parser::write_json(res, active_pw_pt.get_child("result"));
|
||||
|
|
@ -464,17 +468,17 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
|||
|
||||
proposal_create_operation proposal_op;
|
||||
proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account;
|
||||
proposal_op.proposed_ops.emplace_back( op_wrapper( op ) );
|
||||
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.proposed_ops.emplace_back(op_wrapper(op));
|
||||
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);
|
||||
|
||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op);
|
||||
try {
|
||||
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));
|
||||
} catch(fc::exception e){
|
||||
ilog("sidechain_net_handler: sending proposal for son wallet update operation failed with exception ${e}",("e", e.what()));
|
||||
} catch (fc::exception e) {
|
||||
ilog("sidechain_net_handler: sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -482,7 +486,7 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() {
|
|||
if (prev_sw != swi.rend()) {
|
||||
std::stringstream prev_sw_ss(prev_sw->addresses.at(sidechain_type::bitcoin));
|
||||
boost::property_tree::ptree prev_sw_pt;
|
||||
boost::property_tree::read_json( prev_sw_ss, prev_sw_pt );
|
||||
boost::property_tree::read_json(prev_sw_ss, prev_sw_pt);
|
||||
|
||||
std::string active_pw_address = active_pw_pt.get_child("result").get<std::string>("address");
|
||||
std::string prev_pw_address = prev_sw_pt.get<std::string>("address");
|
||||
|
|
@ -504,33 +508,32 @@ void sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw
|
|||
transfer_withdrawal_from_primary_wallet(swwo);
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_bitcoin::create_multisignature_wallet( const std::vector<std::string> public_keys ) {
|
||||
std::string sidechain_net_handler_bitcoin::create_multisignature_wallet(const std::vector<std::string> public_keys) {
|
||||
return bitcoin_client->addmultisigaddress(public_keys);
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_bitcoin::transfer( const std::string& from, const std::string& to, const uint64_t amount ) {
|
||||
std::string sidechain_net_handler_bitcoin::transfer(const std::string &from, const std::string &to, const uint64_t amount) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_bitcoin::sign_transaction( const std::string& transaction ) {
|
||||
std::string sidechain_net_handler_bitcoin::sign_transaction(const std::string &transaction) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_bitcoin::send_transaction( const std::string& transaction ) {
|
||||
std::string sidechain_net_handler_bitcoin::send_transaction(const std::string &transaction) {
|
||||
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;
|
||||
|
||||
ilog(reply_str);
|
||||
|
||||
std::stringstream ss_utx(reply_str);
|
||||
boost::property_tree::ptree pt;
|
||||
boost::property_tree::read_json( ss_utx, pt );
|
||||
boost::property_tree::read_json(ss_utx, pt);
|
||||
|
||||
if( !(pt.count( "error" ) && pt.get_child( "error" ).empty()) || !pt.count("result") ) {
|
||||
if (!(pt.count("error") && pt.get_child("error").empty()) || !pt.count("result")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -540,9 +543,9 @@ std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet
|
|||
ilog(reply_str);
|
||||
std::stringstream ss_stx(reply_str);
|
||||
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( !(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 "";
|
||||
}
|
||||
|
||||
|
|
@ -553,31 +556,25 @@ std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet
|
|||
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 min_fee_rate = 1000;
|
||||
fee_rate = std::max(fee_rate, min_fee_rate);
|
||||
|
||||
double min_amount = ((double)fee_rate/100000000.0); // Account only for relay fee for now
|
||||
double min_amount = ((double)fee_rate / 100000000.0); // Account only for relay fee for now
|
||||
double total_amount = 0.0;
|
||||
std::vector<btc_txout> unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(from_address, 0);
|
||||
|
||||
if(unspent_utxo.size() == 0)
|
||||
{
|
||||
wlog("Failed to find UTXOs to spend for ${pw}",("pw", from_address));
|
||||
if (unspent_utxo.size() == 0) {
|
||||
wlog("Failed to find UTXOs to spend for ${pw}", ("pw", from_address));
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const auto& utx: unspent_utxo)
|
||||
{
|
||||
} else {
|
||||
for (const auto &utx : unspent_utxo) {
|
||||
total_amount += utx.amount_;
|
||||
}
|
||||
|
||||
if(min_amount >= total_amount)
|
||||
{
|
||||
wlog("Failed not enough BTC to transfer from ${fa}",("fa", from_address));
|
||||
if (min_amount >= total_amount) {
|
||||
wlog("Failed not enough BTC to transfer from ${fa}", ("fa", from_address));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -589,9 +586,8 @@ std::string sidechain_net_handler_bitcoin::transfer_all_btc(const std::string& f
|
|||
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)
|
||||
{
|
||||
const auto& idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||
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>();
|
||||
auto obj = idx.rbegin();
|
||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
||||
return "";
|
||||
|
|
@ -601,19 +597,19 @@ std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet (c
|
|||
|
||||
std::stringstream ss(pw_address_json);
|
||||
boost::property_tree::ptree json;
|
||||
boost::property_tree::read_json( ss, json );
|
||||
boost::property_tree::read_json(ss, json);
|
||||
|
||||
std::string pw_address = json.get<std::string>("address");
|
||||
|
||||
std::string txid = swdo.sidechain_transaction_id;
|
||||
std::string suid = swdo.sidechain_uid;
|
||||
std::string nvout = suid.substr(suid.find_last_of("-")+1);
|
||||
std::string nvout = suid.substr(suid.find_last_of("-") + 1);
|
||||
uint64_t deposit_amount = swdo.sidechain_amount.value;
|
||||
uint64_t fee_rate = bitcoin_client->estimatesmartfee();
|
||||
uint64_t min_fee_rate = 1000;
|
||||
fee_rate = std::max(fee_rate, min_fee_rate);
|
||||
deposit_amount -= fee_rate; // Deduct minimum relay fee
|
||||
double transfer_amount = (double)deposit_amount/100000000.0;
|
||||
double transfer_amount = (double)deposit_amount / 100000000.0;
|
||||
|
||||
std::vector<btc_txout> ins;
|
||||
fc::flat_map<std::string, double> outs;
|
||||
|
|
@ -631,10 +627,9 @@ 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) {
|
||||
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();
|
||||
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 "";
|
||||
}
|
||||
|
||||
|
|
@ -642,7 +637,7 @@ std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wall
|
|||
|
||||
std::stringstream ss(pw_address_json);
|
||||
boost::property_tree::ptree json;
|
||||
boost::property_tree::read_json( ss, json );
|
||||
boost::property_tree::read_json(ss, json);
|
||||
|
||||
std::string pw_address = json.get<std::string>("address");
|
||||
|
||||
|
|
@ -654,29 +649,23 @@ std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wall
|
|||
double total_amount = 0.0;
|
||||
std::vector<btc_txout> unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0);
|
||||
|
||||
if(unspent_utxo.size() == 0)
|
||||
{
|
||||
wlog("Failed to find UTXOs to spend for ${pw}",("pw", pw_address));
|
||||
if (unspent_utxo.size() == 0) {
|
||||
wlog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address));
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const auto& utx: unspent_utxo)
|
||||
{
|
||||
} else {
|
||||
for (const auto &utx : unspent_utxo) {
|
||||
total_amount += utx.amount_;
|
||||
}
|
||||
|
||||
if(min_amount > total_amount)
|
||||
{
|
||||
wlog("Failed not enough BTC to spend for ${pw}",("pw", pw_address));
|
||||
if (min_amount > total_amount) {
|
||||
wlog("Failed not enough BTC to spend for ${pw}", ("pw", pw_address));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
fc::flat_map<std::string, double> outs;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -684,20 +673,21 @@ std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wall
|
|||
return sign_and_send_transaction_with_wallet(reply_str);
|
||||
}
|
||||
|
||||
void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data ) {
|
||||
void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) {
|
||||
std::string block = bitcoin_client->getblock(event_data);
|
||||
if( block != "" ) {
|
||||
const auto& vins = extract_info_from_block( block );
|
||||
if (block != "") {
|
||||
const auto &vins = extract_info_from_block(block);
|
||||
|
||||
const auto& sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address>();
|
||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address>();
|
||||
|
||||
for( const auto& v : vins ) {
|
||||
const auto& addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, v.address));
|
||||
if ( addr_itr == sidechain_addresses_idx.end() )
|
||||
for (const auto &v : vins) {
|
||||
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, v.address));
|
||||
if (addr_itr == sidechain_addresses_idx.end())
|
||||
continue;
|
||||
|
||||
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();
|
||||
|
||||
sidechain_event_data sed;
|
||||
|
|
@ -717,31 +707,32 @@ void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<info_for_vin> sidechain_net_handler_bitcoin::extract_info_from_block( const std::string& _block ) {
|
||||
std::stringstream ss( _block );
|
||||
std::vector<info_for_vin> sidechain_net_handler_bitcoin::extract_info_from_block(const std::string &_block) {
|
||||
std::stringstream ss(_block);
|
||||
boost::property_tree::ptree block;
|
||||
boost::property_tree::read_json( ss, block );
|
||||
boost::property_tree::read_json(ss, block);
|
||||
|
||||
std::vector<info_for_vin> result;
|
||||
|
||||
for (const auto& tx_child : block.get_child("tx")) {
|
||||
const auto& tx = tx_child.second;
|
||||
for (const auto &tx_child : block.get_child("tx")) {
|
||||
const auto &tx = tx_child.second;
|
||||
|
||||
for ( const auto& o : tx.get_child("vout") ) {
|
||||
for (const auto &o : tx.get_child("vout")) {
|
||||
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>();
|
||||
info_for_vin vin;
|
||||
vin.out.hash_tx = tx.get_child("txid").get_value<std::string>();
|
||||
string amount = o.second.get_child( "value" ).get_value<std::string>();
|
||||
string amount = o.second.get_child("value").get_value<std::string>();
|
||||
amount.erase(std::remove(amount.begin(), amount.end(), '.'), amount.end());
|
||||
vin.out.amount = std::stoll(amount);
|
||||
vin.out.n_vout = o.second.get_child( "n" ).get_value<uint32_t>();
|
||||
vin.out.n_vout = o.second.get_child("n").get_value<uint32_t>();
|
||||
vin.address = address_base58;
|
||||
result.push_back( vin );
|
||||
result.push_back(vin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -751,5 +742,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 <boost/algorithm/hex.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <fc/crypto/base64.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/protocol/son_wallet.hpp>
|
||||
#include <graphene/chain/sidechain_address_object.hpp>
|
||||
#include <graphene/chain/son_info.hpp>
|
||||
#include <graphene/chain/son_wallet_object.hpp>
|
||||
#include <graphene/chain/protocol/son_wallet.hpp>
|
||||
|
||||
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 = 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() {
|
||||
|
|
@ -31,61 +33,61 @@ sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() {
|
|||
void sidechain_net_handler_peerplays::recreate_primary_wallet() {
|
||||
}
|
||||
|
||||
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_withdrawal(const son_wallet_withdraw_object& swwo) {
|
||||
void sidechain_net_handler_peerplays::process_withdrawal(const son_wallet_withdraw_object &swwo) {
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_peerplays::create_multisignature_wallet( const std::vector<std::string> public_keys ) {
|
||||
std::string sidechain_net_handler_peerplays::create_multisignature_wallet(const std::vector<std::string> public_keys) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_peerplays::transfer( const std::string& from, const std::string& to, const uint64_t amount ) {
|
||||
std::string sidechain_net_handler_peerplays::transfer(const std::string &from, const std::string &to, const uint64_t amount) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_peerplays::sign_transaction( const std::string& transaction ) {
|
||||
std::string sidechain_net_handler_peerplays::sign_transaction(const std::string &transaction) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string sidechain_net_handler_peerplays::send_transaction( const std::string& transaction ) {
|
||||
std::string sidechain_net_handler_peerplays::send_transaction(const std::string &transaction) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void sidechain_net_handler_peerplays::on_applied_block(const signed_block& b) {
|
||||
for (const auto& trx: b.transactions) {
|
||||
size_t operation_index = -1;
|
||||
for (auto op: trx.operations) {
|
||||
operation_index = operation_index + 1;
|
||||
if (op.which() == operation::tag<transfer_operation>::value){
|
||||
transfer_operation transfer_op = op.get<transfer_operation>();
|
||||
if (transfer_op.to != GRAPHENE_SON_ACCOUNT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "peerplays" << "-" << trx.id().str() << "-" << operation_index;
|
||||
std::string sidechain_uid = ss.str();
|
||||
|
||||
sidechain_event_data sed;
|
||||
sed.timestamp = plugin.database().head_block_time();
|
||||
sed.sidechain = sidechain_type::peerplays;
|
||||
sed.sidechain_uid = sidechain_uid;
|
||||
sed.sidechain_transaction_id = trx.id().str();
|
||||
sed.sidechain_from = fc::to_string(transfer_op.from.space_id) + "." + fc::to_string(transfer_op.from.type_id) + "." + fc::to_string((uint64_t)transfer_op.from.instance);
|
||||
sed.sidechain_to = fc::to_string(transfer_op.to.space_id) + "." + fc::to_string(transfer_op.to.type_id) + "." + fc::to_string((uint64_t)transfer_op.to.instance);
|
||||
sed.sidechain_currency = fc::to_string(transfer_op.amount.asset_id.space_id) + "." + fc::to_string(transfer_op.amount.asset_id.type_id) + "." + fc::to_string((uint64_t)transfer_op.amount.asset_id.instance); //transfer_op.amount.asset_id(plugin.database()).symbol;
|
||||
sed.sidechain_amount = transfer_op.amount.amount;
|
||||
sed.peerplays_from = transfer_op.from;
|
||||
sed.peerplays_to = transfer_op.to;
|
||||
// We should calculate exchange rate between CORE/TEST and other Peerplays asset
|
||||
sed.peerplays_asset = asset(transfer_op.amount.amount / transfer_op.amount.asset_id(plugin.database()).options.core_exchange_rate.quote.amount);
|
||||
sidechain_event_data_received(sed);
|
||||
void sidechain_net_handler_peerplays::on_applied_block(const signed_block &b) {
|
||||
for (const auto &trx : b.transactions) {
|
||||
size_t operation_index = -1;
|
||||
for (auto op : trx.operations) {
|
||||
operation_index = operation_index + 1;
|
||||
if (op.which() == operation::tag<transfer_operation>::value) {
|
||||
transfer_operation transfer_op = op.get<transfer_operation>();
|
||||
if (transfer_op.to != GRAPHENE_SON_ACCOUNT) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "peerplays"
|
||||
<< "-" << trx.id().str() << "-" << operation_index;
|
||||
std::string sidechain_uid = ss.str();
|
||||
|
||||
sidechain_event_data sed;
|
||||
sed.timestamp = plugin.database().head_block_time();
|
||||
sed.sidechain = sidechain_type::peerplays;
|
||||
sed.sidechain_uid = sidechain_uid;
|
||||
sed.sidechain_transaction_id = trx.id().str();
|
||||
sed.sidechain_from = fc::to_string(transfer_op.from.space_id) + "." + fc::to_string(transfer_op.from.type_id) + "." + fc::to_string((uint64_t)transfer_op.from.instance);
|
||||
sed.sidechain_to = fc::to_string(transfer_op.to.space_id) + "." + fc::to_string(transfer_op.to.type_id) + "." + fc::to_string((uint64_t)transfer_op.to.instance);
|
||||
sed.sidechain_currency = fc::to_string(transfer_op.amount.asset_id.space_id) + "." + fc::to_string(transfer_op.amount.asset_id.type_id) + "." + fc::to_string((uint64_t)transfer_op.amount.asset_id.instance); //transfer_op.amount.asset_id(plugin.database()).symbol;
|
||||
sed.sidechain_amount = transfer_op.amount.amount;
|
||||
sed.peerplays_from = transfer_op.from;
|
||||
sed.peerplays_to = transfer_op.to;
|
||||
// We should calculate exchange rate between CORE/TEST and other Peerplays asset
|
||||
sed.peerplays_asset = asset(transfer_op.amount.amount / transfer_op.amount.asset_id(plugin.database()).options.core_exchange_rate.quote.amount);
|
||||
sidechain_event_data_received(sed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
|
|
@ -7,56 +7,54 @@
|
|||
|
||||
namespace graphene { namespace peerplays_sidechain {
|
||||
|
||||
sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin& _plugin) :
|
||||
plugin(_plugin),
|
||||
database(_plugin.database())
|
||||
{
|
||||
sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin) :
|
||||
plugin(_plugin),
|
||||
database(_plugin.database()) {
|
||||
}
|
||||
|
||||
sidechain_net_manager::~sidechain_net_manager() {
|
||||
}
|
||||
|
||||
bool sidechain_net_manager::create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map& options) {
|
||||
bool sidechain_net_manager::create_handler(peerplays_sidechain::sidechain_type sidechain, const boost::program_options::variables_map &options) {
|
||||
|
||||
bool ret_val = false;
|
||||
|
||||
switch (sidechain) {
|
||||
case sidechain_type::bitcoin: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_bitcoin(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
case sidechain_type::peerplays: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
case sidechain_type::bitcoin: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_bitcoin(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
case sidechain_type::peerplays: {
|
||||
std::unique_ptr<sidechain_net_handler> h = std::unique_ptr<sidechain_net_handler>(new sidechain_net_handler_peerplays(plugin, options));
|
||||
net_handlers.push_back(std::move(h));
|
||||
ret_val = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
void sidechain_net_manager::recreate_primary_wallet() {
|
||||
for ( size_t i = 0; i < net_handlers.size(); i++ ) {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->recreate_primary_wallet();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_deposits() {
|
||||
for ( size_t i = 0; i < net_handlers.size(); i++ ) {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_deposits();
|
||||
}
|
||||
}
|
||||
|
||||
void sidechain_net_manager::process_withdrawals() {
|
||||
for ( size_t i = 0; i < net_handlers.size(); i++ ) {
|
||||
for (size_t i = 0; i < net_handlers.size(); i++) {
|
||||
net_handlers.at(i)->process_withdrawals();
|
||||
}
|
||||
}
|
||||
|
||||
} } // graphene::peerplays_sidechain
|
||||
|
||||
}} // namespace graphene::peerplays_sidechain
|
||||
|
|
|
|||
Loading…
Reference in a new issue