#357 secp256k1 lib from libbitcoin

This commit is contained in:
Vlad Dobromyslov 2022-07-07 00:53:23 +00:00 committed by serkixenos
parent 09579fbab1
commit 3b5e928094
20 changed files with 65 additions and 1440 deletions

2
.gitmodules vendored
View file

@ -5,5 +5,5 @@
[submodule "libraries/fc"]
path = libraries/fc
url = https://gitlab.com/PBSA/tools-libs/peerplays-fc.git
branch = latest-fc
branch = develop
ignore = dirty

View file

@ -45,7 +45,6 @@ template class fc::api<graphene::app::block_api>;
template class fc::api<graphene::app::network_broadcast_api>;
template class fc::api<graphene::app::network_node_api>;
template class fc::api<graphene::app::history_api>;
template class fc::api<graphene::app::crypto_api>;
template class fc::api<graphene::app::asset_api>;
template class fc::api<graphene::debug_witness::debug_api>;
template class fc::api<graphene::app::login_api>;
@ -90,8 +89,6 @@ void login_api::enable_api(const std::string &api_name) {
_history_api = std::make_shared<history_api>(_app);
} else if (api_name == "network_node_api") {
_network_node_api = std::make_shared<network_node_api>(std::ref(_app));
} else if (api_name == "crypto_api") {
_crypto_api = std::make_shared<crypto_api>();
} else if (api_name == "asset_api") {
_asset_api = std::make_shared<asset_api>(_app);
} else if (api_name == "debug_api") {
@ -289,11 +286,6 @@ fc::api<history_api> login_api::history() const {
return *_history_api;
}
fc::api<crypto_api> login_api::crypto() const {
FC_ASSERT(_crypto_api);
return *_crypto_api;
}
fc::api<asset_api> login_api::asset() const {
FC_ASSERT(_asset_api);
return *_asset_api;
@ -522,55 +514,6 @@ vector<bucket_object> history_api::get_market_history(std::string asset_a, std::
FC_CAPTURE_AND_RETHROW((asset_a)(asset_b)(bucket_seconds)(start)(end))
}
crypto_api::crypto_api(){};
commitment_type crypto_api::blind(const blind_factor_type &blind, uint64_t value) {
return fc::ecc::blind(blind, value);
}
blind_factor_type crypto_api::blind_sum(const std::vector<blind_factor_type> &blinds_in, uint32_t non_neg) {
return fc::ecc::blind_sum(blinds_in, non_neg);
}
bool crypto_api::verify_sum(const std::vector<commitment_type> &commits_in, const std::vector<commitment_type> &neg_commits_in, int64_t excess) {
return fc::ecc::verify_sum(commits_in, neg_commits_in, excess);
}
verify_range_result crypto_api::verify_range(const commitment_type &commit, const std::vector<char> &proof) {
verify_range_result result;
result.success = fc::ecc::verify_range(result.min_val, result.max_val, commit, proof);
return result;
}
std::vector<char> crypto_api::range_proof_sign(uint64_t min_value,
const commitment_type &commit,
const blind_factor_type &commit_blind,
const blind_factor_type &nonce,
int8_t base10_exp,
uint8_t min_bits,
uint64_t actual_value) {
return fc::ecc::range_proof_sign(min_value, commit, commit_blind, nonce, base10_exp, min_bits, actual_value);
}
verify_range_proof_rewind_result crypto_api::verify_range_proof_rewind(const blind_factor_type &nonce,
const commitment_type &commit,
const std::vector<char> &proof) {
verify_range_proof_rewind_result result;
result.success = fc::ecc::verify_range_proof_rewind(result.blind_out,
result.value_out,
result.message_out,
nonce,
result.min_val,
result.max_val,
const_cast<commitment_type &>(commit),
proof);
return result;
}
range_proof_info crypto_api::range_get_info(const std::vector<char> &proof) {
return fc::ecc::range_get_info(proof);
}
// asset_api
asset_api::asset_api(graphene::app::application &app) :
_app(app),

View file

@ -362,7 +362,6 @@ public:
wild_access.allowed_apis.push_back("database_api");
wild_access.allowed_apis.push_back("network_broadcast_api");
wild_access.allowed_apis.push_back("history_api");
wild_access.allowed_apis.push_back("crypto_api");
wild_access.allowed_apis.push_back("bookie_api");
wild_access.allowed_apis.push_back("affiliate_stats_api");
wild_access.allowed_apis.push_back("sidechain_api");

View file

@ -237,9 +237,6 @@ public:
// Proposed transactions
vector<proposal_object> get_proposed_transactions(const std::string account_id_or_name) const;
// Blinded balances
vector<blinded_balance_object> get_blinded_balances(const flat_set<commitment_type> &commitments) const;
// Tournaments
vector<tournament_object> get_tournaments_in_state(tournament_state state, uint32_t limit) const;
vector<tournament_object> get_tournaments(tournament_id_type stop, unsigned limit, tournament_id_type start);
@ -2650,29 +2647,6 @@ vector<proposal_object> database_api_impl::get_proposed_transactions(const std::
return result;
}
//////////////////////////////////////////////////////////////////////
// //
// Blinded balances //
// //
//////////////////////////////////////////////////////////////////////
vector<blinded_balance_object> database_api::get_blinded_balances(const flat_set<commitment_type> &commitments) const {
return my->get_blinded_balances(commitments);
}
vector<blinded_balance_object> database_api_impl::get_blinded_balances(const flat_set<commitment_type> &commitments) const {
vector<blinded_balance_object> result;
result.reserve(commitments.size());
const auto &bal_idx = _db.get_index_type<blinded_balance_index>();
const auto &by_commitment_idx = bal_idx.indices().get<by_commitment>();
for (const auto &c : commitments) {
auto itr = by_commitment_idx.find(c);
if (itr != by_commitment_idx.end())
result.push_back(*itr);
}
return result;
}
//////////////////////////////////////////////////////////////////////
// //
// Tournament methods //

View file

@ -289,33 +289,6 @@ private:
std::function<void(const variant &)> _on_pending_transaction;
};
class crypto_api {
public:
crypto_api();
fc::ecc::commitment_type blind(const fc::ecc::blind_factor_type &blind, uint64_t value);
fc::ecc::blind_factor_type blind_sum(const std::vector<blind_factor_type> &blinds_in, uint32_t non_neg);
bool verify_sum(const std::vector<commitment_type> &commits_in, const std::vector<commitment_type> &neg_commits_in, int64_t excess);
verify_range_result verify_range(const fc::ecc::commitment_type &commit, const std::vector<char> &proof);
std::vector<char> range_proof_sign(uint64_t min_value,
const commitment_type &commit,
const blind_factor_type &commit_blind,
const blind_factor_type &nonce,
int8_t base10_exp,
uint8_t min_bits,
uint64_t actual_value);
verify_range_proof_rewind_result verify_range_proof_rewind(const blind_factor_type &nonce,
const fc::ecc::commitment_type &commit,
const std::vector<char> &proof);
range_proof_info range_get_info(const std::vector<char> &proof);
};
/**
* @brief
*/
@ -359,7 +332,6 @@ extern template class fc::api<graphene::app::block_api>;
extern template class fc::api<graphene::app::network_broadcast_api>;
extern template class fc::api<graphene::app::network_node_api>;
extern template class fc::api<graphene::app::history_api>;
extern template class fc::api<graphene::app::crypto_api>;
extern template class fc::api<graphene::app::asset_api>;
extern template class fc::api<graphene::debug_witness::debug_api>;
@ -394,8 +366,6 @@ public:
fc::api<history_api> history() const;
/// @brief Retrieve the network node API
fc::api<network_node_api> network_node() const;
/// @brief Retrieve the cryptography API
fc::api<crypto_api> crypto() const;
/// @brief Retrieve the asset API
fc::api<asset_api> asset() const;
/// @brief Retrieve the debug API (if available)
@ -417,7 +387,6 @@ private:
optional<fc::api<network_broadcast_api>> _network_broadcast_api;
optional<fc::api<network_node_api>> _network_node_api;
optional<fc::api<history_api>> _history_api;
optional<fc::api<crypto_api>> _crypto_api;
optional<fc::api<asset_api>> _asset_api;
optional<fc::api<graphene::debug_witness::debug_api>> _debug_api;
optional<fc::api<graphene::bookie::bookie_api>> _bookie_api;
@ -475,15 +444,6 @@ FC_API(graphene::app::network_node_api,
(subscribe_to_pending_transactions)
(unsubscribe_from_pending_transactions))
FC_API(graphene::app::crypto_api,
(blind)
(blind_sum)
(verify_sum)
(verify_range)
(range_proof_sign)
(verify_range_proof_rewind)
(range_get_info))
FC_API(graphene::app::asset_api,
(get_asset_holders)
(get_asset_holders_count)
@ -496,7 +456,6 @@ FC_API(graphene::app::login_api,
(database)
(history)
(network_node)
(crypto)
(asset)
(debug)
(bookie)

View file

@ -877,15 +877,6 @@ public:
*/
vector<proposal_object> get_proposed_transactions(const std::string account_id_or_name) const;
//////////////////////
// Blinded balances //
//////////////////////
/**
* @return the set of blinded balance objects by commitment ID
*/
vector<blinded_balance_object> get_blinded_balances(const flat_set<commitment_type> &commitments) const;
/////////////////
// Tournaments //
/////////////////
@ -1198,9 +1189,6 @@ FC_API(graphene::app::database_api,
// Proposed transactions
(get_proposed_transactions)
// Blinded balances
(get_blinded_balances)
// Tournaments
(get_tournaments_in_state)
(get_tournaments_by_state)

View file

@ -33,149 +33,45 @@ namespace graphene { namespace chain {
void_result transfer_to_blind_evaluator::do_evaluate( const transfer_to_blind_operation& o )
{ try {
const auto& d = db();
const auto& atype = o.amount.asset_id(db());
FC_ASSERT( atype.allow_confidential() );
FC_ASSERT( !atype.is_transfer_restricted() );
FC_ASSERT( !(atype.options.flags & white_list) );
for( const auto& out : o.outputs )
{
for( const auto& a : out.owner.account_auths )
a.first(d); // verify all accounts exist and are valid
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o )
{ try {
db().adjust_balance( o.from, -o.amount );
const auto& add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
db().modify( add, [&]( asset_dynamic_data_object& obj ){
obj.confidential_supply += o.amount.amount;
FC_ASSERT( obj.confidential_supply >= 0 );
});
for( const auto& out : o.outputs )
{
db().create<blinded_balance_object>( [&]( blinded_balance_object& obj ){
obj.asset_id = o.amount.asset_id;
obj.owner = out.owner;
obj.commitment = out.commitment;
});
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void transfer_to_blind_evaluator::pay_fee()
{
if( db().head_block_time() >= HARDFORK_563_TIME )
pay_fba_fee( fba_accumulator_id_transfer_to_blind );
else
generic_evaluator::pay_fee();
}
void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o )
{ try {
const auto& d = db();
o.fee.asset_id(d); // verify fee is a legit asset
const auto& bbi = d.get_index_type<blinded_balance_index>();
const auto& cidx = bbi.indices().get<by_commitment>();
for( const auto& in : o.inputs )
{
auto itr = cidx.find( in.commitment );
FC_ASSERT( itr != cidx.end() );
FC_ASSERT( itr->asset_id == o.fee.asset_id );
FC_ASSERT( itr->owner == in.owner );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o )
{ try {
db().adjust_balance( o.fee_payer(), o.fee );
db().adjust_balance( o.to, o.amount );
const auto& bbi = db().get_index_type<blinded_balance_index>();
const auto& cidx = bbi.indices().get<by_commitment>();
for( const auto& in : o.inputs )
{
auto itr = cidx.find( in.commitment );
FC_ASSERT( itr != cidx.end() );
db().remove( *itr );
}
const auto& add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset
db().modify( add, [&]( asset_dynamic_data_object& obj ){
obj.confidential_supply -= o.amount.amount + o.fee.amount;
FC_ASSERT( obj.confidential_supply >= 0 );
});
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void transfer_from_blind_evaluator::pay_fee()
{
if( db().head_block_time() >= HARDFORK_563_TIME )
pay_fba_fee( fba_accumulator_id_transfer_from_blind );
else
generic_evaluator::pay_fee();
}
void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o )
{ try {
const auto& d = db();
o.fee.asset_id(db()); // verify fee is a legit asset
const auto& bbi = db().get_index_type<blinded_balance_index>();
const auto& cidx = bbi.indices().get<by_commitment>();
for( const auto& out : o.outputs )
{
for( const auto& a : out.owner.account_auths )
a.first(d); // verify all accounts exist and are valid
}
for( const auto& in : o.inputs )
{
auto itr = cidx.find( in.commitment );
GRAPHENE_ASSERT( itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment",in.commitment) );
FC_ASSERT( itr->asset_id == o.fee.asset_id );
FC_ASSERT( itr->owner == in.owner );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o )
{ try {
db().adjust_balance( o.fee_payer(), o.fee ); // deposit the fee to the temp account
const auto& bbi = db().get_index_type<blinded_balance_index>();
const auto& cidx = bbi.indices().get<by_commitment>();
for( const auto& in : o.inputs )
{
auto itr = cidx.find( in.commitment );
GRAPHENE_ASSERT( itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment",in.commitment) );
db().remove( *itr );
}
for( const auto& out : o.outputs )
{
db().create<blinded_balance_object>( [&]( blinded_balance_object& obj ){
obj.asset_id = o.fee.asset_id;
obj.owner = out.owner;
obj.commitment = out.commitment;
});
}
const auto& add = o.fee.asset_id(db()).dynamic_asset_data_id(db());
db().modify( add, [&]( asset_dynamic_data_object& obj ){
obj.confidential_supply -= o.fee.amount;
FC_ASSERT( obj.confidential_supply >= 0 );
});
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void blind_transfer_evaluator::pay_fee()
{
if( db().head_block_time() >= HARDFORK_563_TIME )
pay_fba_fee( fba_accumulator_id_blind_transfer );
else
generic_evaluator::pay_fee();
}
} } // graphene::chain

View file

@ -203,27 +203,10 @@ struct get_impacted_account_visitor
_impacted.insert( op.issuer );
}
void operator()( const transfer_to_blind_operation& op )
{
_impacted.insert( op.from );
for( const auto& out : op.outputs )
add_authority_accounts( _impacted, out.owner );
}
void operator()( const blind_transfer_operation& op )
{
for( const auto& in : op.inputs )
add_authority_accounts( _impacted, in.owner );
for( const auto& out : op.outputs )
add_authority_accounts( _impacted, out.owner );
}
void operator()( const transfer_from_blind_operation& op )
{
_impacted.insert( op.to );
for( const auto& in : op.inputs )
add_authority_accounts( _impacted, in.owner );
}
//! We don't use this operations
void operator()( const transfer_to_blind_operation& op ){}
void operator()( const blind_transfer_operation& op ){}
void operator()( const transfer_from_blind_operation& op ){}
void operator()( const asset_settle_cancel_operation& op )
{

View file

@ -182,9 +182,6 @@ namespace graphene { namespace chain {
GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( override_transfer );
GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( not_permitted, override_transfer, 1, "not permitted" )
GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( blind_transfer );
GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( unknown_commitment, blind_transfer, 1, "Attempting to claim an unknown prior commitment" );
/*
FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" )
FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" )

View file

@ -111,12 +111,12 @@ struct stealth_confirmation
/**
* Packs *this then encodes as base58 encoded string.
*/
operator string()const;
//operator string()const;
/**
* Unpacks from a base58 string
*/
stealth_confirmation( const std::string& base58 );
stealth_confirmation(){}
//stealth_confirmation( const std::string& base58 );
//stealth_confirmation(){}
public_key_type one_time_key;
optional<public_key_type> to;
@ -152,16 +152,17 @@ struct transfer_to_blind_operation : public base_operation
uint32_t price_per_output = 5*GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
asset amount;
account_id_type from;
blind_factor_type blinding_factor;
vector<blind_output> outputs;
account_id_type fee_payer()const { return from; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& )const;
account_id_type fee_payer()const { return account_id_type{}; }
//account_id_type fee_payer()const { return from; }
//void validate()const;
//share_type calculate_fee(const fee_parameters_type& )const;
};
/**
@ -180,14 +181,15 @@ struct transfer_from_blind_operation : public base_operation
blind_factor_type blinding_factor;
vector<blind_input> inputs;
account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
void validate()const;
account_id_type fee_payer()const { return account_id_type{}; }
void get_required_authorities( vector<authority>& a )const
{
for( const auto& in : inputs )
a.push_back( in.owner );
}
//account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; }
//void validate()const;
//void get_required_authorities( vector<authority>& a )const
//{
// for( const auto& in : inputs )
// a.push_back( in.owner );
//}
};
/**
@ -243,17 +245,18 @@ struct blind_transfer_operation : public base_operation
asset fee;
vector<blind_input> inputs;
vector<blind_output> outputs;
/** graphene TEMP account */
account_id_type fee_payer()const;
void validate()const;
share_type calculate_fee( const fee_parameters_type& k )const;
void get_required_authorities( vector<authority>& a )const
{
for( const auto& in : inputs )
a.push_back( in.owner );
}
account_id_type fee_payer()const { return account_id_type{}; }
/** graphene TEMP account */
//account_id_type fee_payer()const;
//void validate()const;
//share_type calculate_fee( const fee_parameters_type& k )const;
//void get_required_authorities( vector<authority>& a )const
//{
// for( const auto& in : inputs )
// a.push_back( in.owner );
//}
};
///@} endgroup stealth

View file

@ -106,9 +106,9 @@ namespace graphene { namespace chain {
assert_operation,
balance_claim_operation,
override_transfer_operation,
transfer_to_blind_operation,
blind_transfer_operation,
transfer_from_blind_operation,
transfer_to_blind_operation, //! We don't use this operation
blind_transfer_operation, //! We don't use this operation
transfer_from_blind_operation, //! We don't use this operation
asset_settle_cancel_operation, // VIRTUAL
asset_claim_fees_operation,
fba_distribute_operation, // VIRTUAL

View file

@ -22,12 +22,10 @@
* THE SOFTWARE.
*/
#include <graphene/chain/protocol/confidential.hpp>
#include <graphene/chain/confidential_evaluator.hpp>
#include <graphene/chain/database.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/io/raw.hpp>
/*
namespace graphene { namespace chain {
void transfer_to_blind_operation::validate()const
@ -47,19 +45,6 @@ void transfer_to_blind_operation::validate()const
FC_ASSERT( !outputs[i].owner.is_impossible() );
}
FC_ASSERT( out.size(), "there must be at least one output" );
auto public_c = fc::ecc::blind(blinding_factor,net_public);
FC_ASSERT( fc::ecc::verify_sum( {public_c}, out, 0 ), "", ("net_public",net_public) );
if( outputs.size() > 1 )
{
for( auto out : outputs )
{
auto info = fc::ecc::range_get_info( out.range_proof );
FC_ASSERT( info.max_value <= GRAPHENE_MAX_SHARE_SUPPLY );
}
}
}
share_type transfer_to_blind_operation::calculate_fee( const fee_parameters_type& k )const
@ -79,31 +64,15 @@ void transfer_from_blind_operation::validate()const
vector<commitment_type> in(inputs.size());
vector<commitment_type> out;
int64_t net_public = fee.amount.value + amount.amount.value;
out.push_back( fc::ecc::blind( blinding_factor, net_public ) );
for( uint32_t i = 0; i < in.size(); ++i )
{
in[i] = inputs[i].commitment;
/// by requiring all inputs to be sorted we also prevent duplicate commitments on the input
if( i > 0 ) FC_ASSERT( in[i-1] < in[i], "all inputs must be sorted by commitment id" );
}
FC_ASSERT( in.size(), "there must be at least one input" );
FC_ASSERT( fc::ecc::verify_sum( in, out, 0 ) );
}
/**
* If fee_payer = temp_account_id, then the fee is paid by the surplus balance of inputs-outputs and
* 100% of the fee goes to the network.
*/
account_id_type blind_transfer_operation::fee_payer()const
{
return GRAPHENE_TEMP_ACCOUNT;
}
/**
* This method can be computationally intensive because it verifies that input commitments - output commitments add up to 0
*/
void blind_transfer_operation::validate()const
{ try {
vector<commitment_type> in(inputs.size());
@ -122,17 +91,6 @@ void blind_transfer_operation::validate()const
FC_ASSERT( !outputs[i].owner.is_impossible() );
}
FC_ASSERT( in.size(), "there must be at least one input" );
FC_ASSERT( fc::ecc::verify_sum( in, out, net_public ), "", ("net_public", net_public) );
if( outputs.size() > 1 )
{
for( auto out : outputs )
{
auto info = fc::ecc::range_get_info( out.range_proof );
FC_ASSERT( info.max_value <= GRAPHENE_MAX_SHARE_SUPPLY );
}
}
FC_ASSERT( fc::ecc::verify_sum( in, out, net_public ), "", ("net_public", net_public) );
} FC_CAPTURE_AND_RETHROW( (*this) ) }
share_type blind_transfer_operation::calculate_fee( const fee_parameters_type& k )const
@ -140,16 +98,12 @@ share_type blind_transfer_operation::calculate_fee( const fee_parameters_type& k
return k.fee + outputs.size() * k.price_per_output;
}
/**
* Packs *this then encodes as base58 encoded string.
*/
stealth_confirmation::operator string()const
{
return fc::to_base58( fc::raw::pack( *this ) );
}
/**
* Unpacks from a base58 string
*/
stealth_confirmation::stealth_confirmation( const std::string& base58 )
{
*this = fc::raw::unpack<stealth_confirmation>( fc::from_base58( base58 ) );
@ -157,6 +111,8 @@ stealth_confirmation::stealth_confirmation( const std::string& base58 )
} } // graphene::chain
*/
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_to_blind_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_from_blind_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::blind_transfer_operation::fee_parameters_type )

@ -1 +1 @@
Subproject commit e7369949bea26f3201d8442ba78286a88df74762
Subproject commit 156b0c4e41c9215eadb2af8009b05e0f38c16dda

View file

@ -1,4 +1,5 @@
#include <graphene/peerplays_sidechain/bitcoin/serialize.hpp>
#include <secp256k1.h>
#include <fc/io/raw.hpp>
@ -6,8 +7,8 @@
namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
const secp256k1_context_t *btc_context() {
static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
const secp256k1_context *btc_context() {
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
return ctx;
}
@ -31,20 +32,14 @@ fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &script
return fc::sha256::hash(fc::sha256::hash(vec.data(), vec.size()));
}
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context_t *context_sign) {
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context *context_sign) {
bytes sig;
sig.resize(72);
int sig_len = sig.size();
FC_ASSERT(secp256k1_ecdsa_sign(
context_sign,
reinterpret_cast<unsigned char *>(hash.data()),
reinterpret_cast<unsigned char *>(sig.data()),
&sig_len,
reinterpret_cast<const unsigned char *>(privkey.data()),
secp256k1_nonce_function_rfc6979,
nullptr)); // TODO: replace assert with exception
secp256k1_ecdsa_signature sign;
FC_ASSERT(secp256k1_ecdsa_sign(context_sign, &sign, (const unsigned char *)hash.data(), (const unsigned char *)privkey.data(), secp256k1_nonce_function_rfc6979, nullptr));
FC_ASSERT(secp256k1_ecdsa_signature_serialize_der(context_sign, (unsigned char *)sig.data(), (size_t *)&sig_len, &sign));
sig.resize(sig_len);
return sig;
@ -52,7 +47,7 @@ std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, con
std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t> &amounts, const bytes &privkey,
const secp256k1_context_t *context_sign, int hash_type) {
const secp256k1_context *context_sign, int hash_type) {
FC_ASSERT(tx.vin.size() == redeem_scripts.size() && tx.vin.size() == amounts.size());
FC_ASSERT(!privkey.empty());
@ -77,17 +72,23 @@ void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vecto
}
}
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context_t *context) {
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context *context) {
std::vector<unsigned char> sig_temp(sig.begin(), sig.end());
std::vector<unsigned char> pubkey_temp(pubkey.begin(), pubkey.end());
std::vector<unsigned char> msg_temp(msg.begin(), msg.end());
int result = secp256k1_ecdsa_verify(context, msg_temp.data(), sig_temp.data(), sig_temp.size(), pubkey_temp.data(), pubkey_temp.size());
secp256k1_pubkey pub_key;
FC_ASSERT(secp256k1_ec_pubkey_parse(context, &pub_key, (const unsigned char *)pubkey_temp.data(), pubkey_temp.size()));
secp256k1_ecdsa_signature sign;
FC_ASSERT(secp256k1_ecdsa_signature_parse_der(context, &sign, (const unsigned char *)sig_temp.data(), sig_temp.size()));
int result = secp256k1_ecdsa_verify(context, &sign, (const unsigned char *)msg_temp.data(), &pub_key);
return result == 1;
}
std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t> &amounts, const secp256k1_context_t *context) {
const std::vector<uint64_t> &amounts, const secp256k1_context *context) {
FC_ASSERT(redeem_scripts.size() == amounts.size());
using data = std::pair<size_t, bytes>;

View file

@ -8,23 +8,23 @@ namespace graphene { namespace peerplays_sidechain { namespace bitcoin {
class bitcoin_transaction;
const secp256k1_context_t *btc_context();
const secp256k1_context *btc_context();
fc::sha256 get_signature_hash(const bitcoin_transaction &tx, const bytes &scriptPubKey, int64_t amount,
size_t in_index, int hash_type, bool is_witness);
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context_t *context_sign = nullptr);
std::vector<char> privkey_sign(const bytes &privkey, const fc::sha256 &hash, const secp256k1_context *context_sign = nullptr);
std::vector<bytes> sign_witness_transaction_part(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t> &amounts, const bytes &privkey,
const secp256k1_context_t *context_sign = nullptr, int hash_type = 1);
const secp256k1_context *context_sign = nullptr, int hash_type = 1);
void sign_witness_transaction_finalize(bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts, bool use_mulisig_workaround = true);
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context_t *context);
bool verify_sig(const bytes &sig, const bytes &pubkey, const bytes &msg, const secp256k1_context *context);
std::vector<std::vector<bytes>> sort_sigs(const bitcoin_transaction &tx, const std::vector<bytes> &redeem_scripts,
const std::vector<uint64_t> &amounts, const secp256k1_context_t *context);
const std::vector<uint64_t> &amounts, const secp256k1_context *context);
void add_signatures_to_transaction_multisig(bitcoin_transaction &tx, std::vector<std::vector<bytes>> &signature_set);

View file

@ -68,80 +68,12 @@ enum authority_type
active
};
/**
* Contains the confirmation receipt the sender must give the receiver and
* the meta data about the receipt that helps the sender identify which receipt is
* for the receiver and which is for the change address.
*/
struct blind_confirmation
{
struct output
{
string label;
public_key_type pub_key;
stealth_confirmation::memo_data decrypted_memo;
stealth_confirmation confirmation;
authority auth;
string confirmation_receipt;
};
signed_transaction trx;
vector<output> outputs;
};
struct blind_balance
{
asset amount;
public_key_type from; ///< the account this balance came from
public_key_type to; ///< the account this balance is logically associated with
public_key_type one_time_key; ///< used to derive the authority key and blinding factor
fc::sha256 blinding_factor;
fc::ecc::commitment_type commitment;
bool used = false;
};
struct blind_receipt
{
std::pair<public_key_type,fc::time_point> from_date()const { return std::make_pair(from_key,date); }
std::pair<public_key_type,fc::time_point> to_date()const { return std::make_pair(to_key,date); }
std::tuple<public_key_type,asset_id_type,bool> to_asset_used()const { return std::make_tuple(to_key,amount.asset_id,used); }
const commitment_type& commitment()const { return data.commitment; }
fc::time_point date;
public_key_type from_key;
string from_label;
public_key_type to_key;
string to_label;
asset amount;
string memo;
authority control_authority;
stealth_confirmation::memo_data data;
bool used = false;
stealth_confirmation conf;
};
struct by_from;
struct by_to;
struct by_to_asset_used;
struct by_commitment;
typedef multi_index_container< blind_receipt,
indexed_by<
ordered_unique< tag<by_commitment>, const_mem_fun< blind_receipt, const commitment_type&, &blind_receipt::commitment > >,
ordered_unique< tag<by_to>, const_mem_fun< blind_receipt, std::pair<public_key_type,fc::time_point>, &blind_receipt::to_date > >,
ordered_non_unique< tag<by_to_asset_used>, const_mem_fun< blind_receipt, std::tuple<public_key_type,asset_id_type,bool>, &blind_receipt::to_asset_used > >,
ordered_unique< tag<by_from>, const_mem_fun< blind_receipt, std::pair<public_key_type,fc::time_point>, &blind_receipt::from_date > >
>
> blind_receipt_index_type;
struct key_label
{
string label;
public_key_type key;
};
struct by_label;
struct by_key;
typedef multi_index_container<
@ -195,7 +127,6 @@ struct wallet_data
map<string, string> pending_witness_registrations;
key_label_index_type labeled_keys;
blind_receipt_index_type blind_receipts;
std::map<rock_paper_scissors_throw_commit, rock_paper_scissors_throw_reveal> committed_game_moves;
@ -872,74 +803,10 @@ class wallet_api
bool set_key_label( public_key_type, string label );
string get_key_label( public_key_type )const;
/**
* Generates a new blind account for the given brain key and assigns it the given label.
*/
public_key_type create_blind_account( string label, string brain_key );
/**
* @return the total balance of all blinded commitments that can be claimed by the
* given account key or label
*/
vector<asset> get_blind_balances( string key_or_label );
/** @return all blind accounts */
map<string,public_key_type> get_blind_accounts()const;
/** @return all blind accounts for which this wallet has the private key */
map<string,public_key_type> get_my_blind_accounts()const;
/** @return the public key associated with the given label */
public_key_type get_public_key( string label )const;
///@}
/**
* @return all blind receipts to/form a particular account
*/
vector<blind_receipt> blind_history( string key_or_account );
/**
* Given a confirmation receipt, this method will parse it for a blinded balance and confirm
* that it exists in the blockchain. If it exists then it will report the amount received and
* who sent it.
*
* @param confirmation_receipt - a base58 encoded stealth confirmation
* @param opt_from - if not empty and the sender is a unknown public key, then the unknown public key will be given the label opt_from
* @param opt_memo - optional memo
*/
blind_receipt receive_blind_transfer( string confirmation_receipt, string opt_from, string opt_memo );
/**
* Transfers a public balance from from_account_id_or_name to one or more blinded balances using a
* stealth transfer.
*
* @param from_account_id_or_name account id or name
* @param asset_symbol asset symbol
* @param to_amounts map from key or label to amount
* @param broadcast true to broadcast the transaction on the network
* @returns blind confirmation structure
*/
blind_confirmation transfer_to_blind( string from_account_id_or_name,
string asset_symbol,
vector<pair<string, string>> to_amounts,
bool broadcast = false );
/**
* Transfers funds from a set of blinded balances to a public account balance.
*/
blind_confirmation transfer_from_blind(
string from_blind_account_key_or_label,
string to_account_id_or_name,
string amount,
string asset_symbol,
bool broadcast = false );
/**
* Used to transfer from one set of blinded balances to another
*/
blind_confirmation blind_transfer( string from_key_or_label,
string to_key_or_label,
string amount,
string symbol,
bool broadcast = false );
/** Place a limit order attempting to sell one asset for another.
*
* Buying and selling are the same operation on Graphene; if you want to buy BTS
@ -2547,16 +2414,6 @@ class wallet_api
void network_add_nodes( const vector<string>& nodes );
vector< variant > network_get_connected_peers();
/**
* Used to transfer from one set of blinded balances to another
*/
blind_confirmation blind_transfer_help( string from_key_or_label,
string to_key_or_label,
string amount,
string symbol,
bool broadcast = false,
bool to_temp = false );
std::map<string,std::function<string(fc::variant,const fc::variants&)>> get_result_formatters() const;
/**
@ -2607,9 +2464,6 @@ class wallet_api
extern template class fc::api<graphene::wallet::wallet_api>;
FC_REFLECT( graphene::wallet::key_label, (label)(key) )
FC_REFLECT( graphene::wallet::blind_balance, (amount)(from)(to)(one_time_key)(blinding_factor)(commitment)(used) )
FC_REFLECT( graphene::wallet::blind_confirmation::output, (label)(pub_key)(decrypted_memo)(confirmation)(auth)(confirmation_receipt) )
FC_REFLECT( graphene::wallet::blind_confirmation, (trx)(outputs) )
FC_REFLECT( graphene::wallet::plain_keys, (keys)(checksum) )
@ -2620,7 +2474,6 @@ FC_REFLECT( graphene::wallet::wallet_data,
(extra_keys)
(pending_account_registrations)(pending_witness_registrations)
(labeled_keys)
(blind_receipts)
(committed_game_moves)
(ws_server)
(ws_user)
@ -2639,9 +2492,6 @@ FC_REFLECT( graphene::wallet::exported_account_keys, (account_name)(encrypted_pr
FC_REFLECT( graphene::wallet::exported_keys, (password_checksum)(account_keys) )
FC_REFLECT( graphene::wallet::blind_receipt,
(date)(from_key)(from_label)(to_key)(to_label)(amount)(memo)(control_authority)(data)(used)(conf) )
FC_REFLECT( graphene::wallet::approval_delta,
(active_approvals_to_add)
(active_approvals_to_remove)
@ -2814,15 +2664,6 @@ FC_API( graphene::wallet::wallet_api,
(set_key_label)
(get_key_label)
(get_public_key)
(get_blind_accounts)
(get_my_blind_accounts)
(get_blind_balances)
(create_blind_account)
(transfer_to_blind)
(transfer_from_blind)
(blind_transfer)
(blind_history)
(receive_blind_transfer)
(list_sports)
(list_event_groups)
(list_betting_market_groups)

View file

@ -134,8 +134,6 @@ 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;
@ -3472,70 +3470,6 @@ 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 );
@ -4396,26 +4330,6 @@ 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)
@ -6186,495 +6100,6 @@ 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 //

View file

@ -13,8 +13,8 @@ using namespace fc::ecc;
BOOST_AUTO_TEST_SUITE(bitcoin_sign_tests)
const secp256k1_context_t *btc_context() {
static secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
const secp256k1_context *btc_context() {
static secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
return ctx;
}

View file

@ -1,134 +0,0 @@
/*
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <boost/test/unit_test.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/protocol/protocol.hpp>
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/committee_member_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/db/simple_index.hpp>
#include <fc/crypto/digest.hpp>
#include "../common/database_fixture.hpp"
using namespace graphene::chain;
BOOST_FIXTURE_TEST_SUITE( confidential_tests, database_fixture )
BOOST_AUTO_TEST_CASE( confidential_test )
{ try {
ACTORS( (dan)(nathan) )
const asset_object& core = asset_id_type()(db);
transfer(account_id_type()(db), dan, core.amount(1000000));
transfer_to_blind_operation to_blind;
to_blind.amount = core.amount(1000);
to_blind.from = dan.id;
auto owner1_key = fc::ecc::private_key::generate();
auto owner1_pub = owner1_key.get_public_key();
auto owner2_key = fc::ecc::private_key::generate();
auto owner2_pub = owner2_key.get_public_key();
blind_output out1, out2;
out1.owner = authority( 1, public_key_type(owner1_pub), 1 );
out2.owner = authority( 1, public_key_type(owner2_pub), 1 );
auto InB1 = fc::sha256::hash("InB1");
auto InB2 = fc::sha256::hash("InB2");
auto nonce1 = fc::sha256::hash("nonce");
auto nonce2 = fc::sha256::hash("nonce2");
out1.commitment = fc::ecc::blind(InB1,250);
out1.range_proof = fc::ecc::range_proof_sign( 0, out1.commitment, InB1, nonce1, 0, 0, 250 );
out2.commitment = fc::ecc::blind(InB2,750);
out2.range_proof = fc::ecc::range_proof_sign( 0, out2.commitment, InB1, nonce2, 0, 0, 750 );
to_blind.blinding_factor = fc::ecc::blind_sum( {InB1,InB2}, 2 );
to_blind.outputs = {out2,out1};
trx.operations = {to_blind};
sign( trx, dan_private_key );
db.push_transaction(trx);
trx.clear_signatures();
BOOST_TEST_MESSAGE( "Transfering from blind to blind with change address" );
auto Out3B = fc::sha256::hash("Out3B");
auto Out4B = fc::ecc::blind_sum( {InB2,Out3B}, 1 ); // add InB2 - Out3b
blind_output out3, out4;
out3.commitment = fc::ecc::blind(Out3B,300);
out3.range_proof = fc::ecc::range_proof_sign( 0, out3.commitment, InB1, nonce1, 0, 0, 300 );
out4.commitment = fc::ecc::blind(Out4B,750-300-10);
out4.range_proof = fc::ecc::range_proof_sign( 0, out3.commitment, InB1, nonce1, 0, 0, 750-300-10 );
blind_transfer_operation blind_tr;
blind_tr.fee = core.amount(10);
blind_tr.inputs.push_back( {out2.commitment, out2.owner} );
blind_tr.outputs = {out3,out4};
blind_tr.validate();
trx.operations = {blind_tr};
sign( trx, owner2_key );
db.push_transaction(trx);
BOOST_TEST_MESSAGE( "Attempting to double spend the same commitments" );
blind_tr.fee = core.amount(11);
Out4B = fc::ecc::blind_sum( {InB2,Out3B}, 1 ); // add InB2 - Out3b
out4.commitment = fc::ecc::blind(Out4B,750-300-11);
auto out4_amount = 750-300-10;
out4.range_proof = fc::ecc::range_proof_sign( 0, out3.commitment, InB1, nonce1, 0, 0, 750-300-11 );
blind_tr.outputs = {out4,out3};
trx.operations = {blind_tr};
BOOST_REQUIRE_THROW( db.push_transaction(trx, ~0), graphene::chain::blind_transfer_unknown_commitment );
BOOST_TEST_MESSAGE( "Transfering from blind to nathan public" );
out4.commitment = fc::ecc::blind(Out4B,750-300-10);
transfer_from_blind_operation from_blind;
from_blind.fee = core.amount(10);
from_blind.to = nathan.id;
from_blind.amount = core.amount( out4_amount - 10 );
from_blind.blinding_factor = Out4B;
from_blind.inputs.push_back( {out4.commitment, out4.owner} );
trx.operations = {from_blind};
trx.clear_signatures();
db.push_transaction(trx);
BOOST_REQUIRE_EQUAL( get_balance( nathan, core ), 750-300-10-10 );
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_SUITE_END()

View file

@ -741,212 +741,6 @@ BOOST_AUTO_TEST_CASE( account_create_fee_scaling )
// FC_LOG_AND_RETHROW()
// }
BOOST_AUTO_TEST_CASE( stealth_fba_test )
{
try
{
ACTORS( (alice)(bob)(chloe)(dan)(izzy)(philbin)(tom) );
upgrade_to_lifetime_member(philbin_id);
generate_blocks( HARDFORK_538_TIME );
generate_blocks( HARDFORK_555_TIME );
generate_blocks( HARDFORK_563_TIME );
generate_blocks( HARDFORK_572_TIME );
generate_blocks( HARDFORK_599_TIME );
// Philbin (registrar who registers Rex)
// Izzy (initial issuer of stealth asset, will later transfer to Tom)
// Alice, Bob, Chloe, Dan (ABCD)
// Rex (recycler -- buyback account for stealth asset)
// Tom (owner of stealth asset who will be set as top_n authority)
// Izzy creates STEALTH
asset_id_type stealth_id = create_user_issued_asset( "STEALTH", izzy_id(db),
disable_confidential | transfer_restricted | override_authority | white_list | charge_market_fee ).id;
/*
// this is disabled because it doesn't work, our modify() is probably being overwritten by undo
//
// Init blockchain with stealth ID's
// On a real chain, this would be done with #define GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET
// causing the designated_asset fields of these objects to be set at genesis, but for
// this test we modify the db directly.
//
auto set_fba_asset = [&]( uint64_t fba_acc_id, asset_id_type asset_id )
{
db.modify( fba_accumulator_id_type(fba_acc_id)(db), [&]( fba_accumulator_object& fba )
{
fba.designated_asset = asset_id;
} );
};
set_fba_asset( fba_accumulator_id_transfer_to_blind , stealth_id );
set_fba_asset( fba_accumulator_id_blind_transfer , stealth_id );
set_fba_asset( fba_accumulator_id_transfer_from_blind, stealth_id );
*/
// Izzy kills some permission bits (this somehow happened to the real STEALTH in production)
{
asset_update_operation update_op;
update_op.issuer = izzy_id;
update_op.asset_to_update = stealth_id;
asset_options new_options;
new_options = stealth_id(db).options;
new_options.issuer_permissions = charge_market_fee;
new_options.flags = disable_confidential | transfer_restricted | override_authority | white_list | charge_market_fee;
// after fixing #579 you should be able to delete the following line
new_options.core_exchange_rate = price( asset( 1, stealth_id ), asset( 1, asset_id_type() ) );
update_op.new_options = new_options;
signed_transaction tx;
tx.operations.push_back( update_op );
set_expiration( db, tx );
sign( tx, izzy_private_key );
PUSH_TX( db, tx );
}
// Izzy transfers issuer duty to Tom
{
asset_update_operation update_op;
update_op.issuer = izzy_id;
update_op.asset_to_update = stealth_id;
update_op.new_issuer = tom_id;
// new_options should be optional, but isn't...the following line should be unnecessary #580
update_op.new_options = stealth_id(db).options;
signed_transaction tx;
tx.operations.push_back( update_op );
set_expiration( db, tx );
sign( tx, izzy_private_key );
PUSH_TX( db, tx );
}
// Tom re-enables the permission bits to clear the flags, then clears them again
// Allowed by #572 when current_supply == 0
{
asset_update_operation update_op;
update_op.issuer = tom_id;
update_op.asset_to_update = stealth_id;
asset_options new_options;
new_options = stealth_id(db).options;
new_options.issuer_permissions = new_options.flags | charge_market_fee;
update_op.new_options = new_options;
signed_transaction tx;
// enable perms is one op
tx.operations.push_back( update_op );
new_options.issuer_permissions = charge_market_fee;
new_options.flags = charge_market_fee;
update_op.new_options = new_options;
// reset wrongly set flags and reset permissions can be done in a single op
tx.operations.push_back( update_op );
set_expiration( db, tx );
sign( tx, tom_private_key );
PUSH_TX( db, tx );
}
// Philbin registers Rex who will be the asset's buyback, including sig from the new issuer (Tom)
account_id_type rex_id;
{
buyback_account_options bbo;
bbo.asset_to_buy = stealth_id;
bbo.asset_to_buy_issuer = tom_id;
bbo.markets.emplace( asset_id_type() );
account_create_operation create_op = make_account( "rex" );
create_op.registrar = philbin_id;
create_op.extensions.value.buyback_options = bbo;
create_op.owner = authority::null_authority();
create_op.active = authority::null_authority();
signed_transaction tx;
tx.operations.push_back( create_op );
set_expiration( db, tx );
sign( tx, philbin_private_key );
sign( tx, tom_private_key );
processed_transaction ptx = PUSH_TX( db, tx );
rex_id = ptx.operation_results.back().get< object_id_type >();
}
// Tom issues some asset to Alice and Bob
set_expiration( db, trx ); // #11
issue_uia( alice_id, asset( 1000, stealth_id ) );
issue_uia( bob_id, asset( 1000, stealth_id ) );
// Tom sets his authority to the top_n of the asset
{
top_holders_special_authority top2;
top2.num_top_holders = 2;
top2.asset = stealth_id;
account_update_operation op;
op.account = tom_id;
op.extensions.value.active_special_authority = top2;
op.extensions.value.owner_special_authority = top2;
signed_transaction tx;
tx.operations.push_back( op );
set_expiration( db, tx );
sign( tx, tom_private_key );
PUSH_TX( db, tx );
}
// Wait until the next maintenance interval for top_n to take effect
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
// Do a blind op to add some fees to the pool.
fund( chloe_id(db), asset( 100000, asset_id_type() ) );
auto create_transfer_to_blind = [&]( account_id_type account, asset amount, const std::string& key ) -> transfer_to_blind_operation
{
fc::ecc::private_key blind_key = fc::ecc::private_key::regenerate( fc::sha256::hash( key+"-privkey" ) );
public_key_type blind_pub = blind_key.get_public_key();
fc::sha256 secret = fc::sha256::hash( key+"-secret" );
fc::sha256 nonce = fc::sha256::hash( key+"-nonce" );
transfer_to_blind_operation op;
blind_output blind_out;
blind_out.owner = authority( 1, blind_pub, 1 );
blind_out.commitment = fc::ecc::blind( secret, amount.amount.value );
blind_out.range_proof = fc::ecc::range_proof_sign( 0, blind_out.commitment, secret, nonce, 0, 0, amount.amount.value );
op.amount = amount;
op.from = account;
op.blinding_factor = fc::ecc::blind_sum( {secret}, 1 );
op.outputs = {blind_out};
return op;
};
{
transfer_to_blind_operation op = create_transfer_to_blind( chloe_id, asset( 5000, asset_id_type() ), "chloe-key" );
op.fee = asset( 1000, asset_id_type() );
signed_transaction tx;
tx.operations.push_back( op );
set_expiration( db, tx );
sign( tx, chloe_private_key );
PUSH_TX( db, tx );
}
// wait until next maint interval
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
idump( ( get_operation_history( chloe_id ) ) );
idump( ( get_operation_history( rex_id ) ) );
idump( ( get_operation_history( tom_id ) ) );
}
catch( const fc::exception& e )
{
elog( "caught exception ${e}", ("e", e.to_detail_string()) );
throw;
}
}
// added test from bitshares for issues:
// https://github.com/bitshares/bitshares-core/issues/429
// https://github.com/bitshares/bitshares-core/issues/433