Fix for failing Unit tests
This commit is contained in:
parent
34df0c0754
commit
28df2e744d
2 changed files with 613 additions and 18 deletions
|
|
@ -134,6 +134,8 @@ public:
|
|||
std::string operator()(const T& op)const;
|
||||
|
||||
std::string operator()(const transfer_operation& op)const;
|
||||
std::string operator()(const transfer_from_blind_operation& op)const;
|
||||
std::string operator()(const transfer_to_blind_operation& op)const;
|
||||
std::string operator()(const account_create_operation& op)const;
|
||||
std::string operator()(const account_update_operation& op)const;
|
||||
std::string operator()(const asset_create_operation& op)const;
|
||||
|
|
@ -2156,8 +2158,8 @@ public:
|
|||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (owner_account)(url)(block_signing_key)(broadcast) ) }
|
||||
|
||||
signed_transaction activate_deregistered_son(const string & owner_account,
|
||||
bool broadcast /* = false */)
|
||||
signed_transaction activate_deregistered_son(const string & owner_account,
|
||||
bool broadcast /* = false */)
|
||||
{ try {
|
||||
son_object son = get_son(owner_account);
|
||||
|
||||
|
|
@ -2406,7 +2408,7 @@ public:
|
|||
op.sidechain = sidechain;
|
||||
op.peerplays_uid = peerplays_uid;
|
||||
op.peerplays_transaction_id = peerplays_transaction_id;
|
||||
op.peerplays_from = peerplays_from;
|
||||
op.peerplays_from = peerplays_from;
|
||||
op.peerplays_asset = asset(asset_val.amount * asset_price.base.amount / asset_price.quote.amount);
|
||||
op.withdraw_sidechain = withdraw_sidechain;
|
||||
op.withdraw_address = withdraw_address;
|
||||
|
|
@ -2857,9 +2859,11 @@ public:
|
|||
{
|
||||
account_id_type son_owner_account_id = get_account_id(son);
|
||||
fc::optional<son_object> son_obj = _remote_db->get_son_by_account_id(son_owner_account_id);
|
||||
|
||||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a SON", ("son", son));
|
||||
auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id);
|
||||
dlog("Approving son account ${son}", ("son", son));
|
||||
if (!insert_result.second)
|
||||
FC_THROW("Account ${account} was already voting for SON ${son}", ("account", voting_account)("son", son));
|
||||
}
|
||||
|
|
@ -2870,13 +2874,16 @@ public:
|
|||
if (!son_obj)
|
||||
FC_THROW("Account ${son} is not registered as a SON", ("son", son));
|
||||
unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id);
|
||||
dlog("Rejecting son account ${son}", ("son", son));
|
||||
dlog("votes_removed ${votes_removed}", ("votes_removed", votes_removed));
|
||||
if (!votes_removed)
|
||||
FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son));
|
||||
}
|
||||
voting_account_object.options.extensions.value.num_son = desired_number_of_sons;
|
||||
|
||||
voting_account_object.options.num_son = desired_number_of_sons;
|
||||
dlog("desired_number_of_sons = ${desired_number_of_sons}", ("desired_number_of_sons", desired_number_of_sons));
|
||||
account_update_operation account_update_op;
|
||||
account_update_op.account = voting_account_object.id;
|
||||
dlog("account_update_op.account = ${account_update_op.account}", ("account_update_op.account", account_update_op.account));
|
||||
account_update_op.new_options = voting_account_object.options;
|
||||
|
||||
signed_transaction tx;
|
||||
|
|
@ -3470,6 +3477,70 @@ public:
|
|||
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
m["get_blind_balances"] = [this](variant result, const fc::variants& a)
|
||||
{
|
||||
auto r = result.as<vector<asset>>( GRAPHENE_MAX_NESTED_OBJECTS );
|
||||
vector<asset_object> asset_recs;
|
||||
std::transform(r.begin(), r.end(), std::back_inserter(asset_recs), [this](const asset& a) {
|
||||
return get_asset(a.asset_id);
|
||||
});
|
||||
|
||||
std::stringstream ss;
|
||||
for( unsigned i = 0; i < asset_recs.size(); ++i )
|
||||
ss << asset_recs[i].amount_to_pretty_string(r[i]) << "\n";
|
||||
|
||||
return ss.str();
|
||||
};
|
||||
m["transfer_to_blind"] = [this](variant result, const fc::variants& a)
|
||||
{
|
||||
auto r = result.as<blind_confirmation>( GRAPHENE_MAX_NESTED_OBJECTS );
|
||||
std::stringstream ss;
|
||||
r.trx.operations[0].visit( operation_printer( ss, *this, operation_result() ) );
|
||||
ss << "\n";
|
||||
for( const auto& out : r.outputs )
|
||||
{
|
||||
asset_object a = get_asset( out.decrypted_memo.amount.asset_id );
|
||||
ss << a.amount_to_pretty_string( out.decrypted_memo.amount ) << " to " << out.label << "\n\t receipt: " << out.confirmation_receipt <<"\n\n";
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
m["blind_transfer"] = [this](variant result, const fc::variants& a)
|
||||
{
|
||||
auto r = result.as<blind_confirmation>( GRAPHENE_MAX_NESTED_OBJECTS );
|
||||
std::stringstream ss;
|
||||
r.trx.operations[0].visit( operation_printer( ss, *this, operation_result() ) );
|
||||
ss << "\n";
|
||||
for( const auto& out : r.outputs )
|
||||
{
|
||||
asset_object a = get_asset( out.decrypted_memo.amount.asset_id );
|
||||
ss << a.amount_to_pretty_string( out.decrypted_memo.amount ) << " to " << out.label << "\n\t receipt: " << out.confirmation_receipt <<"\n\n";
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
m["receive_blind_transfer"] = [this](variant result, const fc::variants& a)
|
||||
{
|
||||
auto r = result.as<blind_receipt>( GRAPHENE_MAX_NESTED_OBJECTS );
|
||||
std::stringstream ss;
|
||||
asset_object as = get_asset( r.amount.asset_id );
|
||||
ss << as.amount_to_pretty_string( r.amount ) << " " << r.from_label << " => " << r.to_label << " " << r.memo <<"\n";
|
||||
return ss.str();
|
||||
};
|
||||
m["blind_history"] = [this](variant result, const fc::variants& a)
|
||||
{
|
||||
auto records = result.as<vector<blind_receipt>>( GRAPHENE_MAX_NESTED_OBJECTS );
|
||||
std::stringstream ss;
|
||||
ss << "WHEN "
|
||||
<< " " << "AMOUNT" << " " << "FROM" << " => " << "TO" << " " << "MEMO" <<"\n";
|
||||
ss << "====================================================================================\n";
|
||||
for( auto& r : records )
|
||||
{
|
||||
asset_object as = get_asset( r.amount.asset_id );
|
||||
ss << fc::get_approximate_relative_time_string( r.date )
|
||||
<< " " << as.amount_to_pretty_string( r.amount ) << " " << r.from_label << " => " << r.to_label << " " << r.memo <<"\n";
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
m["get_upcoming_tournaments"] = m["get_tournaments"] = m["get_tournaments_by_state"] = [this](variant result, const fc::variants& a)
|
||||
{
|
||||
const vector<tournament_object> tournaments = result.as<vector<tournament_object> >( GRAPHENE_MAX_NESTED_OBJECTS );
|
||||
|
|
@ -4330,6 +4401,26 @@ std::string operation_printer::operator()(const T& op)const
|
|||
out << " result: " << str_result;
|
||||
return "";
|
||||
}
|
||||
std::string operation_printer::operator()(const transfer_from_blind_operation& op)const
|
||||
{
|
||||
auto a = wallet.get_asset( op.fee.asset_id );
|
||||
auto receiver = wallet.get_account( op.to );
|
||||
|
||||
out << receiver.name
|
||||
<< " received " << a.amount_to_pretty_string( op.amount ) << " from blinded balance";
|
||||
return "";
|
||||
}
|
||||
std::string operation_printer::operator()(const transfer_to_blind_operation& op)const
|
||||
{
|
||||
auto fa = wallet.get_asset( op.fee.asset_id );
|
||||
auto a = wallet.get_asset( op.amount.asset_id );
|
||||
auto sender = wallet.get_account( op.from );
|
||||
|
||||
out << sender.name
|
||||
<< " sent " << a.amount_to_pretty_string( op.amount ) << " to " << op.outputs.size() << " blinded balance" << (op.outputs.size()>1?"s":"")
|
||||
<< " fee: " << fa.amount_to_pretty_string( op.fee );
|
||||
return "";
|
||||
}
|
||||
string operation_printer::operator()(const transfer_operation& op) const
|
||||
{
|
||||
out << "Transfer " << wallet.get_asset(op.amount.asset_id).amount_to_pretty_string(op.amount)
|
||||
|
|
@ -5324,7 +5415,7 @@ signed_transaction wallet_api::sidechain_withdrawal_transaction(const string &so
|
|||
const string &withdraw_amount)
|
||||
{
|
||||
return my->sidechain_withdrawal_transaction(son_name_or_id,
|
||||
block_num,
|
||||
block_num,
|
||||
sidechain,
|
||||
peerplays_uid,
|
||||
peerplays_transaction_id,
|
||||
|
|
@ -5454,7 +5545,7 @@ signed_transaction wallet_api::sidechain_deposit_transaction( const string &son
|
|||
const string &peerplays_from_name_or_id,
|
||||
const string &peerplays_to_name_or_id)
|
||||
{
|
||||
return my->sidechain_deposit_transaction(son_name_or_id,
|
||||
return my->sidechain_deposit_transaction(son_name_or_id,
|
||||
sidechain,
|
||||
transaction_id,
|
||||
operation_index,
|
||||
|
|
@ -6100,6 +6191,495 @@ bool wallet_api::set_key_label( public_key_type key, string label
|
|||
}
|
||||
return false;
|
||||
}
|
||||
map<string,public_key_type> wallet_api::get_blind_accounts()const
|
||||
{
|
||||
map<string,public_key_type> result;
|
||||
for( const auto& item : my->_wallet.labeled_keys )
|
||||
result[item.label] = item.key;
|
||||
return result;
|
||||
}
|
||||
map<string,public_key_type> wallet_api::get_my_blind_accounts()const
|
||||
{
|
||||
FC_ASSERT( !is_locked(), "Wallet is locked, please unlock to get all operations available" );
|
||||
map<string,public_key_type> result;
|
||||
for( const auto& item : my->_wallet.labeled_keys )
|
||||
{
|
||||
if( my->_keys.find(item.key) != my->_keys.end() )
|
||||
result[item.label] = item.key;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public_key_type wallet_api::create_blind_account( string label, string brain_key )
|
||||
{
|
||||
FC_ASSERT( !is_locked(), "Wallet is locked, please unlock to get all operations available" );
|
||||
|
||||
auto label_itr = my->_wallet.labeled_keys.get<by_label>().find(label);
|
||||
if( label_itr != my->_wallet.labeled_keys.get<by_label>().end() )
|
||||
FC_ASSERT( !"Key with label already exists" );
|
||||
brain_key = fc::trim_and_normalize_spaces( brain_key );
|
||||
auto secret = fc::sha256::hash( brain_key.c_str(), brain_key.size() );
|
||||
auto priv_key = fc::ecc::private_key::regenerate( secret );
|
||||
public_key_type pub_key = priv_key.get_public_key();
|
||||
|
||||
FC_ASSERT( set_key_label( pub_key, label ) );
|
||||
|
||||
my->_keys[pub_key] = graphene::utilities::key_to_wif( priv_key );
|
||||
|
||||
save_wallet_file();
|
||||
return pub_key;
|
||||
}
|
||||
|
||||
vector<asset> wallet_api::get_blind_balances( string key_or_label )
|
||||
{
|
||||
vector<asset> result;
|
||||
map<asset_id_type, share_type> balances;
|
||||
|
||||
vector<commitment_type> used;
|
||||
|
||||
auto pub_key = get_public_key( key_or_label );
|
||||
auto& to_asset_used_idx = my->_wallet.blind_receipts.get<by_to_asset_used>();
|
||||
auto start = to_asset_used_idx.lower_bound( std::make_tuple(pub_key,asset_id_type(0),false) );
|
||||
auto end = to_asset_used_idx.lower_bound( std::make_tuple(pub_key,asset_id_type(uint32_t(0xffffffff)),true) );
|
||||
while( start != end )
|
||||
{
|
||||
if( !start->used )
|
||||
{
|
||||
auto answer = my->_remote_db->get_blinded_balances( {start->commitment()} );
|
||||
if( answer.size() )
|
||||
balances[start->amount.asset_id] += start->amount.amount;
|
||||
else
|
||||
used.push_back( start->commitment() );
|
||||
}
|
||||
++start;
|
||||
}
|
||||
for( const auto& u : used )
|
||||
{
|
||||
auto itr = my->_wallet.blind_receipts.get<by_commitment>().find( u );
|
||||
my->_wallet.blind_receipts.modify( itr, []( blind_receipt& r ){ r.used = true; } );
|
||||
}
|
||||
for( auto item : balances )
|
||||
result.push_back( asset( item.second, item.first ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
blind_confirmation wallet_api::transfer_from_blind( string from_blind_account_key_or_label,
|
||||
string to_account_id_or_name,
|
||||
string amount_in,
|
||||
string symbol,
|
||||
bool broadcast )
|
||||
{ try {
|
||||
transfer_from_blind_operation from_blind;
|
||||
|
||||
|
||||
auto fees = my->_remote_db->get_global_properties().parameters.current_fees;
|
||||
fc::optional<asset_object> asset_obj = get_asset(symbol);
|
||||
FC_ASSERT(asset_obj.valid(), "Could not find asset matching ${asset}", ("asset", symbol));
|
||||
auto amount = asset_obj->amount_from_string(amount_in);
|
||||
|
||||
from_blind.fee = fees->calculate_fee( from_blind, asset_obj->options.core_exchange_rate );
|
||||
|
||||
auto blind_in = asset_obj->amount_to_string( from_blind.fee + amount );
|
||||
|
||||
|
||||
auto conf = blind_transfer_help( from_blind_account_key_or_label,
|
||||
from_blind_account_key_or_label,
|
||||
blind_in, symbol, false, true/*to_temp*/ );
|
||||
FC_ASSERT( conf.outputs.size() > 0 );
|
||||
|
||||
auto to_account = my->get_account( to_account_id_or_name );
|
||||
from_blind.to = to_account.id;
|
||||
from_blind.amount = amount;
|
||||
from_blind.blinding_factor = conf.outputs.back().decrypted_memo.blinding_factor;
|
||||
from_blind.inputs.push_back( {conf.outputs.back().decrypted_memo.commitment, authority() } );
|
||||
from_blind.fee = fees->calculate_fee( from_blind, asset_obj->options.core_exchange_rate );
|
||||
|
||||
idump( (from_blind) );
|
||||
conf.trx.operations.push_back(from_blind);
|
||||
ilog( "about to validate" );
|
||||
conf.trx.validate();
|
||||
|
||||
if( broadcast && conf.outputs.size() == 2 ) {
|
||||
|
||||
// Save the change
|
||||
blind_confirmation::output conf_output;
|
||||
blind_confirmation::output change_output = conf.outputs[0];
|
||||
|
||||
// The wallet must have a private key for confirmation.to, this is used to decrypt the memo
|
||||
public_key_type from_key = get_public_key(from_blind_account_key_or_label);
|
||||
conf_output.confirmation.to = from_key;
|
||||
conf_output.confirmation.one_time_key = change_output.confirmation.one_time_key;
|
||||
conf_output.confirmation.encrypted_memo = change_output.confirmation.encrypted_memo;
|
||||
conf_output.confirmation_receipt = conf_output.confirmation;
|
||||
//try {
|
||||
receive_blind_transfer( conf_output.confirmation_receipt, from_blind_account_key_or_label, "@"+to_account.name );
|
||||
//} catch ( ... ){}
|
||||
}
|
||||
|
||||
ilog( "about to broadcast" );
|
||||
conf.trx = sign_transaction( conf.trx, broadcast );
|
||||
|
||||
return conf;
|
||||
} FC_CAPTURE_AND_RETHROW( (from_blind_account_key_or_label)(to_account_id_or_name)(amount_in)(symbol) ) }
|
||||
|
||||
blind_confirmation wallet_api::blind_transfer( string from_key_or_label,
|
||||
string to_key_or_label,
|
||||
string amount_in,
|
||||
string symbol,
|
||||
bool broadcast )
|
||||
{
|
||||
return blind_transfer_help( from_key_or_label, to_key_or_label, amount_in, symbol, broadcast, false );
|
||||
}
|
||||
blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
|
||||
string to_key_or_label,
|
||||
string amount_in,
|
||||
string symbol,
|
||||
bool broadcast,
|
||||
bool to_temp )
|
||||
{
|
||||
blind_confirmation confirm;
|
||||
try {
|
||||
|
||||
FC_ASSERT( !is_locked(), "Wallet is locked, please unlock to get all operations available" );
|
||||
public_key_type from_key = get_public_key(from_key_or_label);
|
||||
public_key_type to_key = get_public_key(to_key_or_label);
|
||||
|
||||
fc::optional<asset_object> asset_obj = get_asset(symbol);
|
||||
FC_ASSERT(asset_obj.valid(), "Could not find asset matching ${asset}", ("asset", symbol));
|
||||
|
||||
blind_transfer_operation blind_tr;
|
||||
blind_tr.outputs.resize(2);
|
||||
|
||||
auto fees = my->_remote_db->get_global_properties().parameters.current_fees;
|
||||
|
||||
auto amount = asset_obj->amount_from_string(amount_in);
|
||||
|
||||
asset total_amount = asset_obj->amount(0);
|
||||
|
||||
vector<fc::sha256> blinding_factors;
|
||||
|
||||
//auto from_priv_key = my->get_private_key( from_key );
|
||||
|
||||
blind_tr.fee = fees->calculate_fee( blind_tr, asset_obj->options.core_exchange_rate );
|
||||
|
||||
vector<commitment_type> used;
|
||||
|
||||
auto& to_asset_used_idx = my->_wallet.blind_receipts.get<by_to_asset_used>();
|
||||
auto start = to_asset_used_idx.lower_bound( std::make_tuple(from_key,amount.asset_id,false) );
|
||||
auto end = to_asset_used_idx.lower_bound( std::make_tuple(from_key,amount.asset_id,true) );
|
||||
while( start != end )
|
||||
{
|
||||
auto result = my->_remote_db->get_blinded_balances( {start->commitment() } );
|
||||
if( result.size() == 0 )
|
||||
{
|
||||
used.push_back( start->commitment() );
|
||||
}
|
||||
else
|
||||
{
|
||||
blind_tr.inputs.push_back({start->commitment(), start->control_authority});
|
||||
blinding_factors.push_back( start->data.blinding_factor );
|
||||
total_amount += start->amount;
|
||||
|
||||
if( total_amount >= amount + blind_tr.fee )
|
||||
break;
|
||||
}
|
||||
++start;
|
||||
}
|
||||
for( const auto& u : used )
|
||||
{
|
||||
auto itr = my->_wallet.blind_receipts.get<by_commitment>().find( u );
|
||||
my->_wallet.blind_receipts.modify( itr, []( blind_receipt& r ){ r.used = true; } );
|
||||
}
|
||||
|
||||
FC_ASSERT( total_amount >= amount+blind_tr.fee, "Insufficent Balance", ("available",total_amount)("amount",amount)("fee",blind_tr.fee) );
|
||||
|
||||
auto one_time_key = fc::ecc::private_key::generate();
|
||||
auto secret = one_time_key.get_shared_secret( to_key );
|
||||
auto child = fc::sha256::hash( secret );
|
||||
auto nonce = fc::sha256::hash( one_time_key.get_secret() );
|
||||
auto blind_factor = fc::sha256::hash( child );
|
||||
|
||||
auto from_secret = one_time_key.get_shared_secret( from_key );
|
||||
auto from_child = fc::sha256::hash( from_secret );
|
||||
auto from_nonce = fc::sha256::hash( nonce );
|
||||
|
||||
auto change = total_amount - amount - blind_tr.fee;
|
||||
fc::sha256 change_blind_factor;
|
||||
fc::sha256 to_blind_factor;
|
||||
if( change.amount > 0 )
|
||||
{
|
||||
idump(("to_blind_factor")(blind_factor) );
|
||||
blinding_factors.push_back( blind_factor );
|
||||
change_blind_factor = fc::ecc::blind_sum( blinding_factors, blinding_factors.size() - 1 );
|
||||
wdump(("change_blind_factor")(change_blind_factor) );
|
||||
}
|
||||
else // change == 0
|
||||
{
|
||||
blind_tr.outputs.resize(1);
|
||||
blind_factor = fc::ecc::blind_sum( blinding_factors, blinding_factors.size() );
|
||||
idump(("to_sum_blind_factor")(blind_factor) );
|
||||
blinding_factors.push_back( blind_factor );
|
||||
idump(("nochange to_blind_factor")(blind_factor) );
|
||||
}
|
||||
fc::ecc::public_key from_pub_key = from_key;
|
||||
fc::ecc::public_key to_pub_key = to_key;
|
||||
|
||||
blind_output to_out;
|
||||
to_out.owner = to_temp ? authority() : authority( 1, public_key_type( to_pub_key.child( child ) ), 1 );
|
||||
to_out.commitment = fc::ecc::blind( blind_factor, amount.amount.value );
|
||||
idump(("to_out.blind")(blind_factor)(to_out.commitment) );
|
||||
|
||||
|
||||
if( blind_tr.outputs.size() > 1 )
|
||||
{
|
||||
to_out.range_proof = fc::ecc::range_proof_sign( 0, to_out.commitment, blind_factor, nonce, 0, 0, amount.amount.value );
|
||||
|
||||
blind_output change_out;
|
||||
change_out.owner = authority( 1, public_key_type( from_pub_key.child( from_child ) ), 1 );
|
||||
change_out.commitment = fc::ecc::blind( change_blind_factor, change.amount.value );
|
||||
change_out.range_proof = fc::ecc::range_proof_sign( 0, change_out.commitment, change_blind_factor, from_nonce, 0, 0, change.amount.value );
|
||||
blind_tr.outputs[1] = change_out;
|
||||
|
||||
|
||||
blind_confirmation::output conf_output;
|
||||
conf_output.label = from_key_or_label;
|
||||
conf_output.pub_key = from_key;
|
||||
conf_output.decrypted_memo.from = from_key;
|
||||
conf_output.decrypted_memo.amount = change;
|
||||
conf_output.decrypted_memo.blinding_factor = change_blind_factor;
|
||||
conf_output.decrypted_memo.commitment = change_out.commitment;
|
||||
conf_output.decrypted_memo.check = from_secret._hash[0];
|
||||
conf_output.confirmation.one_time_key = one_time_key.get_public_key();
|
||||
conf_output.confirmation.to = from_key;
|
||||
conf_output.confirmation.encrypted_memo = fc::aes_encrypt( from_secret, fc::raw::pack( conf_output.decrypted_memo ) );
|
||||
conf_output.auth = change_out.owner;
|
||||
conf_output.confirmation_receipt = conf_output.confirmation;
|
||||
|
||||
confirm.outputs.push_back( conf_output );
|
||||
}
|
||||
blind_tr.outputs[0] = to_out;
|
||||
|
||||
blind_confirmation::output conf_output;
|
||||
conf_output.label = to_key_or_label;
|
||||
conf_output.pub_key = to_key;
|
||||
conf_output.decrypted_memo.from = from_key;
|
||||
conf_output.decrypted_memo.amount = amount;
|
||||
conf_output.decrypted_memo.blinding_factor = blind_factor;
|
||||
conf_output.decrypted_memo.commitment = to_out.commitment;
|
||||
conf_output.decrypted_memo.check = secret._hash[0];
|
||||
conf_output.confirmation.one_time_key = one_time_key.get_public_key();
|
||||
conf_output.confirmation.to = to_key;
|
||||
conf_output.confirmation.encrypted_memo = fc::aes_encrypt( secret, fc::raw::pack( conf_output.decrypted_memo ) );
|
||||
conf_output.auth = to_out.owner;
|
||||
conf_output.confirmation_receipt = conf_output.confirmation;
|
||||
|
||||
confirm.outputs.push_back( conf_output );
|
||||
|
||||
/** commitments must be in sorted order */
|
||||
std::sort( blind_tr.outputs.begin(), blind_tr.outputs.end(),
|
||||
[&]( const blind_output& a, const blind_output& b ){ return a.commitment < b.commitment; } );
|
||||
std::sort( blind_tr.inputs.begin(), blind_tr.inputs.end(),
|
||||
[&]( const blind_input& a, const blind_input& b ){ return a.commitment < b.commitment; } );
|
||||
|
||||
confirm.trx.operations.emplace_back( std::move(blind_tr) );
|
||||
ilog( "validate before" );
|
||||
confirm.trx.validate();
|
||||
confirm.trx = sign_transaction(confirm.trx, broadcast);
|
||||
|
||||
if( broadcast )
|
||||
{
|
||||
for( const auto& out : confirm.outputs )
|
||||
{
|
||||
try { receive_blind_transfer( out.confirmation_receipt, from_key_or_label, "" ); } catch ( ... ){}
|
||||
}
|
||||
}
|
||||
|
||||
return confirm;
|
||||
} FC_CAPTURE_AND_RETHROW( (from_key_or_label)(to_key_or_label)(amount_in)(symbol)(broadcast)(confirm) ) }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Transfers a public balance from @from to one or more blinded balances using a
|
||||
* stealth transfer.
|
||||
*/
|
||||
blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name,
|
||||
string asset_symbol,
|
||||
/** map from key or label to amount */
|
||||
vector<pair<string, string>> to_amounts,
|
||||
bool broadcast )
|
||||
{ try {
|
||||
FC_ASSERT( !is_locked(), "Wallet is locked, please unlock to get all operations available" );
|
||||
idump((to_amounts));
|
||||
|
||||
blind_confirmation confirm;
|
||||
account_object from_account = my->get_account(from_account_id_or_name);
|
||||
|
||||
fc::optional<asset_object> asset_obj = get_asset(asset_symbol);
|
||||
FC_ASSERT(asset_obj, "Could not find asset matching ${asset}", ("asset", asset_symbol));
|
||||
|
||||
transfer_to_blind_operation bop;
|
||||
bop.from = from_account.id;
|
||||
|
||||
vector<fc::sha256> blinding_factors;
|
||||
|
||||
asset total_amount = asset_obj->amount(0);
|
||||
|
||||
for( auto item : to_amounts )
|
||||
{
|
||||
auto one_time_key = fc::ecc::private_key::generate();
|
||||
auto to_key = get_public_key( item.first );
|
||||
auto secret = one_time_key.get_shared_secret( to_key );
|
||||
auto child = fc::sha256::hash( secret );
|
||||
auto nonce = fc::sha256::hash( one_time_key.get_secret() );
|
||||
auto blind_factor = fc::sha256::hash( child );
|
||||
|
||||
blinding_factors.push_back( blind_factor );
|
||||
|
||||
auto amount = asset_obj->amount_from_string(item.second);
|
||||
total_amount += amount;
|
||||
|
||||
|
||||
fc::ecc::public_key to_pub_key = to_key;
|
||||
blind_output out;
|
||||
out.owner = authority( 1, public_key_type( to_pub_key.child( child ) ), 1 );
|
||||
out.commitment = fc::ecc::blind( blind_factor, amount.amount.value );
|
||||
if( to_amounts.size() > 1 )
|
||||
out.range_proof = fc::ecc::range_proof_sign( 0, out.commitment, blind_factor, nonce, 0, 0, amount.amount.value );
|
||||
|
||||
|
||||
blind_confirmation::output conf_output;
|
||||
conf_output.label = item.first;
|
||||
conf_output.pub_key = to_key;
|
||||
conf_output.decrypted_memo.amount = amount;
|
||||
conf_output.decrypted_memo.blinding_factor = blind_factor;
|
||||
conf_output.decrypted_memo.commitment = out.commitment;
|
||||
conf_output.decrypted_memo.check = secret._hash[0];
|
||||
conf_output.confirmation.one_time_key = one_time_key.get_public_key();
|
||||
conf_output.confirmation.to = to_key;
|
||||
conf_output.confirmation.encrypted_memo = fc::aes_encrypt( secret, fc::raw::pack( conf_output.decrypted_memo ) );
|
||||
conf_output.confirmation_receipt = conf_output.confirmation;
|
||||
|
||||
confirm.outputs.push_back( conf_output );
|
||||
|
||||
bop.outputs.push_back(out);
|
||||
}
|
||||
bop.amount = total_amount;
|
||||
bop.blinding_factor = fc::ecc::blind_sum( blinding_factors, blinding_factors.size() );
|
||||
|
||||
/** commitments must be in sorted order */
|
||||
std::sort( bop.outputs.begin(), bop.outputs.end(),
|
||||
[&]( const blind_output& a, const blind_output& b ){ return a.commitment < b.commitment; } );
|
||||
|
||||
confirm.trx.operations.push_back( bop );
|
||||
my->set_operation_fees( confirm.trx, my->_remote_db->get_global_properties().parameters.current_fees);
|
||||
confirm.trx.validate();
|
||||
confirm.trx = sign_transaction(confirm.trx, broadcast);
|
||||
|
||||
if( broadcast )
|
||||
{
|
||||
for( const auto& out : confirm.outputs )
|
||||
{
|
||||
try { receive_blind_transfer( out.confirmation_receipt, "@"+from_account.name, "from @"+from_account.name ); } catch ( ... ){}
|
||||
}
|
||||
}
|
||||
|
||||
return confirm;
|
||||
} FC_CAPTURE_AND_RETHROW( (from_account_id_or_name)(asset_symbol)(to_amounts) ) }
|
||||
|
||||
blind_receipt wallet_api::receive_blind_transfer( string confirmation_receipt, string opt_from, string opt_memo )
|
||||
{
|
||||
FC_ASSERT( !is_locked(), "Wallet is locked, please unlock to get all operations available" );
|
||||
stealth_confirmation conf(confirmation_receipt);
|
||||
FC_ASSERT( conf.to );
|
||||
|
||||
blind_receipt result;
|
||||
result.conf = conf;
|
||||
|
||||
auto to_priv_key_itr = my->_keys.find( *conf.to );
|
||||
FC_ASSERT( to_priv_key_itr != my->_keys.end(), "No private key for receiver", ("conf",conf) );
|
||||
|
||||
|
||||
auto to_priv_key = wif_to_key( to_priv_key_itr->second );
|
||||
FC_ASSERT( to_priv_key );
|
||||
|
||||
auto secret = to_priv_key->get_shared_secret( conf.one_time_key );
|
||||
auto child = fc::sha256::hash( secret );
|
||||
|
||||
auto child_priv_key = to_priv_key->child( child );
|
||||
//auto blind_factor = fc::sha256::hash( child );
|
||||
|
||||
auto plain_memo = fc::aes_decrypt( secret, conf.encrypted_memo );
|
||||
auto memo = fc::raw::unpack<stealth_confirmation::memo_data>( plain_memo );
|
||||
|
||||
result.to_key = *conf.to;
|
||||
result.to_label = get_key_label( result.to_key );
|
||||
if( memo.from )
|
||||
{
|
||||
result.from_key = *memo.from;
|
||||
result.from_label = get_key_label( result.from_key );
|
||||
if( result.from_label == string() )
|
||||
{
|
||||
result.from_label = opt_from;
|
||||
set_key_label( result.from_key, result.from_label );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.from_label = opt_from;
|
||||
}
|
||||
result.amount = memo.amount;
|
||||
result.memo = opt_memo;
|
||||
|
||||
// confirm the amount matches the commitment (verify the blinding factor)
|
||||
auto commtiment_test = fc::ecc::blind( memo.blinding_factor, memo.amount.amount.value );
|
||||
FC_ASSERT( fc::ecc::verify_sum( {commtiment_test}, {memo.commitment}, 0 ) );
|
||||
|
||||
blind_balance bal;
|
||||
bal.amount = memo.amount;
|
||||
bal.to = *conf.to;
|
||||
if( memo.from ) bal.from = *memo.from;
|
||||
bal.one_time_key = conf.one_time_key;
|
||||
bal.blinding_factor = memo.blinding_factor;
|
||||
bal.commitment = memo.commitment;
|
||||
bal.used = false;
|
||||
|
||||
auto child_pubkey = child_priv_key.get_public_key();
|
||||
auto owner = authority(1, public_key_type(child_pubkey), 1);
|
||||
result.control_authority = owner;
|
||||
result.data = memo;
|
||||
|
||||
auto child_key_itr = owner.key_auths.find( child_pubkey );
|
||||
if( child_key_itr != owner.key_auths.end() )
|
||||
my->_keys[child_key_itr->first] = key_to_wif( child_priv_key );
|
||||
|
||||
// my->_wallet.blinded_balances[memo.amount.asset_id][bal.to].push_back( bal );
|
||||
|
||||
result.date = fc::time_point::now();
|
||||
my->_wallet.blind_receipts.insert( result );
|
||||
my->_keys[child_pubkey] = key_to_wif( child_priv_key );
|
||||
|
||||
save_wallet_file();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<blind_receipt> wallet_api::blind_history( string key_or_account )
|
||||
{
|
||||
vector<blind_receipt> result;
|
||||
auto pub_key = get_public_key( key_or_account );
|
||||
|
||||
if( pub_key == public_key_type() )
|
||||
return vector<blind_receipt>();
|
||||
|
||||
for( auto& r : my->_wallet.blind_receipts )
|
||||
{
|
||||
if( r.from_key == pub_key || r.to_key == pub_key )
|
||||
result.push_back( r );
|
||||
}
|
||||
std::sort( result.begin(), result.end(), [&]( const blind_receipt& a, const blind_receipt& b ){ return a.date > b.date; } );
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////
|
||||
// peerplays //
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
fixture_(fixture)
|
||||
{
|
||||
fixture_.init_nathan();
|
||||
fixture_.generate_blocks(HARDFORK_SON3_TIME);
|
||||
fixture_.generate_blocks(HARDFORK_SON_FOR_HIVE_TIME);
|
||||
fixture_.generate_block();
|
||||
}
|
||||
|
||||
|
|
@ -232,6 +232,7 @@ BOOST_AUTO_TEST_CASE( son_voting )
|
|||
con.wallet_api_ptr->create_vesting_balance("nathan", "1000", "1.3.0", vesting_balance_type::gpos, true);
|
||||
// Vote for a son1account
|
||||
BOOST_TEST_MESSAGE("Voting for son1account");
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", true, true);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
|
|
@ -337,8 +338,7 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
|
|||
global_property_object gpo;
|
||||
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
//! Set son number as 5 (as the begining son count)
|
||||
unsigned int son_number = 5;
|
||||
unsigned int son_number = gpo.parameters.maximum_son_count();
|
||||
|
||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
|
|||
BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
BOOST_CHECK(gpo.active_sons.size() == son_number);
|
||||
BOOST_CHECK(gpo.active_sons.size() == gpo.parameters.maximum_son_count());
|
||||
|
||||
} catch( fc::exception& e ) {
|
||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
||||
|
|
@ -454,13 +454,20 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
|
||||
sidechain_public_keys.clear();
|
||||
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1";
|
||||
BOOST_TEST_MESSAGE("sidechain_public_keys add for bitcoin account 1");
|
||||
sidechain_public_keys[sidechain_type::hive] = "hive account 1";
|
||||
BOOST_TEST_MESSAGE("sidechain_public_keys add for hive account 1");
|
||||
sth.create_son("son1account", "http://son1", sidechain_public_keys);
|
||||
BOOST_TEST_MESSAGE("created son account 1");
|
||||
|
||||
sidechain_public_keys.clear();
|
||||
sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2";
|
||||
BOOST_TEST_MESSAGE("sidechain_public_keys add for bitcoin account 2");
|
||||
sidechain_public_keys[sidechain_type::hive] = "hive account 2";
|
||||
BOOST_TEST_MESSAGE("sidechain_public_keys add for hive account 2");
|
||||
sth.create_son("son2account", "http://son2", sidechain_public_keys);
|
||||
BOOST_TEST_MESSAGE("created son account 2");
|
||||
|
||||
|
||||
BOOST_TEST_MESSAGE("Vote for 2 accounts with update_son_votes");
|
||||
|
||||
|
|
@ -472,13 +479,17 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
// Get votes at start
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_start_votes = son1_obj.total_votes;
|
||||
BOOST_TEST_MESSAGE("son1_start_votes: " << son1_start_votes);
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_start_votes = son2_obj.total_votes;
|
||||
|
||||
BOOST_TEST_MESSAGE("son2_start_votes: " << son2_start_votes);
|
||||
std::vector<std::string> accepted;
|
||||
std::vector<std::string> rejected;
|
||||
signed_transaction update_votes_tx;
|
||||
|
||||
generate_block();
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
||||
// Vote for both SONs
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
|
|
@ -493,10 +504,12 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_TEST_MESSAGE("son1_end_votes: " << son1_end_votes);
|
||||
BOOST_CHECK(son1_end_votes > son1_start_votes);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_TEST_MESSAGE("son2_end_votes: " << son2_end_votes);
|
||||
BOOST_CHECK(son2_end_votes > son2_start_votes);
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
|
|
@ -513,18 +526,21 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
// Verify the votes
|
||||
son1_obj = con.wallet_api_ptr->get_son("son1account");
|
||||
son1_end_votes = son1_obj.total_votes;
|
||||
BOOST_TEST_MESSAGE("son1_end_votes: " << son1_end_votes);
|
||||
BOOST_CHECK(son1_end_votes < son1_start_votes);
|
||||
son1_start_votes = son1_end_votes;
|
||||
son2_obj = con.wallet_api_ptr->get_son("son2account");
|
||||
|
||||
// voice distribution changed, SON2 now has all voices
|
||||
son2_end_votes = son2_obj.total_votes;
|
||||
BOOST_TEST_MESSAGE("son2_end_votes: " << son2_end_votes);
|
||||
BOOST_CHECK((son2_end_votes > son2_start_votes)); // nathan spent funds for vb, it has different voting power
|
||||
son2_start_votes = son2_end_votes;
|
||||
|
||||
// Try to reject incorrect SON
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
rejected.push_back("son1accnt");
|
||||
rejected.push_back("son1account");
|
||||
BOOST_CHECK_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true), fc::exception);
|
||||
generate_block();
|
||||
|
|
@ -560,8 +576,8 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test )
|
|||
// Try to accept and reject the same SON
|
||||
accepted.clear();
|
||||
rejected.clear();
|
||||
rejected.push_back("son1accnt");
|
||||
accepted.push_back("son1accnt");
|
||||
rejected.push_back("son1account");
|
||||
accepted.push_back("son1account");
|
||||
BOOST_REQUIRE_THROW(update_votes_tx = con.wallet_api_ptr->update_son_votes("nathan", accepted,
|
||||
rejected, 1, true), fc::exception);
|
||||
BOOST_CHECK(generate_maintenance_block());
|
||||
|
|
@ -645,8 +661,7 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
|
|||
global_property_object gpo;
|
||||
|
||||
gpo = con.wallet_api_ptr->get_global_properties();
|
||||
//! Set son number as 5 (as the begining son count)
|
||||
unsigned int son_number = 5;
|
||||
unsigned int son_number = gpo.parameters.maximum_son_count();
|
||||
|
||||
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||
|
||||
|
|
@ -688,7 +703,7 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture )
|
|||
|
||||
map<string, son_id_type> active_sons = con.wallet_api_ptr->list_active_sons();
|
||||
BOOST_CHECK(active_sons.size() == son_number);
|
||||
for(unsigned int i = 1; i < son_number + 1; i++)
|
||||
for(unsigned int i = 1; i < son_number; i++)
|
||||
{
|
||||
std::string name = "sonaccount" + fc::to_pretty_string(i);
|
||||
BOOST_CHECK(active_sons.find(name) != active_sons.end());
|
||||
|
|
|
|||
Loading…
Reference in a new issue