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;
|
||||
|
||||
// TODO: BTC Transaction Structs go here
|
||||
std::string tx_hex;
|
||||
fc::flat_map<son_id_type, std::vector<peerplays_sidechain::bytes>> signatures;
|
||||
|
||||
account_id_type fee_payer()const { return payer; }
|
||||
|
|
@ -28,7 +27,6 @@ namespace graphene { namespace chain {
|
|||
asset fee;
|
||||
account_id_type payer;
|
||||
proposal_id_type proposal_id;
|
||||
std::string signed_tx_hex;
|
||||
std::vector<peerplays_sidechain::bytes> signatures;
|
||||
|
||||
account_id_type fee_payer()const { return payer; }
|
||||
|
|
@ -53,10 +51,10 @@ namespace graphene { namespace chain {
|
|||
} } // graphene::chain
|
||||
|
||||
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)(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)(payer)(bitcoin_transaction_id) )
|
||||
|
|
@ -17,7 +17,6 @@ namespace graphene { namespace chain {
|
|||
static const uint8_t type_id = bitcoin_transaction_object_type;
|
||||
// Bitcoin structs go here.
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -37,4 +36,4 @@ namespace graphene { namespace chain {
|
|||
} } // graphene::chain
|
||||
|
||||
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 graphene
|
||||
} // namespace graphene
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ protected:
|
|||
virtual std::string sign_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_withdrawal_from_primary_wallet(const std::string& user_address, double sidechain_amount) = 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 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 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:
|
||||
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-public-key", bpo::value<string>()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key")
|
||||
("bitcoin-private-key", bpo::value<string>()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key")
|
||||
("bitcoin-private-keys", bpo::value<vector<string>>()->composing()->multitoken()->
|
||||
("bitcoin-private-keys", bpo::value<vector<string>>()->composing()->multitoken()->
|
||||
DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")),
|
||||
"Tuple of [Bitcoin PublicKey, Bitcoin Private key] (may specify multiple times)")
|
||||
;
|
||||
|
|
@ -123,7 +123,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
|||
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") )
|
||||
|
|
|
|||
|
|
@ -575,41 +575,9 @@ std::string sidechain_net_handler_bitcoin::send_transaction( const std::string&
|
|||
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>();
|
||||
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);
|
||||
std::string reply_str = tx_json;
|
||||
|
||||
ilog(reply_str);
|
||||
|
||||
|
|
@ -640,7 +608,84 @@ std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet (
|
|||
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>();
|
||||
auto obj = idx.rbegin();
|
||||
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");
|
||||
|
||||
double total_amount = (((double)sidechain_amount*1000.0)+1000.0)/100000000.0; // Account only for relay fee for now
|
||||
double transfer_amount = ((double)sidechain_amount*1000.0)/100000000.0;
|
||||
std::vector<btc_txout> unspent_utxo= bitcoin_client->list_unspent_by_address_and_amount(pw_address, total_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);
|
||||
|
||||
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)
|
||||
{
|
||||
wlog("Failed to find UTXOs to spend for ${pw}",("pw", pw_address));
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const auto& utx: unspent_utxo)
|
||||
{
|
||||
total_amount += utx.amount_;
|
||||
}
|
||||
|
||||
btc_txout utxo = unspent_utxo[0];
|
||||
std::string reply_str = bitcoin_client->create_raw_transaction(utxo.txid_, std::to_string(utxo.out_num_), user_address, transfer_amount);
|
||||
ilog(reply_str);
|
||||
|
||||
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 "";
|
||||
if(min_amount > total_amount)
|
||||
{
|
||||
wlog("Failed not enough BTC to spend for ${pw}",("pw", pw_address));
|
||||
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;
|
||||
|
||||
return unsigned_tx_hex;
|
||||
std::string reply_str = bitcoin_client->prepare_tx(unspent_utxo, outs);
|
||||
return sign_and_send_transaction_with_wallet(reply_str);
|
||||
}
|
||||
|
||||
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