Merge branch 'master' of https://github.com/cryptonomex/graphene
This commit is contained in:
commit
6418f819fd
11 changed files with 348 additions and 187 deletions
|
|
@ -97,17 +97,11 @@ void account_statistics_object::process_fees(const account_object& a, database&
|
|||
assert( referrer_cut + registrar_cut + accumulated + reserveed + lifetime_cut == core_fee_total );
|
||||
};
|
||||
|
||||
share_type vesting_fee_subtotal(pending_fees);
|
||||
share_type vested_fee_subtotal(pending_vested_fees);
|
||||
share_type vesting_cashback, vested_cashback;
|
||||
pay_out_fees(a, pending_fees, true);
|
||||
pay_out_fees(a, pending_vested_fees, false);
|
||||
|
||||
pay_out_fees(a, vesting_fee_subtotal, true);
|
||||
d.deposit_cashback(a, vesting_cashback, true);
|
||||
pay_out_fees(a, vested_fee_subtotal, false);
|
||||
d.deposit_cashback(a, vested_cashback, false);
|
||||
|
||||
d.modify(*this, [vested_fee_subtotal, vesting_fee_subtotal](account_statistics_object& s) {
|
||||
s.lifetime_fees_paid += vested_fee_subtotal + vesting_fee_subtotal;
|
||||
d.modify(*this, [&](account_statistics_object& s) {
|
||||
s.lifetime_fees_paid += pending_fees + pending_vested_fees;
|
||||
s.pending_fees = 0;
|
||||
s.pending_vested_fees = 0;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,62 +30,11 @@
|
|||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* Valid symbols can contain [A-Z0-9], and '.'
|
||||
* They must start with [A, Z]
|
||||
* They must end with [A, Z]
|
||||
* They can contain a maximum of one '.'
|
||||
*/
|
||||
bool is_valid_symbol_old( const string& symbol )
|
||||
{
|
||||
if( symbol.size() < GRAPHENE_MIN_ASSET_SYMBOL_LENGTH )
|
||||
return false;
|
||||
|
||||
if( symbol.size() > GRAPHENE_MAX_ASSET_SYMBOL_LENGTH )
|
||||
return false;
|
||||
|
||||
if( !isalpha( symbol.front() ) )
|
||||
return false;
|
||||
|
||||
if( !isalpha( symbol.back() ) )
|
||||
return false;
|
||||
|
||||
bool dot_already_present = false;
|
||||
for( const auto c : symbol )
|
||||
{
|
||||
if( (isalpha( c ) || isdigit(c)) && isupper( c ) )
|
||||
continue;
|
||||
|
||||
if( c == '.' )
|
||||
{
|
||||
if( dot_already_present )
|
||||
return false;
|
||||
|
||||
dot_already_present = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void_result asset_create_evaluator::do_evaluate( const asset_create_operation& op )
|
||||
{ try {
|
||||
|
||||
database& d = db();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma message ("WARNING:HARDFORK remove this check after HARDFORK_359_TIME and rename is_valid_symbol_old -> is_valid_symbol")
|
||||
#else
|
||||
# warning HARDFORK remove this check after HARDFORK_359_TIME and rename is_valid_symbol_old -> is_valid_symbol
|
||||
#endif
|
||||
if( d.head_block_time() <= HARDFORK_359_TIME )
|
||||
{
|
||||
FC_ASSERT( is_valid_symbol_old( op.symbol ) );
|
||||
}
|
||||
|
||||
const auto& chain_parameters = d.get_global_properties().parameters;
|
||||
FC_ASSERT( op.common_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
|
||||
FC_ASSERT( op.common_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
|
||||
|
|
@ -525,100 +474,8 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_
|
|||
const asset_bitasset_data_object& bitasset = base.bitasset_data(d);
|
||||
FC_ASSERT( !bitasset.has_settlement(), "No further feeds may be published after a settlement event" );
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma message ("WARNING: Remove this check when starting a new network")
|
||||
#else
|
||||
# warning Remove this check when starting a new network
|
||||
#endif
|
||||
if( d.head_block_time() <= HARDFORK_357_TIME )
|
||||
{
|
||||
FC_ASSERT(o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset);
|
||||
FC_ASSERT( o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset );
|
||||
|
||||
try
|
||||
{
|
||||
// these two changes should go in price_feed::validate() when creating new network
|
||||
if( !o.feed.core_exchange_rate.is_null() )
|
||||
{
|
||||
o.feed.core_exchange_rate.validate();
|
||||
}
|
||||
if( (!o.feed.settlement_price.is_null()) && (!o.feed.core_exchange_rate.is_null()) )
|
||||
{
|
||||
if( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id )
|
||||
{
|
||||
// uncrossed feed, this is the form we expect
|
||||
FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id );
|
||||
FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.quote.asset_id );
|
||||
}
|
||||
else
|
||||
{
|
||||
// crossed feed, your feed script needs to be fixed
|
||||
FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.quote.asset_id );
|
||||
FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.base.asset_id );
|
||||
/*
|
||||
wlog( "${aname} feed pub with crossed prices by ${name} in block ${n}",
|
||||
("aname", base.symbol)
|
||||
("n", d.head_block_num()+1)
|
||||
("name", o.publisher(d).name)
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if( !o.feed.is_for( o.asset_id ) )
|
||||
{
|
||||
wlog( "${aname} feed pub with wrong asset by ${name} in block ${n}",
|
||||
("aname", base.symbol)
|
||||
("n", d.head_block_num()+1)
|
||||
("name", o.publisher(d).name)
|
||||
);
|
||||
}
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
wlog( "${aname} feed pub with invalid price feed by ${name} in block ${n}",
|
||||
("aname", base.symbol)
|
||||
("n", d.head_block_num()+1)
|
||||
("name", o.publisher(d).name)
|
||||
);
|
||||
wdump( (e) );
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma message ("WARNING: Remove this check when starting a new network")
|
||||
#else
|
||||
# warning Remove this check when starting a new network
|
||||
#endif
|
||||
if( d.head_block_num() > 59300 )
|
||||
{
|
||||
FC_ASSERT(
|
||||
(base.symbol != "SEK")
|
||||
&& (base.symbol != "SILVER")
|
||||
&& (base.symbol != "RUB")
|
||||
&& (base.symbol != "GBP")
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// many of these checks should be moved to price_feed.validate()
|
||||
// or the operation validator when new network is started
|
||||
//
|
||||
if( !o.feed.core_exchange_rate.is_null() )
|
||||
{
|
||||
o.feed.core_exchange_rate.validate();
|
||||
}
|
||||
if( (!o.feed.settlement_price.is_null()) && (!o.feed.core_exchange_rate.is_null()) )
|
||||
{
|
||||
FC_ASSERT( o.feed.settlement_price.base.asset_id == o.feed.core_exchange_rate.base.asset_id );
|
||||
FC_ASSERT( o.feed.settlement_price.quote.asset_id == o.feed.core_exchange_rate.quote.asset_id );
|
||||
}
|
||||
|
||||
FC_ASSERT( !o.feed.settlement_price.is_null() );
|
||||
FC_ASSERT( !o.feed.core_exchange_rate.is_null() );
|
||||
FC_ASSERT( o.feed.settlement_price.quote.asset_id == bitasset.options.short_backing_asset );
|
||||
FC_ASSERT( o.feed.is_for( o.asset_id ) );
|
||||
}
|
||||
//Verify that the publisher is authoritative to publish a feed
|
||||
if( base.options.flags & witness_fed_asset )
|
||||
{
|
||||
|
|
@ -639,17 +496,6 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_
|
|||
void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_operation& o)
|
||||
{ try {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma message ("WARNING: Remove this check when preparing for new network release")
|
||||
#else
|
||||
# warning Remove this check when preparing for new network release
|
||||
#endif
|
||||
if( !o.feed.is_for( o.asset_id ) )
|
||||
{
|
||||
wlog( "Ignoring bad feed" );
|
||||
return void_result();
|
||||
}
|
||||
|
||||
database& d = db();
|
||||
|
||||
const asset_object& base = o.asset_id(d);
|
||||
|
|
|
|||
|
|
@ -646,15 +646,8 @@ const witness_object& database::validate_block_header( uint32_t skip, const sign
|
|||
|
||||
witness_id_type scheduled_witness = get_scheduled_witness( slot_num );
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma message ("WARNING: remove this hardfork check for next release")
|
||||
#else
|
||||
# warning remove this hardfork check for next release
|
||||
#endif
|
||||
if( next_block.block_num() > 58500 ) {
|
||||
FC_ASSERT( next_block.witness == scheduled_witness, "Witness produced block at wrong time",
|
||||
("block witness",next_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) );
|
||||
}
|
||||
FC_ASSERT( next_block.witness == scheduled_witness, "Witness produced block at wrong time",
|
||||
("block witness",next_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) );
|
||||
}
|
||||
|
||||
return witness;
|
||||
|
|
|
|||
|
|
@ -502,9 +502,6 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
a.options.description = asset.description;
|
||||
a.precision = asset.precision;
|
||||
string issuer_name = asset.issuer_name;
|
||||
#warning Remove this check doing real network, change BitAsset owners to be committee-account in genesis.
|
||||
if( issuer_name == "witness-account" )
|
||||
issuer_name = "committee-account";
|
||||
a.issuer = get_account_id(issuer_name);
|
||||
a.options.max_supply = asset.max_supply;
|
||||
a.options.flags = witness_fed_asset;
|
||||
|
|
|
|||
|
|
@ -63,12 +63,7 @@ vector<std::reference_wrapper<const typename Index::object_type>> database::sort
|
|||
template<class... Types>
|
||||
void database::perform_account_maintenance(std::tuple<Types...> helpers)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
# pragma message ("WARNING: switch to this for next release: const auto& idx = get_index_type<account_index>().indices().get<by_name>();")
|
||||
#else
|
||||
# warning switch to this for next release: const auto& idx = get_index_type<account_index>().indices().get<by_name>();
|
||||
#endif
|
||||
const auto& idx = get_index_type<account_index>().indices();
|
||||
const auto& idx = get_index_type<account_index>().indices().get<by_name>();
|
||||
for( const account_object& a : idx )
|
||||
detail::for_each(helpers, a, detail::gen_seq<sizeof...(Types)>());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@ namespace graphene {
|
|||
|
||||
bool address::is_valid( const std::string& base58str, const std::string& prefix )
|
||||
{
|
||||
// TODO: This is temporary for testing
|
||||
if( prefix == GRAPHENE_ADDRESS_PREFIX && is_valid( base58str, "BTS" ) )
|
||||
return true;
|
||||
|
||||
const size_t prefix_len = prefix.size();
|
||||
if( base58str.size() <= prefix_len )
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,21 @@ void asset_publish_feed_operation::validate()const
|
|||
{
|
||||
FC_ASSERT( fee.amount >= 0 );
|
||||
feed.validate();
|
||||
|
||||
// maybe some of these could be moved to feed.validate()
|
||||
if( !feed.core_exchange_rate.is_null() )
|
||||
{
|
||||
feed.core_exchange_rate.validate();
|
||||
}
|
||||
if( (!feed.settlement_price.is_null()) && (!feed.core_exchange_rate.is_null()) )
|
||||
{
|
||||
FC_ASSERT( feed.settlement_price.base.asset_id == feed.core_exchange_rate.base.asset_id );
|
||||
FC_ASSERT( feed.settlement_price.quote.asset_id == feed.core_exchange_rate.quote.asset_id );
|
||||
}
|
||||
|
||||
FC_ASSERT( !feed.settlement_price.is_null() );
|
||||
FC_ASSERT( !feed.core_exchange_rate.is_null() );
|
||||
FC_ASSERT( feed.is_for( asset_id ) );
|
||||
}
|
||||
|
||||
void asset_reserve_operation::validate()const
|
||||
|
|
|
|||
|
|
@ -216,6 +216,13 @@ struct approval_delta
|
|||
vector<string> key_approvals_to_remove;
|
||||
};
|
||||
|
||||
struct worker_vote_delta
|
||||
{
|
||||
flat_set<worker_id_type> vote_for;
|
||||
flat_set<worker_id_type> vote_against;
|
||||
flat_set<worker_id_type> vote_abstain;
|
||||
};
|
||||
|
||||
struct signed_block_with_info : public signed_block
|
||||
{
|
||||
signed_block_with_info( const signed_block& block );
|
||||
|
|
@ -1124,6 +1131,43 @@ class wallet_api
|
|||
string block_signing_key,
|
||||
bool broadcast = false);
|
||||
|
||||
|
||||
/**
|
||||
* Create a worker object.
|
||||
*
|
||||
* @param owner_account The account which owns the worker and will be paid
|
||||
* @param work_begin_date When the work begins
|
||||
* @param work_end_date When the work ends
|
||||
* @param daily_pay Amount of pay per day (NOT per maint interval)
|
||||
* @param name Any text
|
||||
* @param url Any text
|
||||
* @param worker_settings {"type" : "burn"|"refund"|"vesting", "pay_vesting_period_days" : x}
|
||||
* @param broadcast true if you wish to broadcast the transaction.
|
||||
*/
|
||||
signed_transaction create_worker(
|
||||
string owner_account,
|
||||
time_point_sec work_begin_date,
|
||||
time_point_sec work_end_date,
|
||||
share_type daily_pay,
|
||||
string name,
|
||||
string url,
|
||||
variant worker_settings,
|
||||
bool broadcast = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Update your votes for a worker
|
||||
*
|
||||
* @param account The account which will pay the fee and update votes.
|
||||
* @param worker_vote_delta {"vote_for" : [...], "vote_against" : [...], "vote_abstain" : [...]}
|
||||
* @param broadcast true if you wish to broadcast the transaction.
|
||||
*/
|
||||
signed_transaction update_worker_votes(
|
||||
string account,
|
||||
worker_vote_delta delta,
|
||||
bool broadcast = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Get information about a vesting balance object.
|
||||
*
|
||||
|
|
@ -1380,6 +1424,12 @@ FC_REFLECT( graphene::wallet::approval_delta,
|
|||
(key_approvals_to_remove)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::wallet::worker_vote_delta,
|
||||
(vote_for)
|
||||
(vote_against)
|
||||
(vote_abstain)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::wallet::signed_block_with_info, (graphene::chain::signed_block),
|
||||
(block_id)(signing_key) )
|
||||
|
||||
|
|
@ -1440,6 +1490,8 @@ FC_API( graphene::wallet::wallet_api,
|
|||
(list_committee_members)
|
||||
(create_witness)
|
||||
(update_witness)
|
||||
(create_worker)
|
||||
(update_worker_votes)
|
||||
(get_vesting_balances)
|
||||
(withdraw_vesting)
|
||||
(vote_for_committee_member)
|
||||
|
|
|
|||
|
|
@ -1407,6 +1407,122 @@ public:
|
|||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (witness_name)(url)(block_signing_key)(broadcast) ) }
|
||||
|
||||
template<typename WorkerInit>
|
||||
static WorkerInit _create_worker_initializer( const variant& worker_settings )
|
||||
{
|
||||
WorkerInit result;
|
||||
from_variant( worker_settings, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
signed_transaction create_worker(
|
||||
string owner_account,
|
||||
time_point_sec work_begin_date,
|
||||
time_point_sec work_end_date,
|
||||
share_type daily_pay,
|
||||
string name,
|
||||
string url,
|
||||
variant worker_settings,
|
||||
bool broadcast
|
||||
)
|
||||
{
|
||||
worker_initializer init;
|
||||
std::string wtype = worker_settings["type"].get_string();
|
||||
|
||||
// TODO: Use introspection to do this dispatch
|
||||
if( wtype == "burn" )
|
||||
init = _create_worker_initializer< burn_worker_initializer >( worker_settings );
|
||||
else if( wtype == "refund" )
|
||||
init = _create_worker_initializer< refund_worker_initializer >( worker_settings );
|
||||
else if( wtype == "vesting" )
|
||||
init = _create_worker_initializer< vesting_balance_worker_initializer >( worker_settings );
|
||||
else
|
||||
{
|
||||
FC_ASSERT( false, "unknown worker[\"type\"] value" );
|
||||
}
|
||||
|
||||
worker_create_operation op;
|
||||
op.owner = get_account( owner_account ).id;
|
||||
op.work_begin_date = work_begin_date;
|
||||
op.work_end_date = work_end_date;
|
||||
op.daily_pay = daily_pay;
|
||||
op.name = name;
|
||||
op.url = url;
|
||||
op.initializer = init;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( op );
|
||||
set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees );
|
||||
tx.validate();
|
||||
|
||||
return sign_transaction( tx, broadcast );
|
||||
}
|
||||
|
||||
signed_transaction update_worker_votes(
|
||||
string account,
|
||||
worker_vote_delta delta,
|
||||
bool broadcast
|
||||
)
|
||||
{
|
||||
account_object acct = get_account( account );
|
||||
account_update_operation op;
|
||||
|
||||
// you could probably use a faster algorithm for this, but flat_set is fast enough :)
|
||||
flat_set< worker_id_type > merged;
|
||||
merged.reserve( delta.vote_for.size() + delta.vote_against.size() + delta.vote_abstain.size() );
|
||||
for( const worker_id_type& wid : delta.vote_for )
|
||||
{
|
||||
bool inserted = merged.insert( wid ).second;
|
||||
FC_ASSERT( inserted, "worker ${wid} specified multiple times", ("wid", wid) );
|
||||
}
|
||||
for( const worker_id_type& wid : delta.vote_against )
|
||||
{
|
||||
bool inserted = merged.insert( wid ).second;
|
||||
FC_ASSERT( inserted, "worker ${wid} specified multiple times", ("wid", wid) );
|
||||
}
|
||||
for( const worker_id_type& wid : delta.vote_abstain )
|
||||
{
|
||||
bool inserted = merged.insert( wid ).second;
|
||||
FC_ASSERT( inserted, "worker ${wid} specified multiple times", ("wid", wid) );
|
||||
}
|
||||
|
||||
// should be enforced by FC_ASSERT's above
|
||||
assert( merged.size() == delta.vote_for.size() + delta.vote_against.size() + delta.vote_abstain.size() );
|
||||
|
||||
vector< object_id_type > query_ids;
|
||||
for( const worker_id_type& wid : merged )
|
||||
query_ids.push_back( wid );
|
||||
|
||||
flat_set<vote_id_type> new_votes( acct.options.votes );
|
||||
|
||||
fc::variants objects = _remote_db->get_objects( query_ids );
|
||||
for( const variant& obj : objects )
|
||||
{
|
||||
worker_object wo;
|
||||
from_variant( obj, wo );
|
||||
new_votes.erase( wo.vote_for );
|
||||
new_votes.erase( wo.vote_against );
|
||||
if( delta.vote_for.find( wo.id ) != delta.vote_for.end() )
|
||||
new_votes.insert( wo.vote_for );
|
||||
else if( delta.vote_against.find( wo.id ) != delta.vote_against.end() )
|
||||
new_votes.insert( wo.vote_against );
|
||||
else
|
||||
assert( delta.vote_abstain.find( wo.id ) != delta.vote_abstain.end() );
|
||||
}
|
||||
|
||||
account_update_operation update_op;
|
||||
update_op.account = acct.id;
|
||||
update_op.new_options = acct.options;
|
||||
update_op.new_options->votes = new_votes;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( update_op );
|
||||
set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees );
|
||||
tx.validate();
|
||||
|
||||
return sign_transaction( tx, broadcast );
|
||||
}
|
||||
|
||||
vector< vesting_balance_object_with_info > get_vesting_balances( string account_name )
|
||||
{ try {
|
||||
fc::optional<vesting_balance_id_type> vbid = maybe_id<vesting_balance_id_type>( account_name );
|
||||
|
|
@ -2864,6 +2980,28 @@ signed_transaction wallet_api::create_witness(string owner_account,
|
|||
return my->create_witness(owner_account, url, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_worker(
|
||||
string owner_account,
|
||||
time_point_sec work_begin_date,
|
||||
time_point_sec work_end_date,
|
||||
share_type daily_pay,
|
||||
string name,
|
||||
string url,
|
||||
variant worker_settings,
|
||||
bool broadcast /* = false */)
|
||||
{
|
||||
return my->create_worker( owner_account, work_begin_date, work_end_date,
|
||||
daily_pay, name, url, worker_settings, broadcast );
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::update_worker_votes(
|
||||
string owner_account,
|
||||
worker_vote_delta delta,
|
||||
bool broadcast /* = false */)
|
||||
{
|
||||
return my->update_worker_votes( owner_account, delta, broadcast );
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::update_witness(
|
||||
string witness_name,
|
||||
string url,
|
||||
|
|
|
|||
63
programs/genesis_util/change_key_prefix.py
Executable file
63
programs/genesis_util/change_key_prefix.py
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
def dump_json(obj, out, pretty):
|
||||
if pretty:
|
||||
json.dump(obj, out, indent=2, sort_keys=True)
|
||||
else:
|
||||
json.dump(obj, out, separators=(",", ":"), sort_keys=True)
|
||||
return
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Set is_prefixed=false for all asset owners")
|
||||
parser.add_argument("-o", "--output", metavar="OUT", default="-", help="output filename (default: stdout)")
|
||||
parser.add_argument("-i", "--input", metavar="IN", default="-", help="input filename (default: stdin)")
|
||||
parser.add_argument("-f", "--from", metavar="PREFIX", default="", help="initial prefix")
|
||||
parser.add_argument("-t", "--to", metavar="PREFIX", default="", help="new prefix")
|
||||
parser.add_argument("-p", "--pretty", action="store_true", default=False, help="pretty print output")
|
||||
opts = parser.parse_args()
|
||||
|
||||
if opts.input == "-":
|
||||
genesis = json.load(sys.stdin)
|
||||
else:
|
||||
with open(opts.input, "r") as f:
|
||||
genesis = json.load(f)
|
||||
|
||||
frum = opts.__dict__["from"] # from is a language keyword and cannot be an attribute name
|
||||
|
||||
def convert(k):
|
||||
if not k.startswith(frum):
|
||||
print("key {k} does not start with prefix {p}".format(k=repr(k), p=repr(frum)))
|
||||
raise RuntimeError()
|
||||
return opts.to + k[len(frum):]
|
||||
|
||||
for account in genesis["initial_accounts"]:
|
||||
account["owner_key"] = convert(account["owner_key"])
|
||||
account["active_key"] = convert(account["active_key"])
|
||||
|
||||
for asset in genesis["initial_assets"]:
|
||||
for cr in asset.get("collateral_records", []):
|
||||
cr["owner"] = convert(cr["owner"])
|
||||
|
||||
for balance in genesis["initial_balances"]:
|
||||
balance["owner"] = convert(balance["owner"])
|
||||
|
||||
for vb in genesis["initial_vesting_balances"]:
|
||||
vb["owner"] = convert(vb["owner"])
|
||||
|
||||
for witness in genesis["initial_witness_candidates"]:
|
||||
witness["block_signing_key"] = convert(witness["block_signing_key"])
|
||||
|
||||
if opts.output == "-":
|
||||
dump_json( genesis, sys.stdout, opts.pretty )
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
with open(opts.output, "w") as f:
|
||||
dump_json( genesis, f, opts.pretty )
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
72
programs/genesis_util/create_bloom_filter.py
Executable file
72
programs/genesis_util/create_bloom_filter.py
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Set is_prefixed=false for all asset owners")
|
||||
parser.add_argument("-o", "--output", metavar="OUT", default="-", help="output filename (default: stdout)")
|
||||
parser.add_argument("-i", "--input", metavar="IN", default="-", help="input filename (default: stdin)")
|
||||
parser.add_argument("-n", "--num", metavar="N", default=3, type=int, help="number of hashes per key (default: 3)")
|
||||
parser.add_argument("-s", "--size", metavar="BITS", default=8*1048576, type=int, help="number of bits in filter")
|
||||
parser.add_argument("-a", "--algorithm", metavar="NAME", default="sha256", type=str, help="hash algorithm (must exist in hashlib)")
|
||||
opts = parser.parse_args()
|
||||
|
||||
if opts.input == "-":
|
||||
genesis = json.load(sys.stdin)
|
||||
else:
|
||||
with open(opts.input, "r") as f:
|
||||
genesis = json.load(f)
|
||||
|
||||
keys = set()
|
||||
|
||||
for account in genesis["initial_accounts"]:
|
||||
keys.add(account["owner_key"])
|
||||
keys.add(account["active_key"])
|
||||
|
||||
for asset in genesis["initial_assets"]:
|
||||
for cr in asset.get("collateral_records", []):
|
||||
keys.add(cr["owner"])
|
||||
|
||||
for balance in genesis["initial_balances"]:
|
||||
keys.add(balance["owner"])
|
||||
|
||||
for vb in genesis["initial_vesting_balances"]:
|
||||
keys.add(vb["owner"])
|
||||
|
||||
for witness in genesis["initial_witness_candidates"]:
|
||||
keys.add(witness["block_signing_key"])
|
||||
|
||||
sys.stderr.write("got {n} distinct keys\n".format(n=len(keys)))
|
||||
|
||||
keys = [(str(i) + ":" + k).encode("UTF-8") for k in sorted(keys) for i in range(opts.num)]
|
||||
|
||||
data = bytearray((opts.size + 7) >> 3)
|
||||
|
||||
h = getattr(hashlib, opts.algorithm)
|
||||
for k in keys:
|
||||
address = int(h(k).hexdigest(), 16) % opts.size
|
||||
data[address >> 3] |= (1 << (address & 7))
|
||||
|
||||
popcount = [bin(i).count("1") for i in range(256)]
|
||||
w = sum(popcount[x] for x in data)
|
||||
sys.stderr.write("""w={w} o={o:.3%} p={p:.3%}
|
||||
w: Hamming weight o: Occupancy p: False positive probability
|
||||
""".format(
|
||||
w=w,
|
||||
o=float(w) / float(opts.size),
|
||||
p=(float(w) / float(opts.size))**opts.num,
|
||||
))
|
||||
|
||||
if opts.output == "-":
|
||||
sys.stdout.write(data)
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
with open(opts.output, "wb") as f:
|
||||
f.write(data)
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in a new issue