SON261 - Add PW->PW Transfer and Code reorg
This commit is contained in:
parent
d2fdca7dad
commit
c953864c39
8 changed files with 484 additions and 62 deletions
|
|
@ -13,7 +13,6 @@ namespace graphene { namespace chain {
|
||||||
account_id_type payer;
|
account_id_type payer;
|
||||||
|
|
||||||
// TODO: BTC Transaction Structs go here
|
// TODO: BTC Transaction Structs go here
|
||||||
std::string tx_hex;
|
|
||||||
fc::flat_map<son_id_type, std::vector<peerplays_sidechain::bytes>> signatures;
|
fc::flat_map<son_id_type, std::vector<peerplays_sidechain::bytes>> signatures;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return payer; }
|
account_id_type fee_payer()const { return payer; }
|
||||||
|
|
@ -28,7 +27,6 @@ namespace graphene { namespace chain {
|
||||||
asset fee;
|
asset fee;
|
||||||
account_id_type payer;
|
account_id_type payer;
|
||||||
proposal_id_type proposal_id;
|
proposal_id_type proposal_id;
|
||||||
std::string signed_tx_hex;
|
|
||||||
std::vector<peerplays_sidechain::bytes> signatures;
|
std::vector<peerplays_sidechain::bytes> signatures;
|
||||||
|
|
||||||
account_id_type fee_payer()const { return payer; }
|
account_id_type fee_payer()const { return payer; }
|
||||||
|
|
@ -53,10 +51,10 @@ namespace graphene { namespace chain {
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::bitcoin_transaction_send_operation::fee_parameters_type, (fee) )
|
FC_REFLECT( graphene::chain::bitcoin_transaction_send_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT( graphene::chain::bitcoin_transaction_send_operation, (fee)(payer)(tx_hex)(signatures) )
|
FC_REFLECT( graphene::chain::bitcoin_transaction_send_operation, (fee)(payer)(signatures) )
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation::fee_parameters_type, (fee) )
|
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation, (fee)(payer)(proposal_id)(signed_tx_hex)(signatures) )
|
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation, (fee)(payer)(proposal_id)(signatures) )
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::bitcoin_send_transaction_process_operation::fee_parameters_type, (fee) )
|
FC_REFLECT( graphene::chain::bitcoin_send_transaction_process_operation::fee_parameters_type, (fee) )
|
||||||
FC_REFLECT( graphene::chain::bitcoin_send_transaction_process_operation, (fee)(payer)(bitcoin_transaction_id) )
|
FC_REFLECT( graphene::chain::bitcoin_send_transaction_process_operation, (fee)(payer)(bitcoin_transaction_id) )
|
||||||
|
|
@ -17,7 +17,6 @@ namespace graphene { namespace chain {
|
||||||
static const uint8_t type_id = bitcoin_transaction_object_type;
|
static const uint8_t type_id = bitcoin_transaction_object_type;
|
||||||
// Bitcoin structs go here.
|
// Bitcoin structs go here.
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
fc::flat_map<son_id_type, std::string> tx_signatures;
|
|
||||||
fc::flat_map<son_id_type, std::vector<peerplays_sidechain::bytes>> signatures;
|
fc::flat_map<son_id_type, std::vector<peerplays_sidechain::bytes>> signatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -37,4 +36,4 @@ namespace graphene { namespace chain {
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::bitcoin_transaction_object, (graphene::db::object),
|
FC_REFLECT_DERIVED( graphene::chain::bitcoin_transaction_object, (graphene::db::object),
|
||||||
(processed)(tx_signatures)(signatures) )
|
(processed)(signatures) )
|
||||||
|
|
|
||||||
|
|
@ -133,4 +133,4 @@ object_id_type bitcoin_send_transaction_process_evaluator::do_apply(const bitcoi
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chain
|
} // namespace chain
|
||||||
} // namespace graphene
|
} // namespace graphene
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ protected:
|
||||||
virtual std::string sign_transaction( const std::string& transaction ) = 0;
|
virtual std::string sign_transaction( const std::string& transaction ) = 0;
|
||||||
virtual std::string send_transaction( const std::string& transaction ) = 0;
|
virtual std::string send_transaction( const std::string& transaction ) = 0;
|
||||||
virtual std::string transfer_deposit_to_primary_wallet (const sidechain_event_data& sed) = 0;
|
virtual std::string transfer_deposit_to_primary_wallet (const sidechain_event_data& sed) = 0;
|
||||||
|
virtual std::string transfer_withdrawal_from_primary_wallet(const std::string& user_address, double sidechain_amount) = 0;
|
||||||
|
|
||||||
virtual void handle_event( const std::string& event_data ) = 0;
|
virtual void handle_event( const std::string& event_data ) = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,11 @@ public:
|
||||||
std::string transfer( const std::string& from, const std::string& to, const uint64_t amount );
|
std::string transfer( const std::string& from, const std::string& to, const uint64_t amount );
|
||||||
std::string sign_transaction( const std::string& transaction );
|
std::string sign_transaction( const std::string& transaction );
|
||||||
std::string send_transaction( const std::string& transaction );
|
std::string send_transaction( const std::string& transaction );
|
||||||
|
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 sidechain_event_data& sed);
|
std::string transfer_deposit_to_primary_wallet (const sidechain_event_data& sed);
|
||||||
std::string transfer_withdrawal_from_primary_wallet(const std::string& user_address, int64_t sidechain_amount);
|
std::string transfer_withdrawal_from_primary_wallet(const std::string& user_address, double sidechain_amount);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ip;
|
std::string ip;
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
("bitcoin-address", bpo::value<string>()->default_value("2N911a7smwDzUGARg8s7Q1ViizFCw6gWcbR"), "Bitcoin address")
|
("bitcoin-address", bpo::value<string>()->default_value("2N911a7smwDzUGARg8s7Q1ViizFCw6gWcbR"), "Bitcoin address")
|
||||||
("bitcoin-public-key", bpo::value<string>()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key")
|
("bitcoin-public-key", bpo::value<string>()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key")
|
||||||
("bitcoin-private-key", bpo::value<string>()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key")
|
("bitcoin-private-key", bpo::value<string>()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key")
|
||||||
("bitcoin-private-keys", bpo::value<vector<string>>()->composing()->multitoken()->
|
("bitcoin-private-keys", bpo::value<vector<string>>()->composing()->multitoken()->
|
||||||
DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
||||||
"Tuple of [Bitcoin PublicKey, Bitcoin Private key] (may specify multiple times)")
|
"Tuple of [Bitcoin PublicKey, Bitcoin Private key] (may specify multiple times)")
|
||||||
;
|
;
|
||||||
|
|
@ -123,7 +123,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
||||||
config_ready_son = config_ready_son && !_sons.empty();
|
config_ready_son = config_ready_son && !_sons.empty();
|
||||||
|
|
||||||
#ifndef SUPPORT_MULTIPLE_SONS
|
#ifndef SUPPORT_MULTIPLE_SONS
|
||||||
//FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" );
|
FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( options.count("peerplays-private-key") )
|
if( options.count("peerplays-private-key") )
|
||||||
|
|
|
||||||
|
|
@ -575,41 +575,9 @@ std::string sidechain_net_handler_bitcoin::send_transaction( const std::string&
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet ( const sidechain_event_data& sed )
|
std::string sidechain_net_handler_bitcoin::sign_and_send_transaction_with_wallet ( const std::string& tx_json )
|
||||||
{
|
{
|
||||||
const auto& idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
std::string reply_str = tx_json;
|
||||||
auto obj = idx.rbegin();
|
|
||||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second;
|
|
||||||
|
|
||||||
std::stringstream ss(pw_address_json);
|
|
||||||
boost::property_tree::ptree json;
|
|
||||||
boost::property_tree::read_json( ss, json );
|
|
||||||
|
|
||||||
std::string pw_address = json.get<std::string>("address");
|
|
||||||
|
|
||||||
std::string txid = sed.sidechain_transaction_id;
|
|
||||||
std::string suid = sed.sidechain_uid;
|
|
||||||
std::string nvout = suid.substr(suid.find_last_of("-")+1);
|
|
||||||
int64_t deposit_amount = sed.sidechain_amount;
|
|
||||||
deposit_amount -= 1000; // Deduct minimum relay fee
|
|
||||||
double transfer_amount = (double)deposit_amount/100000000.0;
|
|
||||||
|
|
||||||
std::vector<btc_txout> ins;
|
|
||||||
fc::flat_map<std::string, double> outs;
|
|
||||||
|
|
||||||
btc_txout utxo;
|
|
||||||
utxo.txid_ = txid;
|
|
||||||
utxo.out_num_ = std::stoul(nvout);
|
|
||||||
|
|
||||||
ins.push_back(utxo);
|
|
||||||
|
|
||||||
outs[pw_address] = transfer_amount;
|
|
||||||
|
|
||||||
std::string reply_str = bitcoin_client->prepare_tx(ins, outs);
|
|
||||||
|
|
||||||
ilog(reply_str);
|
ilog(reply_str);
|
||||||
|
|
||||||
|
|
@ -640,7 +608,84 @@ std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet (
|
||||||
return reply_str;
|
return reply_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wallet(const std::string& user_address, int64_t sidechain_amount) {
|
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->receive_estimated_fee();
|
||||||
|
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 total_amount = 0.0;
|
||||||
|
std::vector<btc_txout> unspent_utxo= bitcoin_client->list_unspent_by_address_and_amount(from_address, 0);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
total_amount += utx.amount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(min_amount >= total_amount)
|
||||||
|
{
|
||||||
|
wlog("Failed not enough BTC to transfer from ${fa}",("fa", from_address));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fc::flat_map<std::string, double> outs;
|
||||||
|
outs[to_address] = total_amount - min_amount;
|
||||||
|
|
||||||
|
std::string reply_str = bitcoin_client->prepare_tx(unspent_utxo, outs);
|
||||||
|
return sign_and_send_transaction_with_wallet(reply_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet ( const sidechain_event_data& sed )
|
||||||
|
{
|
||||||
|
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 "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second;
|
||||||
|
|
||||||
|
std::stringstream ss(pw_address_json);
|
||||||
|
boost::property_tree::ptree json;
|
||||||
|
boost::property_tree::read_json( ss, json );
|
||||||
|
|
||||||
|
std::string pw_address = json.get<std::string>("address");
|
||||||
|
|
||||||
|
std::string txid = sed.sidechain_transaction_id;
|
||||||
|
std::string suid = sed.sidechain_uid;
|
||||||
|
std::string nvout = suid.substr(suid.find_last_of("-")+1);
|
||||||
|
uint64_t deposit_amount = sed.sidechain_amount;
|
||||||
|
uint64_t fee_rate = bitcoin_client->receive_estimated_fee();
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::vector<btc_txout> ins;
|
||||||
|
fc::flat_map<std::string, double> outs;
|
||||||
|
|
||||||
|
btc_txout utxo;
|
||||||
|
utxo.txid_ = txid;
|
||||||
|
utxo.out_num_ = std::stoul(nvout);
|
||||||
|
|
||||||
|
ins.push_back(utxo);
|
||||||
|
|
||||||
|
outs[pw_address] = transfer_amount;
|
||||||
|
|
||||||
|
std::string reply_str = bitcoin_client->prepare_tx(ins, outs);
|
||||||
|
return sign_and_send_transaction_with_wallet(reply_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wallet(const std::string& user_address, double sidechain_amount) {
|
||||||
const auto& idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
const auto& idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
|
||||||
auto obj = idx.rbegin();
|
auto obj = idx.rbegin();
|
||||||
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end())
|
if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end())
|
||||||
|
|
@ -656,32 +701,42 @@ std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wall
|
||||||
|
|
||||||
std::string pw_address = json.get<std::string>("address");
|
std::string pw_address = json.get<std::string>("address");
|
||||||
|
|
||||||
double total_amount = (((double)sidechain_amount*1000.0)+1000.0)/100000000.0; // Account only for relay fee for now
|
uint64_t fee_rate = bitcoin_client->receive_estimated_fee();
|
||||||
double transfer_amount = ((double)sidechain_amount*1000.0)/100000000.0;
|
uint64_t min_fee_rate = 1000;
|
||||||
std::vector<btc_txout> unspent_utxo= bitcoin_client->list_unspent_by_address_and_amount(pw_address, total_amount);
|
fee_rate = std::max(fee_rate, min_fee_rate);
|
||||||
|
|
||||||
|
double min_amount = sidechain_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->list_unspent_by_address_and_amount(pw_address, 0);
|
||||||
|
|
||||||
if(unspent_utxo.size() == 0)
|
if(unspent_utxo.size() == 0)
|
||||||
{
|
{
|
||||||
|
wlog("Failed to find UTXOs to spend for ${pw}",("pw", pw_address));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(const auto& utx: unspent_utxo)
|
||||||
|
{
|
||||||
|
total_amount += utx.amount_;
|
||||||
|
}
|
||||||
|
|
||||||
btc_txout utxo = unspent_utxo[0];
|
if(min_amount > total_amount)
|
||||||
std::string reply_str = bitcoin_client->create_raw_transaction(utxo.txid_, std::to_string(utxo.out_num_), user_address, transfer_amount);
|
{
|
||||||
ilog(reply_str);
|
wlog("Failed not enough BTC to spend for ${pw}",("pw", pw_address));
|
||||||
|
return "";
|
||||||
std::stringstream ss_utx(reply_str);
|
}
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
boost::property_tree::read_json( ss_utx, pt );
|
|
||||||
|
|
||||||
if( !(pt.count( "error" ) && pt.get_child( "error" ).empty()) || !pt.count("result") ) {
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string unsigned_tx_hex = pt.get<std::string>("result");
|
fc::flat_map<std::string, double> outs;
|
||||||
|
outs[user_address] = sidechain_amount;
|
||||||
|
if((total_amount - min_amount) > 0.0)
|
||||||
|
{
|
||||||
|
outs[pw_address] = total_amount - min_amount;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << unsigned_tx_hex << std::endl;
|
std::string reply_str = bitcoin_client->prepare_tx(unspent_utxo, outs);
|
||||||
|
return sign_and_send_transaction_with_wallet(reply_str);
|
||||||
return unsigned_tx_hex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data ) {
|
void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data ) {
|
||||||
|
|
|
||||||
366
tests/tests/sidechain_transaction_tests.cpp
Normal file
366
tests/tests/sidechain_transaction_tests.cpp
Normal file
|
|
@ -0,0 +1,366 @@
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include "../common/database_fixture.hpp"
|
||||||
|
|
||||||
|
#include <graphene/chain/hardfork.hpp>
|
||||||
|
#include <graphene/chain/sidechain_transaction_object.hpp>
|
||||||
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
|
#include <graphene/chain/son_object.hpp>
|
||||||
|
#include <graphene/peerplays_sidechain/defs.hpp>
|
||||||
|
|
||||||
|
using namespace graphene;
|
||||||
|
using namespace graphene::chain;
|
||||||
|
using namespace graphene::chain::test;
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(sidechain_transaction_tests, database_fixture)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(bitcoin_transaction_send_test)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("bitcoin_transaction_send_test");
|
||||||
|
|
||||||
|
generate_blocks(HARDFORK_SON_TIME);
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
ACTORS((alice)(bob));
|
||||||
|
|
||||||
|
upgrade_to_lifetime_member(alice);
|
||||||
|
upgrade_to_lifetime_member(bob);
|
||||||
|
|
||||||
|
transfer(committee_account, alice_id, asset(500000 * GRAPHENE_BLOCKCHAIN_PRECISION));
|
||||||
|
transfer(committee_account, bob_id, asset(500000 * GRAPHENE_BLOCKCHAIN_PRECISION));
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
std::string test_url = "https://create_son_test";
|
||||||
|
|
||||||
|
// create deposit vesting
|
||||||
|
vesting_balance_id_type deposit_alice;
|
||||||
|
{
|
||||||
|
vesting_balance_create_operation op;
|
||||||
|
op.creator = alice_id;
|
||||||
|
op.owner = alice_id;
|
||||||
|
op.amount = asset(500 * GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||||
|
op.balance_type = vesting_balance_type::son;
|
||||||
|
op.policy = dormant_vesting_policy_initializer{};
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
deposit_alice = ptx.operation_results[0].get<object_id_type>();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
// create payment normal vesting
|
||||||
|
vesting_balance_id_type payment_alice;
|
||||||
|
{
|
||||||
|
vesting_balance_create_operation op;
|
||||||
|
op.creator = alice_id;
|
||||||
|
op.owner = alice_id;
|
||||||
|
op.amount = asset(500 * GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||||
|
op.balance_type = vesting_balance_type::normal;
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
payment_alice = ptx.operation_results[0].get<object_id_type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
// alice becomes son
|
||||||
|
{
|
||||||
|
flat_map<graphene::peerplays_sidechain::sidechain_type, string> sidechain_public_keys;
|
||||||
|
sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin address";
|
||||||
|
|
||||||
|
son_create_operation op;
|
||||||
|
op.owner_account = alice_id;
|
||||||
|
op.url = test_url;
|
||||||
|
op.deposit = deposit_alice;
|
||||||
|
op.pay_vb = payment_alice;
|
||||||
|
op.signing_key = alice_public_key;
|
||||||
|
op.sidechain_public_keys = sidechain_public_keys;
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
// create deposit vesting
|
||||||
|
vesting_balance_id_type deposit_bob;
|
||||||
|
{
|
||||||
|
vesting_balance_create_operation op;
|
||||||
|
op.creator = bob_id;
|
||||||
|
op.owner = bob_id;
|
||||||
|
op.amount = asset(500 * GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||||
|
op.balance_type = vesting_balance_type::son;
|
||||||
|
op.policy = dormant_vesting_policy_initializer{};
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
sign(trx, bob_private_key);
|
||||||
|
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
deposit_bob = ptx.operation_results[0].get<object_id_type>();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
// create payment normal vesting
|
||||||
|
vesting_balance_id_type payment_bob;
|
||||||
|
{
|
||||||
|
vesting_balance_create_operation op;
|
||||||
|
op.creator = bob_id;
|
||||||
|
op.owner = bob_id;
|
||||||
|
op.amount = asset(500 * GRAPHENE_BLOCKCHAIN_PRECISION);
|
||||||
|
op.balance_type = vesting_balance_type::normal;
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
sign(trx, bob_private_key);
|
||||||
|
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
payment_bob = ptx.operation_results[0].get<object_id_type>();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
set_expiration(db, trx);
|
||||||
|
|
||||||
|
// bob becomes son
|
||||||
|
{
|
||||||
|
flat_map<graphene::peerplays_sidechain::sidechain_type, string> sidechain_public_keys;
|
||||||
|
sidechain_public_keys[graphene::peerplays_sidechain::sidechain_type::bitcoin] = "bitcoin address";
|
||||||
|
|
||||||
|
son_create_operation op;
|
||||||
|
op.owner_account = bob_id;
|
||||||
|
op.url = test_url;
|
||||||
|
op.deposit = deposit_bob;
|
||||||
|
op.pay_vb = payment_bob;
|
||||||
|
op.signing_key = bob_public_key;
|
||||||
|
op.sidechain_public_keys = sidechain_public_keys;
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
|
||||||
|
const auto &son_btc_account = db.create<account_object>([&](account_object &obj) {
|
||||||
|
obj.name = "son_btc_account";
|
||||||
|
obj.statistics = db.create<account_statistics_object>([&](account_statistics_object &acc_stat) { acc_stat.owner = obj.id; }).id;
|
||||||
|
obj.membership_expiration_date = time_point_sec::maximum();
|
||||||
|
obj.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE;
|
||||||
|
obj.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE;
|
||||||
|
|
||||||
|
obj.owner.add_authority(bob_id, 1);
|
||||||
|
obj.active.add_authority(bob_id, 1);
|
||||||
|
obj.owner.add_authority(alice_id, 1);
|
||||||
|
obj.active.add_authority(alice_id, 1);
|
||||||
|
obj.active.weight_threshold = 2;
|
||||||
|
obj.owner.weight_threshold = 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
db.modify( db.get_global_properties(), [&]( global_property_object& _gpo )
|
||||||
|
{
|
||||||
|
_gpo.parameters.extensions.value.son_btc_account = son_btc_account.get_id();
|
||||||
|
if( _gpo.pending_parameters )
|
||||||
|
_gpo.pending_parameters->extensions.value.son_btc_account = son_btc_account.get_id();
|
||||||
|
});
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
|
||||||
|
const global_property_object &gpo = db.get_global_properties();
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Send bitcoin_transaction_send_operation");
|
||||||
|
|
||||||
|
bitcoin_transaction_send_operation send_op;
|
||||||
|
|
||||||
|
send_op.payer = db.get_global_properties().parameters.get_son_btc_account_id();
|
||||||
|
|
||||||
|
proposal_create_operation proposal_op;
|
||||||
|
proposal_op.fee_paying_account = alice_id;
|
||||||
|
proposal_op.proposed_ops.push_back(op_wrapper(send_op));
|
||||||
|
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||||
|
proposal_op.expiration_time = time_point_sec(db.head_block_time().sec_since_epoch() + lifetime);
|
||||||
|
|
||||||
|
trx.operations.push_back(proposal_op);
|
||||||
|
set_expiration(db, trx);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("Check proposal results");
|
||||||
|
|
||||||
|
const auto &idx = db.get_index_type<proposal_index>().indices().get<by_id>();
|
||||||
|
BOOST_REQUIRE(idx.size() == 1);
|
||||||
|
auto obj = idx.find(proposal_id_type(0));
|
||||||
|
BOOST_REQUIRE(obj != idx.end());
|
||||||
|
|
||||||
|
const auto& btidx = db.get_index_type<bitcoin_transaction_index>().indices().get<by_id>();
|
||||||
|
BOOST_REQUIRE(btidx.size() == 0);
|
||||||
|
|
||||||
|
std::vector<unsigned char> a1 = {'a', 'l', 'i', 'c', 'e', '1'};
|
||||||
|
std::vector<unsigned char> a2 = {'a', 'l', 'i', 'c', 'e', '2'};
|
||||||
|
std::vector<unsigned char> a3 = {'a', 'l', 'i', 'c', 'e', '3'};
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Send bitcoin_transaction_sign_operation");
|
||||||
|
|
||||||
|
bitcoin_transaction_sign_operation sign_op;
|
||||||
|
|
||||||
|
sign_op.payer = alice_id;
|
||||||
|
sign_op.proposal_id = proposal_id_type(0);
|
||||||
|
sign_op.signatures.push_back(a1);
|
||||||
|
sign_op.signatures.push_back(a2);
|
||||||
|
sign_op.signatures.push_back(a3);
|
||||||
|
|
||||||
|
trx.operations.push_back(sign_op);
|
||||||
|
set_expiration(db, trx);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(idx.size() == 1);
|
||||||
|
BOOST_REQUIRE(btidx.size() == 0);
|
||||||
|
auto pobj = idx.find(proposal_id_type(0));
|
||||||
|
BOOST_REQUIRE(pobj != idx.end());
|
||||||
|
|
||||||
|
const auto& sidx = db.get_index_type<son_index>().indices().get<graphene::chain::by_account>();
|
||||||
|
const auto son_obj1 = sidx.find( alice_id );
|
||||||
|
BOOST_REQUIRE(son_obj1 != sidx.end());
|
||||||
|
|
||||||
|
auto bitcoin_transaction_send_op = pobj->proposed_transaction.operations[0].get<bitcoin_transaction_send_operation>();
|
||||||
|
BOOST_REQUIRE(bitcoin_transaction_send_op.signatures.size() == 1);
|
||||||
|
BOOST_REQUIRE(bitcoin_transaction_send_op.signatures[son_obj1->id][0] == a1);
|
||||||
|
BOOST_REQUIRE(bitcoin_transaction_send_op.signatures[son_obj1->id][1] == a2);
|
||||||
|
BOOST_REQUIRE(bitcoin_transaction_send_op.signatures[son_obj1->id][2] == a3);
|
||||||
|
|
||||||
|
std::vector<unsigned char> b1 = {'b', 'o', 'b', '1'};
|
||||||
|
std::vector<unsigned char> b2 = {'b', 'o', 'b', '2'};
|
||||||
|
std::vector<unsigned char> b3 = {'b', 'o', 'b', '3'};
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Send bitcoin_transaction_sign_operation");
|
||||||
|
|
||||||
|
bitcoin_transaction_sign_operation sign_op;
|
||||||
|
|
||||||
|
sign_op.payer = bob_id;
|
||||||
|
sign_op.proposal_id = proposal_id_type(0);
|
||||||
|
sign_op.signatures.push_back(b1);
|
||||||
|
sign_op.signatures.push_back(b2);
|
||||||
|
sign_op.signatures.push_back(b3);
|
||||||
|
|
||||||
|
trx.operations.push_back(sign_op);
|
||||||
|
set_expiration(db, trx);
|
||||||
|
sign(trx, bob_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(idx.size() == 0);
|
||||||
|
|
||||||
|
const auto son_obj2 = sidx.find( bob_id );
|
||||||
|
BOOST_REQUIRE(son_obj2 != sidx.end());
|
||||||
|
|
||||||
|
BOOST_REQUIRE(btidx.size() == 1);
|
||||||
|
|
||||||
|
const auto btobj = btidx.find(bitcoin_transaction_id_type(0));
|
||||||
|
BOOST_REQUIRE(btobj != btidx.end());
|
||||||
|
|
||||||
|
BOOST_REQUIRE(btobj->processed == false);
|
||||||
|
|
||||||
|
auto sigs = btobj->signatures;
|
||||||
|
|
||||||
|
BOOST_REQUIRE(sigs[son_obj1->id][0] == a1);
|
||||||
|
BOOST_REQUIRE(sigs[son_obj1->id][1] == a2);
|
||||||
|
BOOST_REQUIRE(sigs[son_obj1->id][2] == a3);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(sigs[son_obj2->id][0] == b1);
|
||||||
|
BOOST_REQUIRE(sigs[son_obj2->id][1] == b2);
|
||||||
|
BOOST_REQUIRE(sigs[son_obj2->id][2] == b3);
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Send bitcoin_send_transaction_process_operation");
|
||||||
|
|
||||||
|
bitcoin_send_transaction_process_operation process_op;
|
||||||
|
process_op.bitcoin_transaction_id = bitcoin_transaction_id_type(0);
|
||||||
|
process_op.payer = db.get_global_properties().parameters.get_son_btc_account_id();
|
||||||
|
|
||||||
|
proposal_create_operation proposal_op;
|
||||||
|
proposal_op.fee_paying_account = alice_id;
|
||||||
|
proposal_op.proposed_ops.push_back(op_wrapper(process_op));
|
||||||
|
uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3;
|
||||||
|
proposal_op.expiration_time = time_point_sec(db.head_block_time().sec_since_epoch() + lifetime);
|
||||||
|
|
||||||
|
trx.operations.push_back(proposal_op);
|
||||||
|
set_expiration(db, trx);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_block();
|
||||||
|
BOOST_REQUIRE(idx.size() == 1);
|
||||||
|
obj = idx.find(proposal_id_type(1));
|
||||||
|
BOOST_REQUIRE(obj != idx.end());
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Send proposal_update_operation");
|
||||||
|
|
||||||
|
proposal_update_operation puo;
|
||||||
|
puo.fee_paying_account = bob_id;
|
||||||
|
puo.proposal = obj->id;
|
||||||
|
puo.active_approvals_to_add = { bob_id };
|
||||||
|
|
||||||
|
trx.operations.push_back(puo);
|
||||||
|
set_expiration(db, trx);
|
||||||
|
sign(trx, bob_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
BOOST_REQUIRE(idx.size() == 1);
|
||||||
|
obj = idx.find(proposal_id_type(1));
|
||||||
|
BOOST_REQUIRE(obj != idx.end());
|
||||||
|
|
||||||
|
BOOST_REQUIRE(btobj != btidx.end());
|
||||||
|
BOOST_REQUIRE(btobj->processed == false);
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST_MESSAGE("Send proposal_update_operation");
|
||||||
|
|
||||||
|
proposal_update_operation puo;
|
||||||
|
puo.fee_paying_account = alice_id;
|
||||||
|
puo.proposal = obj->id;
|
||||||
|
puo.active_approvals_to_add = { alice_id };
|
||||||
|
|
||||||
|
trx.operations.push_back(puo);
|
||||||
|
set_expiration(db, trx);
|
||||||
|
sign(trx, alice_private_key);
|
||||||
|
PUSH_TX(db, trx, ~0);
|
||||||
|
trx.clear();
|
||||||
|
}
|
||||||
|
generate_block();
|
||||||
|
BOOST_REQUIRE(idx.size() == 0);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(btobj != btidx.end());
|
||||||
|
BOOST_REQUIRE(btobj->processed == true);
|
||||||
|
}
|
||||||
|
FC_LOG_AND_RETHROW()
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
Loading…
Reference in a new issue