Progress #17
- Add initial support for vesting genesis balances - Add owner/active keys to genesis accounts - Cleanup circa balance_object and evaluator
This commit is contained in:
parent
a05a13b20e
commit
c530867933
23 changed files with 348 additions and 345 deletions
|
|
@ -161,14 +161,21 @@ namespace detail {
|
|||
for( int i = 0; i < 10; ++i )
|
||||
{
|
||||
auto name = "init"+fc::to_string(i);
|
||||
initial_state.initial_accounts.emplace_back(name, nathan_key.get_public_key(), true);
|
||||
initial_state.initial_accounts.emplace_back(name,
|
||||
nathan_key.get_public_key(),
|
||||
nathan_key.get_public_key(),
|
||||
true);
|
||||
initial_state.initial_committee.push_back({name});
|
||||
initial_state.initial_witnesses.push_back({name, nathan_key.get_public_key(), secret});
|
||||
}
|
||||
|
||||
initial_state.initial_accounts.emplace_back("nathan", address(public_key_type(nathan_key.get_public_key())), 1);
|
||||
initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key());
|
||||
initial_state.initial_balances.push_back({nathan_key.get_public_key(),
|
||||
GRAPHENE_SYMBOL,
|
||||
GRAPHENE_MAX_SHARE_SUPPLY});
|
||||
if( _options->count("genesis-json") )
|
||||
initial_state = fc::json::from_file(_options->at("genesis-json").as<boost::filesystem::path>()).as<genesis_state_type>();
|
||||
initial_state = fc::json::from_file(_options->at("genesis-json").as<boost::filesystem::path>())
|
||||
.as<genesis_state_type>();
|
||||
else
|
||||
dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key)));
|
||||
|
||||
|
|
@ -199,20 +206,9 @@ namespace detail {
|
|||
try
|
||||
{
|
||||
if( id.item_type == graphene::net::block_message_type )
|
||||
{
|
||||
// for some reason, the contains() function called by is_known_block
|
||||
// throws when the block is not present (instead of returning false)
|
||||
try
|
||||
{
|
||||
return _chain_db->is_known_block( id.item_hash );
|
||||
}
|
||||
catch (const fc::key_not_found_exception&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return _chain_db->is_known_block(id.item_hash);
|
||||
else
|
||||
return _chain_db->is_known_transaction( id.item_hash ); // is_known_transaction behaves normally
|
||||
return _chain_db->is_known_transaction(id.item_hash);
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW( (id) )
|
||||
}
|
||||
|
|
@ -255,7 +251,7 @@ namespace detail {
|
|||
virtual std::vector<item_hash_t> get_item_ids(uint32_t item_type,
|
||||
const std::vector<item_hash_t>& blockchain_synopsis,
|
||||
uint32_t& remaining_item_count,
|
||||
uint32_t limit ) override
|
||||
uint32_t limit) override
|
||||
{ try {
|
||||
FC_ASSERT( item_type == graphene::net::block_message_type );
|
||||
vector<block_id_type> result;
|
||||
|
|
@ -268,7 +264,7 @@ namespace detail {
|
|||
auto itr = blockchain_synopsis.rbegin();
|
||||
while( itr != blockchain_synopsis.rend() )
|
||||
{
|
||||
if( _chain_db->is_known_block( *itr ) || *itr == block_id_type() )
|
||||
if( _chain_db->is_known_block(*itr) || *itr == block_id_type() )
|
||||
{
|
||||
last_known_block_id = *itr;
|
||||
break;
|
||||
|
|
@ -285,7 +281,6 @@ namespace detail {
|
|||
if( block_header::num_from_id(result.back()) < _chain_db->head_block_num() )
|
||||
remaining_item_count = _chain_db->head_block_num() - block_header::num_from_id(result.back());
|
||||
|
||||
idump((blockchain_synopsis)(limit)(result)(remaining_item_count));
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (blockchain_synopsis)(remaining_item_count)(limit) ) }
|
||||
|
||||
|
|
|
|||
|
|
@ -48,13 +48,11 @@ void block_database::open( const fc::path& dbdir )
|
|||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (dbdir) ) }
|
||||
|
||||
|
||||
bool block_database::is_open()const
|
||||
{
|
||||
return _blocks.is_open();
|
||||
}
|
||||
|
||||
|
||||
void block_database::close()
|
||||
{
|
||||
_blocks.close();
|
||||
|
|
@ -67,7 +65,6 @@ void block_database::flush()
|
|||
_block_num_to_pos.flush();
|
||||
}
|
||||
|
||||
|
||||
void block_database::store( const block_id_type& id, const signed_block& b )
|
||||
{
|
||||
auto num = block_header::num_from_id(id);
|
||||
|
|
@ -82,7 +79,6 @@ void block_database::store( const block_id_type& id, const signed_block& b )
|
|||
_block_num_to_pos.write( (char*)&e, sizeof(e) );
|
||||
}
|
||||
|
||||
|
||||
void block_database::remove( const block_id_type& id )
|
||||
{ try {
|
||||
index_entry e;
|
||||
|
|
@ -102,25 +98,20 @@ void block_database::remove( const block_id_type& id )
|
|||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (id) ) }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool block_database::contains( const block_id_type& id )const
|
||||
bool block_database::contains( const block_id_type& id )const
|
||||
{
|
||||
index_entry e;
|
||||
auto index_pos = sizeof(e)*block_header::num_from_id(id);
|
||||
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
|
||||
if ( _block_num_to_pos.tellg() <= index_pos )
|
||||
FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${id} not contained in block database", ("id", id));
|
||||
return false;
|
||||
_block_num_to_pos.seekg( index_pos );
|
||||
_block_num_to_pos.read( (char*)&e, sizeof(e) );
|
||||
|
||||
return e.block_id == id;
|
||||
}
|
||||
|
||||
|
||||
block_id_type block_database::fetch_block_id( uint32_t block_num )const
|
||||
block_id_type block_database::fetch_block_id( uint32_t block_num )const
|
||||
{
|
||||
index_entry e;
|
||||
auto index_pos = sizeof(e)*block_num;
|
||||
|
|
@ -134,22 +125,21 @@ block_id_type block_database::fetch_block_id( uint32_t block_num )const
|
|||
return e.block_id;
|
||||
}
|
||||
|
||||
|
||||
optional<signed_block> block_database::fetch_optional( const block_id_type& id )const
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
index_entry e;
|
||||
auto index_pos = sizeof(e)*block_header::num_from_id(id);
|
||||
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
|
||||
if ( _block_num_to_pos.tellg() <= index_pos )
|
||||
FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${id} not contained in block database", ("id", id));
|
||||
|
||||
return {};
|
||||
|
||||
_block_num_to_pos.seekg( index_pos );
|
||||
_block_num_to_pos.read( (char*)&e, sizeof(e) );
|
||||
|
||||
|
||||
if( e.block_id != id ) return optional<signed_block>();
|
||||
|
||||
|
||||
vector<char> data( e.block_size );
|
||||
_blocks.seekg( e.block_pos );
|
||||
_blocks.read( data.data(), e.block_size );
|
||||
|
|
@ -168,13 +158,13 @@ optional<signed_block> block_database::fetch_optional( const block_id_type& id )
|
|||
|
||||
optional<signed_block> block_database::fetch_by_number( uint32_t block_num )const
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
index_entry e;
|
||||
auto index_pos = sizeof(e)*block_num;
|
||||
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
|
||||
if ( _block_num_to_pos.tellg() <= index_pos )
|
||||
FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block number ${block_num} not contained in block database", ("block_num", block_num));
|
||||
return {};
|
||||
|
||||
_block_num_to_pos.seekg( index_pos, _block_num_to_pos.beg );
|
||||
_block_num_to_pos.read( (char*)&e, sizeof(e) );
|
||||
|
|
@ -195,10 +185,9 @@ optional<signed_block> block_database::fetch_by_number( uint32_t block_num )cons
|
|||
return optional<signed_block>();
|
||||
}
|
||||
|
||||
|
||||
optional<signed_block> block_database::last()const
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
index_entry e;
|
||||
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
|
||||
|
|
@ -231,5 +220,4 @@ optional<signed_block> block_database::last()const
|
|||
}
|
||||
return optional<signed_block>();
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -301,10 +301,10 @@ signed_block database::_generate_block(
|
|||
{
|
||||
for( const auto& trx : tmp.transactions )
|
||||
{
|
||||
try {
|
||||
push_transaction( trx, skip );
|
||||
} catch ( const fc::exception& e ) {
|
||||
wlog( "Transaction is no longer valid: ${trx}", ("trx",trx) );
|
||||
try {
|
||||
push_transaction( trx, skip );
|
||||
} catch ( const fc::exception& e ) {
|
||||
wlog( "Transaction is no longer valid: ${trx}", ("trx",trx) );
|
||||
}
|
||||
}
|
||||
return _generate_block( when, witness_id, block_signing_private_key );
|
||||
|
|
@ -435,28 +435,6 @@ processed_transaction database::apply_transaction( const signed_transaction& trx
|
|||
return result;
|
||||
}
|
||||
|
||||
struct signature_check_visitor
|
||||
{
|
||||
typedef void result_type;
|
||||
|
||||
flat_map<address,bool>& sigs;
|
||||
signature_check_visitor( flat_map<address,bool>& s ):sigs(s){}
|
||||
|
||||
template<typename T>
|
||||
result_type operator()( const T& o )const{}
|
||||
|
||||
result_type operator()( const balance_claim_operation& o )const
|
||||
{
|
||||
for( auto& owner : o.owners )
|
||||
{
|
||||
auto itr = sigs.find(owner);
|
||||
FC_ASSERT( itr != sigs.end() );
|
||||
itr->second = true;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
processed_transaction database::_apply_transaction( const signed_transaction& trx )
|
||||
{ try {
|
||||
uint32_t skip = get_node_properties().skip_flags;
|
||||
|
|
@ -476,8 +454,6 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr
|
|||
|
||||
for( const auto& sig : trx.signatures )
|
||||
FC_ASSERT( eval_state._sigs.insert( std::make_pair( address(fc::ecc::public_key( sig, trx.digest() )), false) ).second, "Multiple signatures by same key detected" ) ;
|
||||
|
||||
trx.visit( signature_check_visitor(eval_state._sigs) );
|
||||
}
|
||||
|
||||
//If we're skipping tapos check, but not dupe check, assume all transactions have maximum expiration time.
|
||||
|
|
@ -503,9 +479,9 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr
|
|||
eval_state._sigs.reserve( trx.signatures.size() );
|
||||
|
||||
for( const auto& sig : trx.signatures )
|
||||
FC_ASSERT( eval_state._sigs.insert( std::make_pair(address(fc::ecc::public_key( sig, trx.digest(tapos_block_summary.block_id) )),false) ).second, "Multiple signatures by same key detected" ) ;
|
||||
|
||||
trx.visit( signature_check_visitor(eval_state._sigs) );
|
||||
FC_ASSERT(eval_state._sigs.insert(
|
||||
std::make_pair(address(fc::ecc::public_key(sig, trx.digest(tapos_block_summary.block_id) )),
|
||||
false)).second, "Multiple signatures by same key detected");
|
||||
}
|
||||
|
||||
//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
|
||||
|
|
@ -513,7 +489,7 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr
|
|||
trx_expiration = tapos_block_summary.timestamp + chain_parameters.block_interval*trx.relative_expiration;
|
||||
} else if( trx.relative_expiration == 0 ) {
|
||||
trx_expiration = fc::time_point_sec() + fc::seconds(trx.ref_block_prefix);
|
||||
FC_ASSERT( trx_expiration <= _pending_block.timestamp + chain_parameters.maximum_time_until_expiration, "",
|
||||
FC_ASSERT( trx_expiration <= _pending_block.timestamp + chain_parameters.maximum_time_until_expiration, "",
|
||||
("trx_expiration",trx_expiration)("_pending_block.timestamp",_pending_block.timestamp)("max_til_exp",chain_parameters.maximum_time_until_expiration));
|
||||
}
|
||||
FC_ASSERT( _pending_block.timestamp <= trx_expiration, "", ("pending.timestamp",_pending_block.timestamp)("trx_exp",trx_expiration) );
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
|
||||
transaction_evaluation_state genesis_eval_state(this);
|
||||
|
||||
// Create initial accounts
|
||||
// Create blockchain accounts
|
||||
fc::ecc::private_key null_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")));
|
||||
create<key_object>( [&null_private_key](key_object& k) {
|
||||
k.key_data = public_key_type(null_private_key.get_public_key());
|
||||
|
|
@ -280,6 +280,8 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
adjust_balance(GRAPHENE_COMMITTEE_ACCOUNT, -get_balance(GRAPHENE_COMMITTEE_ACCOUNT,{}));
|
||||
}
|
||||
|
||||
// TODO: Create initial vesting balances
|
||||
|
||||
// Create initial accounts
|
||||
if( !genesis_state.initial_accounts.empty() )
|
||||
{
|
||||
|
|
@ -288,12 +290,21 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
|||
key_id_type key_id = apply_operation(genesis_eval_state,
|
||||
key_create_operation({asset(),
|
||||
committee_account.id,
|
||||
account.addr})).get<object_id_type>();
|
||||
account.owner_key})).get<object_id_type>();
|
||||
account_create_operation cop;
|
||||
cop.name = account.name;
|
||||
cop.registrar = account_id_type(1);
|
||||
cop.active = authority(1, key_id, 1);
|
||||
cop.owner = cop.active;
|
||||
cop.owner = authority(1, key_id, 1);
|
||||
if( account.owner_key != account.active_key )
|
||||
{
|
||||
key_id = apply_operation(genesis_eval_state,
|
||||
key_create_operation({asset(),
|
||||
committee_account.id,
|
||||
account.owner_key})).get<object_id_type>();
|
||||
cop.active = authority(1, key_id, 1);
|
||||
} else {
|
||||
cop.active = cop.owner;
|
||||
}
|
||||
cop.options.memo_key = key_id;
|
||||
account_id_type account_id(apply_operation(genesis_eval_state, cop).get<object_id_type>());
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
database& generic_evaluator::db()const { return trx_state->db(); }
|
||||
database& generic_evaluator::db()const { return trx_state->db(); }
|
||||
|
||||
operation_result generic_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
|
||||
{ try {
|
||||
trx_state = &eval_state;
|
||||
|
|
|
|||
|
|
@ -1,47 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/transaction.hpp>
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
#include <graphene/chain/balance_object.hpp>
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @ingroup operations
|
||||
*/
|
||||
class balance_claim_evaluator : public evaluator<balance_claim_evaluator>
|
||||
class balance_claim_evaluator : public evaluator<balance_claim_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef balance_claim_operation operation_type;
|
||||
|
||||
const balance_object* balance = nullptr;
|
||||
asset amount_withdrawn;
|
||||
|
||||
asset do_evaluate(const balance_claim_operation& op)
|
||||
{
|
||||
public:
|
||||
typedef balance_claim_operation operation_type;
|
||||
database& d = db();
|
||||
balance = &op.balance_to_claim(d);
|
||||
|
||||
void_result do_evaluate( const balance_claim_operation& op )
|
||||
{
|
||||
return void_result();
|
||||
}
|
||||
FC_ASSERT(trx_state->_sigs.count(balance->owner) == 1);
|
||||
trx_state->_sigs[balance->owner] = true;
|
||||
FC_ASSERT(op.total_claimed.asset_id == balance->asset_type());
|
||||
|
||||
/**
|
||||
* @note the fee is always 0 for this particular operation because once the
|
||||
* balance is claimed it frees up memory and it cannot be used to spam the network
|
||||
*/
|
||||
void_result do_apply( const balance_claim_operation& op )
|
||||
{
|
||||
const auto& bal_idx = db().get_index_type<balance_index>();
|
||||
const auto& by_owner_idx = bal_idx.indices().get<by_owner>();
|
||||
if( balance->vesting_policy.valid() ) {
|
||||
FC_ASSERT(op.total_claimed.amount == 0);
|
||||
return amount_withdrawn = balance->vesting_policy->get_allowed_withdraw({balance->balance,
|
||||
d.head_block_time(),
|
||||
{}});
|
||||
}
|
||||
|
||||
asset total(0, op.total_claimed.asset_id);
|
||||
for( const auto& owner : op.owners )
|
||||
{
|
||||
auto itr = by_owner_idx.find( boost::make_tuple( owner, total.asset_id ) );
|
||||
if( itr != by_owner_idx.end() )
|
||||
{
|
||||
total += itr->balance;
|
||||
db().remove( *itr );
|
||||
}
|
||||
}
|
||||
FC_ASSERT(op.total_claimed == balance->balance);
|
||||
return amount_withdrawn = op.total_claimed;
|
||||
}
|
||||
|
||||
FC_ASSERT( total == op.total_claimed, "", ("total",total)("op",op) );
|
||||
/**
|
||||
* @note the fee is always 0 for this particular operation because once the
|
||||
* balance is claimed it frees up memory and it cannot be used to spam the network
|
||||
*/
|
||||
asset do_apply(const balance_claim_operation& op)
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
db().adjust_balance( op.deposit_to_account, total );
|
||||
if( balance->vesting_policy.valid() && amount_withdrawn < balance->balance )
|
||||
d.modify(*balance, [&](balance_object& b) {
|
||||
b.vesting_policy->on_withdraw({b.balance, d.head_block_time(), amount_withdrawn});
|
||||
b.balance -= amount_withdrawn;
|
||||
});
|
||||
else
|
||||
d.remove(*balance);
|
||||
|
||||
return void_result();
|
||||
}
|
||||
};
|
||||
d.adjust_balance(op.deposit_to_account, amount_withdrawn);
|
||||
return amount_withdrawn;
|
||||
}
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class balance_object : public abstract_object<balance_object>
|
||||
|
|
@ -10,6 +12,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
address owner;
|
||||
asset balance;
|
||||
optional<linear_vesting_policy> vesting_policy;
|
||||
asset_id_type asset_type()const { return balance.asset_id; }
|
||||
};
|
||||
|
||||
|
|
@ -36,4 +39,4 @@ namespace graphene { namespace chain {
|
|||
using balance_index = generic_index<balance_object, balance_multi_index_type>;
|
||||
} }
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::balance_object, (graphene::db::object), (owner)(balance) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::balance_object, (graphene::db::object), (owner)(balance)(vesting_policy) )
|
||||
|
|
|
|||
|
|
@ -40,20 +40,34 @@ namespace graphene { namespace chain {
|
|||
using graphene::db::object;
|
||||
|
||||
struct genesis_state_type {
|
||||
struct genesis_account_type {
|
||||
genesis_account_type(const string& name = string(),
|
||||
const address& addr = address(),
|
||||
bool is_lifetime_member = false)
|
||||
: name(name), addr(addr), is_lifetime_member(is_lifetime_member){}
|
||||
struct initial_account_type {
|
||||
initial_account_type(const string& name = string(),
|
||||
const public_key_type& owner_key = public_key_type(),
|
||||
const public_key_type& active_key = public_key_type(),
|
||||
bool is_lifetime_member = false)
|
||||
: name(name),
|
||||
owner_key(owner_key),
|
||||
active_key(active_key == public_key_type()? owner_key : active_key),
|
||||
is_lifetime_member(is_lifetime_member)
|
||||
{}
|
||||
string name;
|
||||
address addr;
|
||||
public_key_type owner_key;
|
||||
public_key_type active_key;
|
||||
bool is_lifetime_member;
|
||||
};
|
||||
struct genesis_balance_type {
|
||||
struct initial_balance_type {
|
||||
address owner;
|
||||
string asset_symbol;
|
||||
share_type amount;
|
||||
};
|
||||
struct initial_vesting_balance_type {
|
||||
address owner;
|
||||
string asset_symbol;
|
||||
share_type amount;
|
||||
time_point_sec vesting_start_date;
|
||||
time_point_sec earliest_withdrawal_date;
|
||||
time_point_sec vesting_end_date;
|
||||
};
|
||||
struct initial_witness_type {
|
||||
/// Must correspond to one of the allocation targets.
|
||||
string owner_name;
|
||||
|
|
@ -66,8 +80,8 @@ namespace graphene { namespace chain {
|
|||
};
|
||||
|
||||
chain_parameters initial_parameters;
|
||||
vector<genesis_account_type> initial_accounts;
|
||||
vector<genesis_balance_type> initial_balances;
|
||||
vector<initial_account_type> initial_accounts;
|
||||
vector<initial_balance_type> initial_balances;
|
||||
vector<initial_witness_type> initial_witnesses;
|
||||
vector<initial_committee_member_type> initial_committee;
|
||||
};
|
||||
|
|
@ -513,9 +527,12 @@ namespace graphene { namespace chain {
|
|||
}
|
||||
} }
|
||||
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::genesis_account_type, (name)(addr)(is_lifetime_member))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::genesis_balance_type,
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type,
|
||||
(owner)(asset_symbol)(amount))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type,
|
||||
(owner)(asset_symbol)(amount)(vesting_start_date)(earliest_withdrawal_date)(vesting_end_date))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)(initial_secret))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type, (initial_parameters)(initial_accounts)(initial_balances)(initial_witnesses)(initial_committee))
|
||||
FC_REFLECT(graphene::chain::genesis_state_type,
|
||||
(initial_parameters)(initial_accounts)(initial_balances)(initial_witnesses)(initial_committee))
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
namespace graphene { namespace chain {
|
||||
|
||||
class database;
|
||||
class signed_transaction;
|
||||
class generic_evaluator;
|
||||
class transaction_evaluation_state;
|
||||
|
||||
|
|
@ -42,175 +43,175 @@ namespace graphene { namespace chain {
|
|||
*/
|
||||
class evaluation_observer
|
||||
{
|
||||
public:
|
||||
virtual ~evaluation_observer(){}
|
||||
public:
|
||||
virtual ~evaluation_observer(){}
|
||||
|
||||
virtual void pre_evaluate(
|
||||
const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge ) {}
|
||||
virtual void pre_evaluate(const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge)
|
||||
{}
|
||||
|
||||
virtual void post_evaluate(
|
||||
const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge,
|
||||
const operation_result& result ) {}
|
||||
virtual void post_evaluate(const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge,
|
||||
const operation_result& result)
|
||||
{}
|
||||
|
||||
virtual void evaluation_failed(
|
||||
const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge,
|
||||
const operation_result& result ) {}
|
||||
virtual void evaluation_failed(const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge,
|
||||
const operation_result& result)
|
||||
{}
|
||||
};
|
||||
|
||||
class generic_evaluator
|
||||
{
|
||||
public:
|
||||
virtual ~generic_evaluator(){}
|
||||
public:
|
||||
virtual ~generic_evaluator(){}
|
||||
|
||||
virtual int get_type()const = 0;
|
||||
virtual operation_result start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply );
|
||||
virtual int get_type()const = 0;
|
||||
virtual operation_result start_evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply);
|
||||
|
||||
/** @note derived classes should ASSUME that the default validation that is
|
||||
* indepenent of chain state should be performed by op.validate() and should
|
||||
* not perform these extra checks.
|
||||
*/
|
||||
virtual operation_result evaluate( const operation& op ) = 0;
|
||||
virtual operation_result apply( const operation& op ) = 0;
|
||||
/**
|
||||
* @note derived classes should ASSUME that the default validation that is
|
||||
* indepenent of chain state should be performed by op.validate() and should
|
||||
* not perform these extra checks.
|
||||
*/
|
||||
virtual operation_result evaluate(const operation& op) = 0;
|
||||
virtual operation_result apply(const operation& op) = 0;
|
||||
|
||||
database& db()const;
|
||||
database& db()const;
|
||||
|
||||
void check_required_authorities(const operation& op);
|
||||
void check_required_authorities(const operation& op);
|
||||
protected:
|
||||
/**
|
||||
* @brief Fetch objects relevant to fee payer and set pointer members
|
||||
* @param account_id Account which is paying the fee
|
||||
* @param fee The fee being paid. May be in assets other than core.
|
||||
*
|
||||
* This method verifies that the fee is valid and sets the object pointer members and the fee fields. It should
|
||||
* be called during do_evaluate.
|
||||
*/
|
||||
void prepare_fee(account_id_type account_id, asset fee);
|
||||
/// Pays the fee and returns the number of CORE asset that were paid.
|
||||
void pay_fee();
|
||||
/**
|
||||
* @brief Fetch objects relevant to fee payer and set pointer members
|
||||
* @param account_id Account which is paying the fee
|
||||
* @param fee The fee being paid. May be in assets other than core.
|
||||
*
|
||||
* This method verifies that the fee is valid and sets the object pointer members and the fee fields. It should
|
||||
* be called during do_evaluate.
|
||||
*/
|
||||
void prepare_fee(account_id_type account_id, asset fee);
|
||||
/// Pays the fee and returns the number of CORE asset that were paid.
|
||||
void pay_fee();
|
||||
|
||||
bool verify_authority( const account_object&, authority::classification );
|
||||
//bool verify_signature( const key_object& );
|
||||
bool verify_authority(const account_object&, authority::classification);
|
||||
|
||||
object_id_type get_relative_id( object_id_type rel_id )const;
|
||||
object_id_type get_relative_id( object_id_type rel_id )const;
|
||||
|
||||
void check_relative_ids(const authority& a)const;
|
||||
authority resolve_relative_ids( const authority& a )const;
|
||||
void check_relative_ids(const authority& a)const;
|
||||
authority resolve_relative_ids( const authority& a )const;
|
||||
|
||||
asset fee_from_account;
|
||||
share_type core_fee_paid;
|
||||
const account_object* fee_paying_account = nullptr;
|
||||
const account_statistics_object* fee_paying_account_statistics = nullptr;
|
||||
const asset_object* fee_asset = nullptr;
|
||||
const asset_dynamic_data_object* fee_asset_dyn_data = nullptr;
|
||||
transaction_evaluation_state* trx_state;
|
||||
asset fee_from_account;
|
||||
share_type core_fee_paid;
|
||||
const account_object* fee_paying_account = nullptr;
|
||||
const account_statistics_object* fee_paying_account_statistics = nullptr;
|
||||
const asset_object* fee_asset = nullptr;
|
||||
const asset_dynamic_data_object* fee_asset_dyn_data = nullptr;
|
||||
transaction_evaluation_state* trx_state;
|
||||
};
|
||||
|
||||
class op_evaluator
|
||||
{
|
||||
public:
|
||||
virtual ~op_evaluator(){}
|
||||
virtual operation_result evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply ) = 0;
|
||||
public:
|
||||
virtual ~op_evaluator(){}
|
||||
virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply) = 0;
|
||||
|
||||
vector< evaluation_observer* > eval_observers;
|
||||
vector<evaluation_observer*> eval_observers;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class op_evaluator_impl : public op_evaluator
|
||||
{
|
||||
public:
|
||||
virtual operation_result evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply = true ) override
|
||||
public:
|
||||
virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply = true) override
|
||||
{
|
||||
// fc::exception from observers are suppressed.
|
||||
// fc::exception from evaluation is deferred (re-thrown
|
||||
// after all observers receive evaluation_failed)
|
||||
|
||||
T eval;
|
||||
optional< fc::exception > evaluation_exception;
|
||||
size_t observer_count = 0;
|
||||
operation_result result;
|
||||
|
||||
for( const auto& obs : eval_observers )
|
||||
{
|
||||
// fc::exception from observers are suppressed.
|
||||
// fc::exception from evaluation is deferred (re-thrown
|
||||
// after all observers receive evaluation_failed)
|
||||
|
||||
T eval;
|
||||
optional< fc::exception > evaluation_exception;
|
||||
size_t observer_count = 0;
|
||||
operation_result result;
|
||||
|
||||
for( const auto& obs : eval_observers )
|
||||
{
|
||||
try
|
||||
{
|
||||
obs->pre_evaluate( eval_state, op, apply, &eval );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "suppressed exception in observer pre method:\n${e}", ( "e", e.to_detail_string() ) );
|
||||
}
|
||||
observer_count++;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = eval.start_evaluate( eval_state, op, apply );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
evaluation_exception = e;
|
||||
}
|
||||
|
||||
while( observer_count > 0 )
|
||||
{
|
||||
--observer_count;
|
||||
const auto& obs = eval_observers[ observer_count ];
|
||||
try
|
||||
{
|
||||
if( !evaluation_exception.valid() )
|
||||
obs->post_evaluate( eval_state, op, apply, &eval, result );
|
||||
else
|
||||
obs->evaluation_failed( eval_state, op, apply, &eval, result );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "suppressed exception in observer post method:\n${e}", ( "e", e.to_detail_string() ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( evaluation_exception.valid() )
|
||||
throw *evaluation_exception;
|
||||
return result;
|
||||
try
|
||||
{
|
||||
obs->pre_evaluate(eval_state, op, apply, &eval);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "suppressed exception in observer pre method:\n${e}", ( "e", e.to_detail_string() ) );
|
||||
}
|
||||
observer_count++;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = eval.start_evaluate(eval_state, op, apply);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
evaluation_exception = e;
|
||||
}
|
||||
|
||||
while( observer_count > 0 )
|
||||
{
|
||||
--observer_count;
|
||||
const auto& obs = eval_observers[observer_count];
|
||||
try
|
||||
{
|
||||
if( !evaluation_exception.valid() )
|
||||
obs->post_evaluate(eval_state, op, apply, &eval, result);
|
||||
else
|
||||
obs->evaluation_failed(eval_state, op, apply, &eval, result);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "suppressed exception in observer post method:\n${e}", ( "e", e.to_detail_string() ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( evaluation_exception.valid() )
|
||||
throw *evaluation_exception;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DerivedEvaluator>
|
||||
class evaluator : public generic_evaluator
|
||||
{
|
||||
public:
|
||||
virtual int get_type()const override { return operation::tag<typename DerivedEvaluator::operation_type>::value; }
|
||||
public:
|
||||
virtual int get_type()const override { return operation::tag<typename DerivedEvaluator::operation_type>::value; }
|
||||
|
||||
virtual operation_result evaluate( const operation& o ) final override
|
||||
{
|
||||
auto* eval = static_cast<DerivedEvaluator*>(this);
|
||||
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
|
||||
virtual operation_result evaluate(const operation& o) final override
|
||||
{
|
||||
auto* eval = static_cast<DerivedEvaluator*>(this);
|
||||
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
|
||||
|
||||
prepare_fee(op.fee_payer(), op.fee);
|
||||
FC_ASSERT( core_fee_paid >= op.calculate_fee(db().current_fee_schedule()) );
|
||||
prepare_fee(op.fee_payer(), op.fee);
|
||||
FC_ASSERT( core_fee_paid >= op.calculate_fee(db().current_fee_schedule()) );
|
||||
|
||||
return eval->do_evaluate( op );
|
||||
}
|
||||
virtual operation_result apply( const operation& o ) final override
|
||||
{
|
||||
auto* eval = static_cast<DerivedEvaluator*>(this);
|
||||
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
|
||||
return eval->do_evaluate(op);
|
||||
}
|
||||
virtual operation_result apply(const operation& o) final override
|
||||
{
|
||||
auto* eval = static_cast<DerivedEvaluator*>(this);
|
||||
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
|
||||
|
||||
pay_fee();
|
||||
pay_fee();
|
||||
|
||||
auto result = eval->do_apply( op );
|
||||
auto result = eval->do_apply(op);
|
||||
|
||||
db().adjust_balance(op.fee_payer(), -fee_from_account);
|
||||
db().adjust_balance(op.fee_payer(), -fee_from_account);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace graphene { namespace chain {
|
|||
class fork_database
|
||||
{
|
||||
public:
|
||||
typedef vector<item_ptr> branch_type;
|
||||
typedef vector<item_ptr> branch_type;
|
||||
|
||||
fork_database();
|
||||
void reset();
|
||||
|
|
@ -81,8 +81,8 @@ namespace graphene { namespace chain {
|
|||
pair< branch_type, branch_type > fetch_branch_from( block_id_type first,
|
||||
block_id_type second )const;
|
||||
|
||||
struct block_id{};
|
||||
struct block_num{};
|
||||
struct block_id;
|
||||
struct block_num;
|
||||
typedef multi_index_container<
|
||||
item_ptr,
|
||||
indexed_by<
|
||||
|
|
|
|||
|
|
@ -130,14 +130,19 @@ namespace graphene { namespace chain {
|
|||
};
|
||||
|
||||
/**
|
||||
* This operation will claim all initial balance objects owned by any of the addresses and
|
||||
* deposit them into the deposit_to_account.
|
||||
* @brief Claim a balance in a @ref balanc_object
|
||||
*
|
||||
* This operation is used to claim the balance in a given @ref balance_object. If the balance object contains a
|
||||
* vesting balance, @ref total_claimed must be set to zero, and all available vested funds will be claimed. If the
|
||||
* object contains a non-vesting balance, @ref total_claimed must be the full balance of the object.
|
||||
*
|
||||
* This operation returns the total amount claimed.
|
||||
*/
|
||||
struct balance_claim_operation
|
||||
{
|
||||
asset fee;
|
||||
account_id_type deposit_to_account;
|
||||
flat_set<address> owners;
|
||||
balance_id_type balance_to_claim;
|
||||
asset total_claimed;
|
||||
|
||||
account_id_type fee_payer()const { return deposit_to_account; }
|
||||
|
|
@ -145,8 +150,8 @@ namespace graphene { namespace chain {
|
|||
share_type calculate_fee(const fee_schedule_type& k)const { return 0; }
|
||||
void validate()const;
|
||||
|
||||
void get_balance_delta(balance_accumulator& acc, const operation_result& result = asset())const {
|
||||
acc.adjust(fee_payer(), total_claimed);
|
||||
void get_balance_delta(balance_accumulator& acc, const operation_result& result)const {
|
||||
acc.adjust(deposit_to_account, result.get<asset>());
|
||||
acc.adjust(fee_payer(), -fee);
|
||||
}
|
||||
};
|
||||
|
|
@ -1646,7 +1651,7 @@ FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)(
|
|||
FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths) )
|
||||
|
||||
FC_REFLECT( graphene::chain::void_result, )
|
||||
FC_REFLECT( graphene::chain::balance_claim_operation, (fee)(deposit_to_account)(owners)(total_claimed) )
|
||||
FC_REFLECT( graphene::chain::balance_claim_operation, (fee)(deposit_to_account)(balance_to_claim)(total_claimed) )
|
||||
|
||||
FC_REFLECT_TYPENAME( graphene::chain::operation )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::operation_result )
|
||||
|
|
|
|||
|
|
@ -153,16 +153,8 @@ namespace graphene { namespace chain {
|
|||
|
||||
vector<signature_type> signatures;
|
||||
|
||||
// flat_map<key_id_type,signature_type> signatures;
|
||||
|
||||
/** some operations may depend only upon a signature and not
|
||||
* require account approval. This allows those extra signatures
|
||||
* to be added to the transaction.
|
||||
*/
|
||||
// flat_map<address,signature_type> extra_signatures;
|
||||
|
||||
/// Removes all operations and signatures
|
||||
void clear() { operations.clear(); signatures.clear(); /*extra_signatures.clear();*/ }
|
||||
void clear() { operations.clear(); signatures.clear(); }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,12 +34,9 @@ namespace graphene { namespace chain {
|
|||
using boost::multi_index_container;
|
||||
using namespace boost::multi_index;
|
||||
/**
|
||||
* The purpose of this object is to enable the detection
|
||||
* of duplicate transactions. When a transaction is
|
||||
* included in a block a transaction_object is
|
||||
* added. At the end of block processing all
|
||||
* transaction_objects that have expired can
|
||||
* be removed from the index.
|
||||
* The purpose of this object is to enable the detection of duplicate transactions. When a transaction is included
|
||||
* in a block a transaction_object is added. At the end of block processing all transaction_objects that have
|
||||
* expired can be removed from the index.
|
||||
*/
|
||||
class transaction_object : public abstract_object<transaction_object>
|
||||
{
|
||||
|
|
@ -52,7 +49,6 @@ namespace graphene { namespace chain {
|
|||
transaction_id_type trx_id;
|
||||
};
|
||||
|
||||
|
||||
struct by_expiration;
|
||||
struct by_id;
|
||||
struct by_trx_id;
|
||||
|
|
@ -66,7 +62,6 @@ namespace graphene { namespace chain {
|
|||
> transaction_multi_index_type;
|
||||
|
||||
typedef generic_index<transaction_object, transaction_multi_index_type> transaction_index;
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::transaction_object, (graphene::db::object), (trx)(expiration) )
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ namespace graphene { namespace chain {
|
|||
typedef object_id< protocol_ids, withdraw_permission_object_type,withdraw_permission_object> withdraw_permission_id_type;
|
||||
typedef object_id< protocol_ids, vesting_balance_object_type, vesting_balance_object> vesting_balance_id_type;
|
||||
typedef object_id< protocol_ids, worker_object_type, worker_object> worker_id_type;
|
||||
typedef object_id< protocol_ids, balance_object_type, balance_object> balance_id_type;
|
||||
typedef object_id< protocol_ids, balance_object_type, balance_object> balance_id_type;
|
||||
|
||||
typedef object_id< relative_protocol_ids, key_object_type, key_object> relative_key_id_type;
|
||||
typedef object_id< relative_protocol_ids, account_object_type, account_object> relative_account_id_type;
|
||||
|
|
|
|||
|
|
@ -44,24 +44,26 @@ namespace graphene { namespace chain {
|
|||
};
|
||||
|
||||
/**
|
||||
* @brief Linear vesting balance with cliff
|
||||
* @brief Linear vesting balance with cliff
|
||||
*
|
||||
* This vesting balance type is used to mimic traditional stock vesting contracts where
|
||||
* each day a certain amount vests until it is fully matured.
|
||||
* each day a certain amount vests until it is fully matured.
|
||||
*
|
||||
* @note New funds may not be added to a linear vesting balance.
|
||||
*/
|
||||
struct linear_vesting_policy
|
||||
{
|
||||
uint32_t vesting_seconds = 0; ///< must be greater than zero
|
||||
/** while coindays may accrue over time, none may be claimed before first_claim date */
|
||||
fc::time_point_sec start_claim;
|
||||
/** linear vesting may begin prior to allowing the user to actually claim the funds, this
|
||||
* can be used to create a cliff.
|
||||
*/
|
||||
fc::time_point_sec begin_date;
|
||||
share_type begin_balance; ///< same asset as balance
|
||||
share_type total_withdrawn; ///< same asset as balance
|
||||
/// No amount may be withdrawn before this time, regardless of how much has vested.
|
||||
fc::time_point_sec earliest_withdraw_time;
|
||||
/// This is the time at which funds begin vesting.
|
||||
/// Note that withdrawals are still not available until @ref earliest_withdraw_time
|
||||
fc::time_point_sec begin_date;
|
||||
/// Duration of vesting period, in seconds. Must be greater than zero.
|
||||
uint32_t vesting_seconds = 0;
|
||||
/// The total amount of asset to vest
|
||||
share_type begin_balance;
|
||||
/// The total amount of asset which has already been withdrawn
|
||||
share_type total_withdrawn;
|
||||
|
||||
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
|
||||
bool is_deposit_allowed(const vesting_policy_context& ctx)const;
|
||||
|
|
@ -73,20 +75,19 @@ namespace graphene { namespace chain {
|
|||
void on_withdraw(const vesting_policy_context& ctx);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief defines vesting in terms of coin-days accrued which allows for dynamic deposit/withdraw
|
||||
*
|
||||
* The economic effect of this vesting policy is to require a certain amount of "interest" to accrue
|
||||
* before the full balance may be withdrawn. Interest accrues as coindays (balance * length held). If
|
||||
* some of the balance is withdrawn, the remaining balance must be held longer.
|
||||
* some of the balance is withdrawn, the remaining balance must be held longer.
|
||||
*/
|
||||
struct cdd_vesting_policy
|
||||
{
|
||||
uint32_t vesting_seconds = 0;
|
||||
fc::uint128_t coin_seconds_earned;
|
||||
/** while coindays may accrue over time, none may be claimed before first_claim date */
|
||||
fc::time_point_sec start_claim;
|
||||
fc::time_point_sec start_claim;
|
||||
fc::time_point_sec coin_seconds_earned_last_update;
|
||||
|
||||
/**
|
||||
|
|
@ -117,7 +118,6 @@ namespace graphene { namespace chain {
|
|||
cdd_vesting_policy
|
||||
> vesting_policy;
|
||||
|
||||
|
||||
/**
|
||||
* Vesting balance object is a balance that is locked by the blockchain for a period of time.
|
||||
*/
|
||||
|
|
@ -127,15 +127,17 @@ namespace graphene { namespace chain {
|
|||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = vesting_balance_object_type;
|
||||
|
||||
account_id_type owner;
|
||||
asset balance;
|
||||
vesting_policy policy;
|
||||
/// Account which owns and may withdraw from this vesting balance
|
||||
account_id_type owner;
|
||||
/// Total amount remaining in this vesting balance
|
||||
/// Includes the unvested funds, and the vested funds which have not yet been withdrawn
|
||||
asset balance;
|
||||
/// The vesting policy stores details on when funds vest, and controls when they may be withdrawn
|
||||
vesting_policy policy;
|
||||
|
||||
vesting_balance_object() {}
|
||||
|
||||
/**
|
||||
* Used to increase existing vesting balances.
|
||||
*/
|
||||
///@brief Deposit amount into vesting balance, requiring it to vest before withdrawal
|
||||
void deposit(const fc::time_point_sec& now, const asset& amount);
|
||||
bool is_deposit_allowed(const fc::time_point_sec& now, const asset& amount)const;
|
||||
|
||||
|
|
@ -144,12 +146,12 @@ namespace graphene { namespace chain {
|
|||
bool is_deposit_vested_allowed(const fc::time_point_sec& now, const asset& amount)const;
|
||||
|
||||
/**
|
||||
* Used to remove a vesting balance from the VBO. As well
|
||||
* as the balance field, coin_seconds_earned and
|
||||
* Used to remove a vesting balance from the VBO. As well as the
|
||||
* balance field, coin_seconds_earned and
|
||||
* coin_seconds_earned_last_update fields are updated.
|
||||
*
|
||||
* The money doesn't "go" anywhere; the caller is responsible
|
||||
* for crediting it to the proper account.
|
||||
* The money doesn't "go" anywhere; the caller is responsible for
|
||||
* crediting it to the proper account.
|
||||
*/
|
||||
void withdraw(const fc::time_point_sec& now, const asset& amount);
|
||||
bool is_withdraw_allowed(const fc::time_point_sec& now, const asset& amount)const;
|
||||
|
|
@ -158,9 +160,9 @@ namespace graphene { namespace chain {
|
|||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT(graphene::chain::linear_vesting_policy,
|
||||
(vesting_seconds)
|
||||
(start_claim)
|
||||
(earliest_withdraw_time)
|
||||
(begin_date)
|
||||
(vesting_seconds)
|
||||
(begin_balance)
|
||||
(total_withdrawn)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -939,8 +939,6 @@ void balance_claim_operation::get_required_auth(flat_set<account_id_type>& acti
|
|||
|
||||
void balance_claim_operation::validate()const
|
||||
{
|
||||
FC_ASSERT( owners.size() > 0 );
|
||||
FC_ASSERT( total_claimed.amount > 0 );
|
||||
FC_ASSERT( fee == asset() );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ struct init_policy_visitor
|
|||
linear_vesting_policy policy;
|
||||
policy.vesting_seconds = i.vesting_seconds;
|
||||
policy.begin_date = i.begin_date;
|
||||
policy.start_claim = i.start_claim;
|
||||
policy.earliest_withdraw_time = i.start_claim;
|
||||
policy.begin_balance = init_balance;
|
||||
p = policy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@ inline bool sum_below_max_shares(const asset& a, const asset& b)
|
|||
assert(GRAPHENE_MAX_SHARE_SUPPLY + GRAPHENE_MAX_SHARE_SUPPLY > GRAPHENE_MAX_SHARE_SUPPLY);
|
||||
return (a.amount <= GRAPHENE_MAX_SHARE_SUPPLY)
|
||||
&& ( b.amount <= GRAPHENE_MAX_SHARE_SUPPLY)
|
||||
&& ((a.amount + b.amount) <= GRAPHENE_MAX_SHARE_SUPPLY)
|
||||
;
|
||||
&& ((a.amount + b.amount) <= GRAPHENE_MAX_SHARE_SUPPLY);
|
||||
}
|
||||
|
||||
asset linear_vesting_policy::get_allowed_withdraw(const vesting_policy_context& ctx) const
|
||||
{
|
||||
if(ctx.now <= start_claim)
|
||||
if(ctx.now <= earliest_withdraw_time)
|
||||
return asset(0, ctx.balance.asset_id);
|
||||
if(ctx.now <= begin_date)
|
||||
return asset(0, ctx.balance.asset_id);
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ public:
|
|||
{
|
||||
// Right now the wallet_api has no way of knowing if the connection to the
|
||||
// witness has already disconnected (via the witness node exiting first).
|
||||
// If it has exited, cancel_all_subscriptsions() will throw and there's
|
||||
// If it has exited, cancel_all_subscriptsions() will throw and there's
|
||||
// nothing we can do about it.
|
||||
// dlog("Caught exception ${e} while canceling database subscriptions", ("e", e));
|
||||
}
|
||||
|
|
@ -892,7 +892,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (symbol)(new_issuer)(new_options)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction update_bitasset(string symbol,
|
||||
asset_object::bitasset_options new_options,
|
||||
bool broadcast /* = false */)
|
||||
|
|
@ -913,7 +913,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (symbol)(new_options)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction update_asset_feed_producers(string symbol,
|
||||
flat_set<string> new_feed_producers,
|
||||
bool broadcast /* = false */)
|
||||
|
|
@ -959,7 +959,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (publishing_account)(symbol)(feed)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction fund_asset_fee_pool(string from,
|
||||
string symbol,
|
||||
string amount,
|
||||
|
|
@ -983,7 +983,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (from)(symbol)(amount)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction burn_asset(string from,
|
||||
string amount,
|
||||
string symbol,
|
||||
|
|
@ -1005,7 +1005,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (from)(amount)(symbol)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction global_settle_asset(string symbol,
|
||||
price settle_price,
|
||||
bool broadcast /* = false */)
|
||||
|
|
@ -1065,7 +1065,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (authorizing_account)(account_to_list)(new_listing_status)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction create_delegate(string owner_account,
|
||||
bool broadcast /* = false */)
|
||||
{ try {
|
||||
|
|
@ -1133,7 +1133,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (voting_account)(delegate)(approve)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction vote_for_witness(string voting_account,
|
||||
string witness,
|
||||
bool approve,
|
||||
|
|
@ -1167,7 +1167,7 @@ public:
|
|||
|
||||
return sign_transaction( tx, broadcast );
|
||||
} FC_CAPTURE_AND_RETHROW( (voting_account)(witness)(approve)(broadcast) ) }
|
||||
|
||||
|
||||
signed_transaction set_voting_proxy(string account_to_modify,
|
||||
optional<string> voting_account,
|
||||
bool broadcast /* = false */)
|
||||
|
|
@ -1186,7 +1186,7 @@ public:
|
|||
FC_THROW("Account ${account} is already voting for itself", ("account", account_to_modify));
|
||||
account_object_to_modify.options.voting_account = account_id_type();
|
||||
}
|
||||
|
||||
|
||||
account_update_operation account_update_op;
|
||||
account_update_op.account = account_object_to_modify.id;
|
||||
account_update_op.new_options = account_object_to_modify.options;
|
||||
|
|
@ -1849,7 +1849,7 @@ signed_transaction wallet_api::update_asset(string symbol,
|
|||
{
|
||||
return my->update_asset(symbol, new_issuer, new_options, broadcast);
|
||||
}
|
||||
|
||||
|
||||
signed_transaction wallet_api::update_bitasset(string symbol,
|
||||
asset_object::bitasset_options new_options,
|
||||
bool broadcast /* = false */)
|
||||
|
|
@ -1937,7 +1937,7 @@ signed_transaction wallet_api::vote_for_witness(string voting_account,
|
|||
bool broadcast /* = false */)
|
||||
{
|
||||
return my->vote_for_witness(voting_account, witness, approve, broadcast);
|
||||
}
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::set_voting_proxy(string account_to_modify,
|
||||
optional<string> voting_account,
|
||||
|
|
@ -2148,18 +2148,17 @@ signed_transaction wallet_api::import_balance( string name_or_id, const vector<s
|
|||
for( auto a : bal_types )
|
||||
{
|
||||
balance_claim_operation op;
|
||||
op.total_claimed = asset( 0, a );
|
||||
for( auto b : balances )
|
||||
op.deposit_to_account = claimer.id;
|
||||
for( const auto& b : balances )
|
||||
{
|
||||
if( b.balance.asset_id == a )
|
||||
{
|
||||
op.total_claimed += b.balance;
|
||||
op.owners.insert( b.owner );
|
||||
op.deposit_to_account = claimer.id;
|
||||
required_addrs.insert( b.owner );
|
||||
op.total_claimed = b.vesting_policy.valid()? asset(0, b.balance.asset_id) : b.balance;
|
||||
op.balance_to_claim = b.id;
|
||||
trx.operations.push_back(op);
|
||||
required_addrs.insert(b.owner);
|
||||
}
|
||||
}
|
||||
trx.operations.push_back(op);
|
||||
}
|
||||
|
||||
trx.visit( operation_set_fee( my->_remote_db->get_global_properties().parameters.current_fees ) );
|
||||
|
|
@ -2170,7 +2169,7 @@ signed_transaction wallet_api::import_balance( string name_or_id, const vector<s
|
|||
for( auto a : required_addrs )
|
||||
tx.sign( keys[a] );
|
||||
|
||||
if( broadcast )
|
||||
if( broadcast )
|
||||
my->_remote_net->broadcast_transaction(tx);
|
||||
|
||||
return tx;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <graphene/chain/call_order_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/balance_object.hpp>
|
||||
#include <graphene/chain/block.hpp>
|
||||
#include <iostream>
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,10 @@ database_fixture::database_fixture()
|
|||
for( int i = 0; i < 10; ++i )
|
||||
{
|
||||
auto name = "init"+fc::to_string(i);
|
||||
genesis_state.initial_accounts.emplace_back(name, delegate_priv_key.get_public_key(), true);
|
||||
genesis_state.initial_accounts.emplace_back(name,
|
||||
delegate_priv_key.get_public_key(),
|
||||
delegate_priv_key.get_public_key(),
|
||||
true);
|
||||
genesis_state.initial_committee.push_back({name});
|
||||
genesis_state.initial_witnesses.push_back({name, delegate_priv_key.get_public_key(), secret});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ genesis_state_type make_genesis() {
|
|||
for( int i = 0; i < 10; ++i )
|
||||
{
|
||||
auto name = "init"+fc::to_string(i);
|
||||
genesis_state.initial_accounts.emplace_back(name, delegate_priv_key.get_public_key(), true);
|
||||
genesis_state.initial_accounts.emplace_back(name,
|
||||
delegate_priv_key.get_public_key(),
|
||||
delegate_priv_key.get_public_key(),
|
||||
true);
|
||||
genesis_state.initial_committee.push_back({name});
|
||||
genesis_state.initial_witnesses.push_back({name, delegate_priv_key.get_public_key(), secret});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -981,31 +981,32 @@ BOOST_AUTO_TEST_CASE( balance_object_test )
|
|||
fc::temp_directory td;
|
||||
genesis_state.initial_balances.push_back({generate_private_key("n").get_public_key(), GRAPHENE_SYMBOL, 1});
|
||||
genesis_state.initial_balances.push_back({generate_private_key("x").get_public_key(), GRAPHENE_SYMBOL, 1});
|
||||
genesis_state.initial_accounts.emplace_back("n", generate_private_key("n").get_public_key(), false);
|
||||
// TODO: vesting genesis balances
|
||||
genesis_state.initial_accounts.emplace_back("n", generate_private_key("n").get_public_key());
|
||||
|
||||
db.open(td.path(), genesis_state);
|
||||
const balance_object& balance = *db.get_index_type<balance_index>().indices().find(balance_id_type());
|
||||
const balance_object& balance = balance_id_type()(db);
|
||||
BOOST_CHECK_EQUAL(balance.balance.amount.value, 1);
|
||||
BOOST_CHECK_EQUAL(db.get_index_type<balance_index>().indices().find(balance_id_type(1))->balance.amount.value, 1);
|
||||
BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1);
|
||||
|
||||
balance_claim_operation op;
|
||||
op.deposit_to_account = db.get_index_type<account_index>().indices().get<by_name>().find("n")->get_id();
|
||||
op.total_claimed = asset(1);
|
||||
op.owners.insert(genesis_state.initial_balances.back().owner);
|
||||
op.balance_to_claim = balance_id_type(1);
|
||||
trx.operations = {op};
|
||||
trx.sign(generate_private_key("n"));
|
||||
//trx.sign(generate_private_key("n"));
|
||||
// Fail because I'm claiming the wrong address
|
||||
// Fail because I'm claiming from an address which hasn't signed
|
||||
BOOST_CHECK_THROW(db.push_transaction(trx), fc::exception);
|
||||
trx.clear();
|
||||
op.owners = {genesis_state.initial_balances.front().owner};
|
||||
op.balance_to_claim = balance_id_type();
|
||||
trx.operations = {op};
|
||||
trx.sign(generate_private_key("n"));
|
||||
//trx.sign(generate_private_key("n"));
|
||||
db.push_transaction(trx);
|
||||
|
||||
// Not using fixture's get_balance() here because it uses fixture's db, not my override
|
||||
BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 1);
|
||||
BOOST_CHECK(db.find_object(balance_id_type()) == nullptr);
|
||||
BOOST_CHECK(db.find_object(balance_id_type(1)) != nullptr);
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
// TODO: Write linear VBO tests
|
||||
|
|
|
|||
Loading…
Reference in a new issue