This commit is contained in:
Daniel Larimer 2015-10-22 09:59:03 -04:00
commit 6418f819fd
11 changed files with 348 additions and 187 deletions

View file

@ -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;
});

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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)>());
}

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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,

View 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()

View 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()