Refactored chain library

- remove circular dependency with fee_schedule
- unitiy build db_* as database.cpp
- move protocol definitions in separate directory
- combined some objects/evaluators
- combined limit/call evaluator/objects into market_evaluator.*
This commit is contained in:
Daniel Larimer 2015-07-08 16:39:23 -04:00
parent 90e04d0290
commit baf5531238
103 changed files with 3440 additions and 3648 deletions

View file

@ -2,19 +2,28 @@ file(GLOB HEADERS "include/graphene/chain/*.hpp")
## SORT .cpp by most likely to change / break compile
add_library( graphene_chain
types.cpp
type_id.cpp
protocol/types.cpp
protocol/address.cpp
protocol/asset.cpp
protocol/account.cpp
protocol/transfer.cpp
protocol/delegate.cpp
protocol/witness.cpp
protocol/market.cpp
protocol/proposal.cpp
protocol/withdraw_permission.cpp
protocol/asset_ops.cpp
protocol/memo.cpp
protocol/worker.cpp
protocol/custom.cpp
protocol/operations.cpp
protocol/transaction.cpp
protocol/block.cpp
address.cpp
pts_address.cpp
asset.cpp
predicate.cpp
operations.cpp
evaluator.cpp
balance_evaluator.cpp
global_parameters_evaluator.cpp
account_evaluator.cpp
assert_evaluator.cpp
witness_evaluator.cpp
@ -22,8 +31,7 @@ add_library( graphene_chain
asset_evaluator.cpp
transfer_evaluator.cpp
proposal_evaluator.cpp
call_order_evaluator.cpp
limit_order_evaluator.cpp
market_evaluator.cpp
vesting_balance_evaluator.cpp
withdraw_permission_evaluator.cpp
worker_evaluator.cpp
@ -32,25 +40,23 @@ add_library( graphene_chain
asset_object.cpp
proposal_object.cpp
vesting_balance_object.cpp
worker_object.cpp
transaction.cpp
block.cpp
transaction_evaluation_state.cpp
fork_database.cpp
block_database.cpp
db_balance.cpp
db_block.cpp
db_debug.cpp
db_getter.cpp
db_init.cpp
db_maint.cpp
db_management.cpp
db_market.cpp
db_update.cpp
db_witness_schedule.cpp
database.cpp
# db_balance.cpp
# db_block.cpp
# db_debug.cpp
# db_getter.cpp
# db_init.cpp
# db_maint.cpp
# db_management.cpp
# db_market.cpp
# db_update.cpp
# db_witness_schedule.cpp
${HEADERS}
)

View file

@ -87,11 +87,14 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
db().modify(dynamic_properties, [](dynamic_global_property_object& p) {
++p.accounts_registered_this_interval;
});
/** TODO: update fee scaling for account creation...
if( dynamic_properties.accounts_registered_this_interval %
global_properties.parameters.accounts_per_fee_scale == 0 )
db().modify(global_properties, [&dynamic_properties](global_property_object& p) {
p.parameters.current_fees.account_create_fee <<= p.parameters.account_fee_scale_bitshifts;
});
*/
return new_acnt_object.id;
} FC_CAPTURE_AND_RETHROW((o)) }

View file

@ -18,7 +18,6 @@
#include <graphene/chain/assert_evaluator.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/predicate.hpp>
#include <sstream>
@ -26,15 +25,18 @@ namespace graphene { namespace chain {
struct predicate_evaluator
{
typedef bool result_type;
typedef void result_type;
const database& db;
predicate_evaluator( const database& d ):db(d){}
template< typename T >
bool operator()( const T& p )const
void operator()( const account_name_eq_lit_predicate& p )const
{
return p.evaluate( db );
FC_ASSERT( p.account_id(db).name == p.name );
}
void operator()( const asset_symbol_eq_lit_predicate& p )const
{
FC_ASSERT( p.asset_id(db).symbol == p.symbol );
}
};
@ -47,20 +49,11 @@ void_result assert_evaluator::do_evaluate( const assert_operation& o )
if( skip & database::skip_assert_evaluation )
return void_result();
for( const vector<char>& pdata : o.predicates )
for( const auto& p : o.predicates )
{
fc::datastream<const char*> ds( pdata.data(), pdata.size() );
predicate p;
//
// FC_ASSERT deep in the bowels of static_variant implementation
// will trip if we get a predicate which isn't in our code's
// static_variant. This is desired behavior.
//
fc::raw::unpack( ds, p );
FC_ASSERT( p.which() >= 0 );
FC_ASSERT( unsigned(p.which()) < max_predicate_opcode );
FC_ASSERT( p.visit( predicate_evaluator( _db ) ) );
p.visit( predicate_evaluator( _db ) );
}
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }

View file

@ -18,7 +18,7 @@
#include <graphene/chain/asset_evaluator.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/database.hpp>
#include <functional>
@ -42,8 +42,7 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o
auto asset_symbol_itr = asset_indx.find( op.symbol );
FC_ASSERT( asset_symbol_itr == asset_indx.end() );
core_fee_paid -= op.calculate_fee(d.current_fee_schedule()).value/2;
assert( core_fee_paid >= 0 );
core_fee_paid -= core_fee_paid.value/2;
if( op.bitasset_options )
{
@ -76,7 +75,7 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o
const asset_dynamic_data_object& dyn_asset =
db().create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
a.current_supply = 0;
a.fee_pool = op.calculate_fee(db().current_fee_schedule()).value / 2;
a.fee_pool = core_fee_paid; //op.calculate_fee(db().current_fee_schedule()).value / 2;
});
asset_bitasset_data_id_type bit_asset_id;

View file

@ -17,7 +17,6 @@
*/
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <fc/uint128.hpp>
@ -83,40 +82,7 @@ void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point
current_feed = median_feed;
}
void asset_object::asset_options::validate()const
{
FC_ASSERT( max_supply > 0 );
FC_ASSERT( max_supply <= GRAPHENE_MAX_SHARE_SUPPLY );
FC_ASSERT( market_fee_percent <= GRAPHENE_100_PERCENT );
FC_ASSERT( max_market_fee >= 0 && max_market_fee <= GRAPHENE_MAX_SHARE_SUPPLY );
// There must be no high bits in permissions whose meaning is not known.
FC_ASSERT( !(issuer_permissions & ~ASSET_ISSUER_PERMISSION_MASK) );
// There must be no high bits in flags which are not also high in permissions.
FC_ASSERT( !(flags & ~issuer_permissions ) );
// The global_settle flag may never be set (this is a permission only)
FC_ASSERT( !(flags & global_settle) );
core_exchange_rate.validate();
FC_ASSERT( core_exchange_rate.base.asset_id.instance.value == 0 ||
core_exchange_rate.quote.asset_id.instance.value == 0 );
if(!whitelist_authorities.empty() || !blacklist_authorities.empty())
FC_ASSERT( flags & white_list );
for( auto item : whitelist_markets )
{
FC_ASSERT( blacklist_markets.find(item) == blacklist_markets.end() );
}
for( auto item : blacklist_markets )
{
FC_ASSERT( whitelist_markets.find(item) == whitelist_markets.end() );
}
}
void asset_object::bitasset_options::validate() const
{
FC_ASSERT(minimum_feeds > 0);
FC_ASSERT(force_settlement_offset_percent <= GRAPHENE_100_PERCENT);
FC_ASSERT(maximum_force_settlement_volume <= GRAPHENE_100_PERCENT);
}
asset asset_object::amount_from_string(string amount_string) const
{ try {

View file

@ -16,6 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/block_database.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/io/raw.hpp>
namespace graphene { namespace chain {

View file

@ -0,0 +1,11 @@
/// This file combines these sources to perform a partial unity build
#include "db_balance.cpp"
#include "db_block.cpp"
#include "db_debug.cpp"
#include "db_getter.cpp"
#include "db_init.cpp"
#include "db_maint.cpp"
#include "db_management.cpp"
#include "db_market.cpp"
#include "db_update.cpp"
#include "db_witness_schedule.cpp"

View file

@ -24,6 +24,7 @@
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
namespace graphene { namespace chain {

View file

@ -20,8 +20,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/witness_object.hpp>

View file

@ -38,7 +38,7 @@ const dynamic_global_property_object&database::get_dynamic_global_properties() c
return get( dynamic_global_property_id_type() );
}
const fee_schedule_type& database::current_fee_schedule()const
const fee_schedule& database::current_fee_schedule()const
{
return get_global_properties().parameters.current_fees;
}

View file

@ -24,25 +24,20 @@
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/balance_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/worker_object.hpp>
#include <graphene/chain/account_evaluator.hpp>
#include <graphene/chain/asset_evaluator.hpp>
#include <graphene/chain/assert_evaluator.hpp>
#include <graphene/chain/custom_evaluator.hpp>
#include <graphene/chain/delegate_evaluator.hpp>
#include <graphene/chain/global_parameters_evaluator.hpp>
#include <graphene/chain/limit_order_evaluator.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/proposal_evaluator.hpp>
#include <graphene/chain/call_order_evaluator.hpp>
#include <graphene/chain/transfer_evaluator.hpp>
#include <graphene/chain/vesting_balance_evaluator.hpp>
#include <graphene/chain/withdraw_permission_evaluator.hpp>
@ -50,6 +45,8 @@
#include <graphene/chain/worker_evaluator.hpp>
#include <graphene/chain/balance_evaluator.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/uint128.hpp>
#include <fc/crypto/digest.hpp>
@ -57,6 +54,64 @@
namespace graphene { namespace chain {
// C++ requires that static class variables declared and initialized
// in headers must also have a definition in a single source file,
// else linker errors will occur [1].
//
// The purpose of this source file is to collect such definitions in
// a single place.
//
// [1] http://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char
const uint8_t account_object::space_id;
const uint8_t account_object::type_id;
const uint8_t asset_object::space_id;
const uint8_t asset_object::type_id;
const uint8_t block_summary_object::space_id;
const uint8_t block_summary_object::type_id;
const uint8_t call_order_object::space_id;
const uint8_t call_order_object::type_id;
const uint8_t delegate_object::space_id;
const uint8_t delegate_object::type_id;
const uint8_t force_settlement_object::space_id;
const uint8_t force_settlement_object::type_id;
const uint8_t global_property_object::space_id;
const uint8_t global_property_object::type_id;
const uint8_t limit_order_object::space_id;
const uint8_t limit_order_object::type_id;
const uint8_t operation_history_object::space_id;
const uint8_t operation_history_object::type_id;
const uint8_t proposal_object::space_id;
const uint8_t proposal_object::type_id;
const uint8_t transaction_object::space_id;
const uint8_t transaction_object::type_id;
const uint8_t vesting_balance_object::space_id;
const uint8_t vesting_balance_object::type_id;
const uint8_t withdraw_permission_object::space_id;
const uint8_t withdraw_permission_object::type_id;
const uint8_t witness_object::space_id;
const uint8_t witness_object::type_id;
const uint8_t witness_schedule_object::space_id;
const uint8_t witness_schedule_object::type_id;
const uint8_t worker_object::space_id;
const uint8_t worker_object::type_id;
void database::initialize_evaluators()
{
_operation_evaluators.resize(255);
@ -65,6 +120,7 @@ void database::initialize_evaluators()
register_evaluator<account_upgrade_evaluator>();
register_evaluator<account_whitelist_evaluator>();
register_evaluator<delegate_create_evaluator>();
register_evaluator<delegate_update_global_parameters_evaluator>();
register_evaluator<custom_evaluator>();
register_evaluator<asset_create_evaluator>();
register_evaluator<asset_issue_evaluator>();
@ -85,7 +141,6 @@ void database::initialize_evaluators()
register_evaluator<proposal_create_evaluator>();
register_evaluator<proposal_update_evaluator>();
register_evaluator<proposal_delete_evaluator>();
register_evaluator<global_parameters_update_evaluator>();
register_evaluator<witness_create_evaluator>();
register_evaluator<witness_withdraw_pay_evaluator>();
register_evaluator<vesting_balance_create_evaluator>();
@ -242,7 +297,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
p.parameters = genesis_state.initial_parameters;
// Set fees to zero initially, so that genesis initialization needs not pay them
// We'll fix it at the end of the function
p.parameters.current_fees.set_all_fees(0);
p.parameters.current_fees->set_all_fees(0);
});
create<dynamic_global_property_object>( [&](dynamic_global_property_object& p) {

View file

@ -25,7 +25,7 @@
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/worker_object.hpp>
#include <graphene/chain/worker_evaluator.hpp>
#include <fc/uint128.hpp>
@ -59,6 +59,25 @@ void database::perform_account_maintenance(std::tuple<Types...> helpers)
detail::for_each(helpers, a, detail::gen_seq<sizeof...(Types)>());
}
/// @brief A visitor for @ref worker_type which calls pay_worker on the worker within
struct worker_pay_visitor
{
private:
share_type pay;
database& db;
public:
worker_pay_visitor(share_type pay, database& db)
: pay(pay), db(db) {}
typedef void result_type;
template<typename W>
void operator()(W& worker)const
{
worker.pay_worker(pay, db);
}
};
void database::pay_workers( share_type& budget )
{
// ilog("Processing payroll! Available budget is ${b}", ("b", budget));
@ -436,9 +455,12 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
modify(gpo, [this](global_property_object& p) {
// Remove scaling of account registration fee
/*
/// TODO reimplement this
const auto& dgpo = get_dynamic_global_properties();
p.parameters.current_fees.account_create_fee >>= p.parameters.account_fee_scale_bitshifts *
(dgpo.accounts_registered_this_interval / p.parameters.accounts_per_fee_scale);
*/
if( p.pending_parameters )
{

View file

@ -19,6 +19,7 @@
#include <graphene/chain/database.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
namespace graphene { namespace chain {

View file

@ -20,8 +20,7 @@
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <fc/uint128.hpp>
@ -248,7 +247,7 @@ bool database::fill_order( const limit_order_object& order, const asset& pays, c
pay_order( seller, receives - issuer_fees, pays );
assert( pays.asset_id != receives.asset_id );
push_applied_operation( fill_order_operation{ order.id, order.seller, pays, receives, issuer_fees } );
push_applied_operation( fill_order_operation( order.id, order.seller, pays, receives, issuer_fees ) );
if( pays == order.amount_for_sale() )
{

View file

@ -20,12 +20,12 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/uint128.hpp>

View file

@ -19,6 +19,8 @@
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <graphene/chain/transaction_evaluation_state.hpp>
namespace graphene { namespace chain {
@ -43,4 +45,22 @@ object_id_type delegate_create_evaluator::do_apply( const delegate_create_operat
return new_del_object.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result delegate_update_global_parameters_evaluator::do_evaluate(const delegate_update_global_parameters_operation& o)
{ try {
FC_ASSERT(trx_state->_is_proposed_trx);
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result delegate_update_global_parameters_evaluator::do_apply(const delegate_update_global_parameters_operation& o)
{ try {
db().modify(db().get_global_properties(), [&o](global_property_object& p) {
p.pending_parameters = o.new_parameters;
});
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
} } // graphene::chain

View file

@ -21,8 +21,8 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/uint128.hpp>
@ -85,9 +85,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
flat_set<account_id_type> owner_auths;
vector<authority> other_auths;
operation_get_required_active_authorities( op, active_auths );
operation_get_required_owner_authorities( op, owner_auths );
operation_get_required_authorities( op, other_auths );
operation_get_required_authorities( op, active_auths, owner_auths, other_auths );
for( auto id : active_auths )
FC_ASSERT(verify_authority(id(db()), authority::active) ||

View file

@ -1,40 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/global_parameters_evaluator.hpp>
#include <graphene/chain/transaction_evaluation_state.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {
void_result global_parameters_update_evaluator::do_evaluate(const global_parameters_update_operation& o)
{ try {
FC_ASSERT(trx_state->_is_proposed_trx);
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result global_parameters_update_evaluator::do_apply(const global_parameters_update_operation& o)
{ try {
db().modify(db().get_global_properties(), [&o](global_property_object& p) {
p.pending_parameters = o.new_parameters;
});
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
} } // graphene::chain

View file

@ -16,14 +16,12 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/authority.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/db/generic_index.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <graphene/chain/operations.hpp>
namespace graphene { namespace chain {
class database;
class database;
/**
* @class account_statistics_object

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/protocol/asset_ops.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/db/flat_index.hpp>
#include <graphene/db/generic_index.hpp>
@ -116,86 +116,8 @@ namespace graphene { namespace chain {
/// ID of the account which issued this asset.
account_id_type issuer;
/**
* @brief The asset_options struct contains options available on all assets in the network
*
* @note Changes to this struct will break protocol compatibility
*/
struct asset_options {
/// The maximum supply of this asset which may exist at any given time. This can be as large as
/// GRAPHENE_MAX_SHARE_SUPPLY
share_type max_supply = GRAPHENE_MAX_SHARE_SUPPLY;
/// When this asset is traded on the markets, this percentage of the total traded will be exacted and paid
/// to the issuer. This is a fixed point value, representing hundredths of a percent, i.e. a value of 100
/// in this field means a 1% fee is charged on market trades of this asset.
uint16_t market_fee_percent = 0;
/// Market fees calculated as @ref market_fee_percent of the traded volume are capped to this value
share_type max_market_fee = GRAPHENE_MAX_SHARE_SUPPLY;
asset_options options;
/// The flags which the issuer has permission to update. See @ref asset_issuer_permission_flags
uint16_t issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
/// The currently active flags on this permission. See @ref asset_issuer_permission_flags
uint16_t flags = 0;
/// When a non-core asset is used to pay a fee, the blockchain must convert that asset to core asset in
/// order to accept the fee. If this asset's fee pool is funded, the chain will automatically deposite fees
/// in this asset to its accumulated fees, and withdraw from the fee pool the same amount as converted at
/// the core exchange rate.
price core_exchange_rate;
/// A set of accounts which maintain whitelists to consult for this asset. If enforce_white_list() returns
/// true, an account may only send, receive, trade, etc. in this asset if one of these accounts appears in
/// its account_object::whitelisting_accounts field.
flat_set<account_id_type> whitelist_authorities;
/// A set of accounts which maintain blacklists to consult for this asset. If enforce_white_list() returns
/// true, an account may only send, receive, trade, etc. in this asset if none of these accounts appears in
/// its account_object::blacklisting_accounts field. If the account is blacklisted, it may not transact in
/// this asset even if it is also whitelisted.
flat_set<account_id_type> blacklist_authorities;
/** defines the assets that this asset may be traded against in the market */
flat_set<asset_id_type> whitelist_markets;
/** defines the assets that this asset may not be traded against in the market, must not overlap whitelist */
flat_set<asset_id_type> blacklist_markets;
/**
* data that describes the meaning/purpose of this asset, fee will be charged proportional to
* size of description.
*/
string description;
/// Perform internal consistency checks.
/// @throws fc::exception if any check fails
void validate()const;
} options;
/**
* @brief The bitasset_options struct contains configurable options available only to BitAssets.
*
* @note Changes to this struct will break protocol compatibility
*/
struct bitasset_options {
/// Time before a price feed expires
uint32_t feed_lifetime_sec = GRAPHENE_DEFAULT_PRICE_FEED_LIFETIME;
/// Minimum number of unexpired feeds required to extract a median feed from
uint8_t minimum_feeds = 1;
/// This is the delay between the time a long requests settlement and the chain evaluates the settlement
uint32_t force_settlement_delay_sec = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY;
/// This is the percent to adjust the feed price in the short's favor in the event of a forced settlement
uint16_t force_settlement_offset_percent = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_OFFSET;
/// Force settlement volume can be limited such that only a certain percentage of the total existing supply
/// of the asset may be force-settled within any given chain maintenance interval. This field stores the
/// percentage of the current supply which may be force settled within the current maintenance interval. If
/// force settlements come due in an interval in which the maximum volume has already been settled, the new
/// settlements will be enqueued and processed at the beginning of the next maintenance interval.
uint16_t maximum_force_settlement_volume = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_MAX_VOLUME;
/// This speicifies which asset type is used to collateralize short sales
/// This field may only be updated if the current supply of the asset is zero.
asset_id_type short_backing_asset;
/// Perform internal consistency checks.
/// @throws fc::exception if any check fails
void validate()const;
};
/// Current supply, fee pool, and collected fees are stored in a separate object as they change frequently.
asset_dynamic_data_id_type dynamic_asset_data_id;
@ -243,7 +165,7 @@ namespace graphene { namespace chain {
static const uint8_t type_id = impl_asset_bitasset_data_type;
/// The tunable options for BitAssets are stored in this field.
asset_object::bitasset_options options;
bitasset_options options;
/// Feeds published for this asset. If issuer is not genesis, the keys in this map are the feed publishing
/// accounts; otherwise, the feed publishers are the currently active delegates and witnesses and this map
@ -325,28 +247,6 @@ FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db::
(settlement_fund)
)
FC_REFLECT( graphene::chain::asset_object::asset_options,
(max_supply)
(market_fee_percent)
(max_market_fee)
(issuer_permissions)
(flags)
(core_exchange_rate)
(whitelist_authorities)
(blacklist_authorities)
(whitelist_markets)
(blacklist_markets)
(description)
)
FC_REFLECT( graphene::chain::asset_object::bitasset_options,
(feed_lifetime_sec)
(minimum_feeds)
(force_settlement_delay_sec)
(force_settlement_offset_percent)
(maximum_force_settlement_volume)
(short_backing_asset)
)
FC_REFLECT_DERIVED( graphene::chain::asset_object,
(graphene::db::annotated_object<graphene::chain::asset_object>),
(symbol)

View file

@ -1,7 +1,7 @@
#pragma once
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/transaction.hpp>
#include <graphene/chain/balance_object.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/exceptions.hpp>

View file

@ -17,7 +17,7 @@
*/
#pragma once
#include <fstream>
#include <graphene/chain/block.hpp>
#include <graphene/chain/protocol/block.hpp>
namespace graphene { namespace chain {
class block_database

View file

@ -1,40 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
{
public:
typedef call_order_update_operation operation_type;
void_result do_evaluate( const call_order_update_operation& o );
void_result do_apply( const call_order_update_operation& o );
bool _closing_order = false;
const asset_object* _debt_asset = nullptr;
const account_object* _paying_account = nullptr;
const call_order_object* _order = nullptr;
const asset_bitasset_data_object* _bitasset_data = nullptr;
};
} } // graphene::chain

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {

View file

@ -17,8 +17,7 @@
*/
#pragma once
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/block.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/block.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/node_property_object.hpp>
#include <graphene/chain/account_object.hpp>
@ -227,7 +226,7 @@ namespace graphene { namespace chain {
const global_property_object& get_global_properties()const;
const dynamic_global_property_object& get_dynamic_global_properties()const;
const node_property_object& get_node_properties()const;
const fee_schedule_type& current_fee_schedule()const;
const fee_schedule& current_fee_schedule()const;
time_point_sec head_block_time()const;
uint32_t head_block_num()const;

View file

@ -30,4 +30,14 @@ namespace graphene { namespace chain {
object_id_type do_apply( const delegate_create_operation& o );
};
class delegate_update_global_parameters_evaluator : public evaluator<delegate_update_global_parameters_evaluator>
{
public:
typedef delegate_update_global_parameters_operation operation_type;
void_result do_evaluate( const delegate_update_global_parameters_operation& o );
void_result do_apply( const delegate_update_global_parameters_operation& o );
};
} } // graphene::chain

View file

@ -16,7 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>

View file

@ -16,8 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/operations.hpp>
#include <graphene/chain/authority.hpp>
#include <graphene/chain/protocol/operations.hpp>
namespace graphene { namespace chain {
@ -194,7 +193,7 @@ namespace graphene { namespace chain {
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()) );
FC_ASSERT( core_fee_paid >= db().current_fee_schedule().calculate_fee( op ).amount );
return eval->do_evaluate(op);
}

View file

@ -16,8 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/block.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/block.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>

View file

@ -1,6 +1,6 @@
#pragma once
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <string>
#include <vector>

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/evaluator.hpp>
namespace graphene { namespace chain {
class global_parameters_update_evaluator : public evaluator<global_parameters_update_evaluator>
{
public:
typedef global_parameters_update_operation operation_type;
void_result do_evaluate( const global_parameters_update_operation& o );
void_result do_apply( const global_parameters_update_operation& o );
};
} } // graphene::chain

View file

@ -16,10 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/chain_parameters.hpp>
#include <graphene/chain/protocol/chain_parameters.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/authority.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/db/object.hpp>
namespace graphene { namespace chain {

View file

@ -22,31 +22,5 @@
namespace graphene { namespace chain {
class limit_order_create_evaluator : public evaluator<limit_order_create_evaluator>
{
public:
typedef limit_order_create_operation operation_type;
void_result do_evaluate( const limit_order_create_operation& o );
object_id_type do_apply( const limit_order_create_operation& o );
asset calculate_market_fee( const asset_object* aobj, const asset& trade_amount );
const limit_order_create_operation* _op = nullptr;
const account_object* _seller = nullptr;
const asset_object* _sell_asset = nullptr;
const asset_object* _receive_asset = nullptr;
};
class limit_order_cancel_evaluator : public evaluator<limit_order_cancel_evaluator>
{
public:
typedef limit_order_cancel_operation operation_type;
void_result do_evaluate( const limit_order_cancel_operation& o );
asset do_apply( const limit_order_cancel_operation& o );
const limit_order_object* _order;
};
} } // graphene::chain

View file

@ -1,78 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/db/object.hpp>
#include <graphene/chain/authority.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/db/generic_index.hpp>
#include <boost/multi_index/composite_key.hpp>
namespace graphene { namespace chain {
using namespace graphene::db;
/**
* @brief an offer to sell a amount of a asset at a specified exchange rate by a certain time
* @ingroup object
* @ingroup protocol
* @ingroup market
*
* This limit_order_objects are indexed by @ref expiration and is automatically deleted on the first block after expiration.
*/
class limit_order_object : public abstract_object<limit_order_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = limit_order_object_type;
time_point_sec expiration;
account_id_type seller;
share_type for_sale; ///< asset id is sell_price.base.asset_id
price sell_price;
asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); }
asset amount_to_receive()const { return amount_for_sale() * sell_price; }
};
struct by_id;
struct by_price;
struct by_expiration;
typedef multi_index_container<
limit_order_object,
indexed_by<
hashed_unique< tag<by_id>,
member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_expiration>, member< limit_order_object, time_point_sec, &limit_order_object::expiration> >,
ordered_unique< tag<by_price>,
composite_key< limit_order_object,
member< limit_order_object, price, &limit_order_object::sell_price>,
member< object, object_id_type, &object::id>
>,
composite_key_compare< std::greater<price>, std::less<object_id_type> >
>
>
> limit_order_multi_index_type;
typedef generic_index<limit_order_object, limit_order_multi_index_type> limit_order_index;
} }
FC_REFLECT_DERIVED( graphene::chain::limit_order_object,
(graphene::db::object),
(expiration)(seller)(for_sale)(sell_price)
)

View file

@ -1,30 +1,56 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Copyright (c) 2015, Cryptonomex, Inc. All rights reserved. */
#pragma once
#include <graphene/db/generic_index.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/authority.hpp>
#include <graphene/chain/asset.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <fc/uint128.hpp>
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {
using namespace graphene::db;
using namespace graphene::db;
/**
* @brief an offer to sell a amount of a asset at a specified exchange rate by a certain time
* @ingroup object
* @ingroup protocol
* @ingroup market
*
* This limit_order_objects are indexed by @ref expiration and is automatically deleted on the first block after expiration.
*/
class limit_order_object : public abstract_object<limit_order_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = limit_order_object_type;
time_point_sec expiration;
account_id_type seller;
share_type for_sale; ///< asset id is sell_price.base.asset_id
price sell_price;
asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); }
asset amount_to_receive()const { return amount_for_sale() * sell_price; }
};
struct by_id;
struct by_price;
struct by_expiration;
typedef multi_index_container<
limit_order_object,
indexed_by<
hashed_unique< tag<by_id>,
member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_expiration>, member< limit_order_object, time_point_sec, &limit_order_object::expiration> >,
ordered_unique< tag<by_price>,
composite_key< limit_order_object,
member< limit_order_object, price, &limit_order_object::sell_price>,
member< object, object_id_type, &object::id>
>,
composite_key_compare< std::greater<price>, std::less<object_id_type> >
>
>
> limit_order_multi_index_type;
typedef generic_index<limit_order_object, limit_order_multi_index_type> limit_order_index;
/**
* @class call_order_object
@ -121,8 +147,58 @@ namespace graphene { namespace chain {
typedef generic_index<call_order_object, call_order_multi_index_type> call_order_index;
typedef generic_index<force_settlement_object, force_settlement_object_multi_index_type> force_settlement_index;
class limit_order_create_evaluator : public evaluator<limit_order_create_evaluator>
{
public:
typedef limit_order_create_operation operation_type;
void_result do_evaluate( const limit_order_create_operation& o );
object_id_type do_apply( const limit_order_create_operation& o );
asset calculate_market_fee( const asset_object* aobj, const asset& trade_amount );
const limit_order_create_operation* _op = nullptr;
const account_object* _seller = nullptr;
const asset_object* _sell_asset = nullptr;
const asset_object* _receive_asset = nullptr;
};
class limit_order_cancel_evaluator : public evaluator<limit_order_cancel_evaluator>
{
public:
typedef limit_order_cancel_operation operation_type;
void_result do_evaluate( const limit_order_cancel_operation& o );
asset do_apply( const limit_order_cancel_operation& o );
const limit_order_object* _order;
};
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
{
public:
typedef call_order_update_operation operation_type;
void_result do_evaluate( const call_order_update_operation& o );
void_result do_apply( const call_order_update_operation& o );
bool _closing_order = false;
const asset_object* _debt_asset = nullptr;
const account_object* _paying_account = nullptr;
const call_order_object* _order = nullptr;
const asset_bitasset_data_object* _bitasset_data = nullptr;
};
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::limit_order_object,
(graphene::db::object),
(expiration)(seller)(for_sale)(sell_price)
)
FC_REFLECT_DERIVED( graphene::chain::call_order_object, (graphene::db::object),
(borrower)(collateral)(debt)(call_price) )

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/db/object.hpp>
#include <graphene/chain/operations.hpp>
namespace graphene { namespace chain {

File diff suppressed because it is too large Load diff

View file

@ -1,83 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/types.hpp>
namespace graphene { namespace chain {
class database;
namespace pred {
/**
* Used to verify that account_id->name is equal to the given string literal.
*/
struct account_name_eq_lit
{
account_id_type account_id;
string name;
/**
* Perform state-independent checks. Verify
* account_name is a valid account name.
*/
bool validate()const;
/**
* Evaluate the predicate.
*/
bool evaluate( const database& db )const;
};
/**
* Used to verify that asset_id->symbol is equal to the given string literal.
*/
struct asset_symbol_eq_lit
{
asset_id_type asset_id;
string symbol;
/**
* Perform state independent checks. Verify symbol is a
* valid asset symbol.
*/
bool validate()const;
/**
* Evaluate the predicate.
*/
bool evaluate( const database& db )const;
};
}
/**
* When defining predicates do not make the protocol dependent upon
* implementation details.
*/
typedef static_variant<
pred::account_name_eq_lit,
pred::asset_symbol_eq_lit
> predicate;
} }
FC_REFLECT( graphene::chain::pred::account_name_eq_lit, (account_id)(name) )
FC_REFLECT( graphene::chain::pred::asset_symbol_eq_lit, (asset_id)(symbol) )
FC_REFLECT_TYPENAME( graphene::chain::predicate )

View file

@ -17,8 +17,8 @@
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/transaction_evaluation_state.hpp>

View file

@ -17,8 +17,7 @@
*/
#pragma once
#include <graphene/chain/types.hpp>
#include <graphene/chain/transaction.hpp>
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/chain/transaction_evaluation_state.hpp>
#include <graphene/db/generic_index.hpp>

View file

@ -0,0 +1,10 @@
Protocol Definition
--------------------
The classes declared in these headers provide the complete definition of the
Graphene protocol and are organized according to feature. Nothing in this
directory should depend upon anything other than fc or other types defined
in the protocol directory.
To be more specific, implementation details such as the objects defined in
the object database should not be required here.

View file

@ -0,0 +1,224 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
bool is_valid_name( const string& s );
bool is_cheap_name( const string& n );
/// These are the fields which can be updated by the active authority.
struct account_options
{
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
/// multiple keys in it.
public_key_type memo_key;
/// If this field is set to an account ID other than 0, this account's votes will be ignored and its stake
/// will be counted as voting for the referenced account's selected votes instead.
account_id_type voting_account;
/// The number of active witnesses this account votes the blockchain should appoint
/// Must not exceed the actual number of witnesses voted for in @ref votes
uint16_t num_witness = 0;
/// The number of active committee members this account votes the blockchain should appoint
/// Must not exceed the actual number of committee members voted for in @ref votes
uint16_t num_committee = 0;
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
/// account's balance of core asset.
flat_set<vote_id_type> votes;
void validate()const;
};
/**
* @ingroup operations
*/
struct account_create_operation : public base_operation
{
struct fee_parameters_type {
uint64_t basic_fee = 5*GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to register the cheapest non-free account
uint64_t premium_fee = 2000*GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to register the cheapest non-free account
uint32_t price_per_kbyte = GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
/// This account pays the fee. Must be a lifetime member.
account_id_type registrar;
/// This account receives a portion of the fee split between registrar and referrer. Must be a member.
account_id_type referrer;
/// Of the fee split between registrar and referrer, this percentage goes to the referrer. The rest goes to the
/// registrar.
uint16_t referrer_percent = 0;
string name;
authority owner;
authority active;
account_options options;
account_id_type fee_payer()const { return registrar; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& )const;
};
/**
* @ingroup operations
* @brief Update an existing account
*
* This operation is used to update an existing account. It can be used to update the authorities, or adjust the options on the account.
* See @ref account_object::options_type for the options which may be updated.
*/
struct account_update_operation : public base_operation
{
struct fee_parameters_type {
share_type fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
/// The account to update
account_id_type account;
/// New owner authority. If set, this operation requires owner authority to execute.
optional<authority> owner;
/// New active authority. If set, this operation requires owner authority to execute: TODO: why?
optional<authority> active;
/// New account options
optional<account_options> new_options;
account_id_type fee_payer()const { return account; }
void validate()const;
share_type calculate_fee( const fee_parameters_type& k )const;
};
/**
* @brief This operation is used to whitelist and blacklist accounts, primarily for transacting in whitelisted assets
* @ingroup operations
*
* Accounts can freely specify opinions about other accounts, in the form of either whitelisting or blacklisting
* them. This information is used in chain validation only to determine whether an account is authorized to transact
* in an asset type which enforces a whitelist, but third parties can use this information for other uses as well,
* as long as it does not conflict with the use of whitelisted assets.
*
* An asset which enforces a whitelist specifies a list of accounts to maintain its whitelist, and a list of
* accounts to maintain its blacklist. In order for a given account A to hold and transact in a whitelisted asset S,
* A must be whitelisted by at least one of S's whitelist_authorities and blacklisted by none of S's
* blacklist_authorities. If A receives a balance of S, and is later removed from the whitelist(s) which allowed it
* to hold S, or added to any blacklist S specifies as authoritative, A's balance of S will be frozen until A's
* authorization is reinstated.
*
* This operation requires authorizing_account's signature, but not account_to_list's. The fee is paid by
* authorizing_account.
*/
struct account_whitelist_operation : public base_operation
{
struct fee_parameters_type { share_type fee = 300000; };
enum account_listing {
no_listing = 0x0, ///< No opinion is specified about this account
white_listed = 0x1, ///< This account is whitelisted, but not blacklisted
black_listed = 0x2, ///< This account is blacklisted, but not whitelisted
white_and_black_listed = white_listed | black_listed ///< This account is both whitelisted and blacklisted
};
/// Paid by authorizing_account
asset fee;
/// The account which is specifying an opinion of another account
account_id_type authorizing_account;
/// The account being opined about
account_id_type account_to_list;
/// The new white and blacklist status of account_to_list, as determined by authorizing_account
/// This is a bitfield using values defined in the account_listing enum
uint8_t new_listing;
account_id_type fee_payer()const { return authorizing_account; }
void validate()const { FC_ASSERT( fee.amount >= 0 ); FC_ASSERT(new_listing < 0x4); }
};
/**
* @brief Manage an account's membership status
* @ingroup operations
*
* This operation is used to upgrade an account to a member, or renew its subscription. If an account which is an
* unexpired annual subscription member publishes this operation with @ref upgrade_to_lifetime_member set to false,
* the account's membership expiration date will be pushed backward one year. If a basic account publishes it with
* @ref upgrade_to_lifetime_member set to false, the account will be upgraded to a subscription member with an
* expiration date one year after the processing time of this operation.
*
* Any account may use this operation to become a lifetime member by setting @ref upgrade_to_lifetime_member to
* true. Once an account has become a lifetime member, it may not use this operation anymore.
*/
struct account_upgrade_operation : public base_operation
{
struct fee_parameters_type {
uint64_t membership_annual_fee = 2000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t membership_lifetime_fee = 10000 * GRAPHENE_BLOCKCHAIN_PRECISION; ///< the cost to upgrade to a lifetime member
};
asset fee;
/// The account to upgrade; must not already be a lifetime member
account_id_type account_to_upgrade;
/// If true, the account will be upgraded to a lifetime member; otherwise, it will add a year to the subscription
bool upgrade_to_lifetime_member = false;
account_id_type fee_payer()const { return account_to_upgrade; }
void validate()const;
share_type calculate_fee( const fee_parameters_type& k )const;
};
/**
* @brief transfers the account to another account while clearing the white list
* @ingroup operations
*
* In theory an account can be transferred by simply updating the authorities, but that kind
* of transfer lacks semantic meaning and is more often done to rotate keys without transferring
* ownership. This operation is used to indicate the legal transfer of title to this account and
* a break in the operation history.
*
* The account_id's owner/active/voting/memo authority should be set to new_owner
*
* This operation will clear the account's whitelist statuses, but not the blacklist statuses.
*/
struct account_transfer_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 500 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type account_id;
account_id_type new_owner;
account_id_type fee_payer()const { return account_id; }
void validate()const;
};
} }
FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes))
FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
(no_listing)(white_listed)(black_listed)(white_and_black_listed))
FC_REFLECT( graphene::chain::account_create_operation,
(fee)(registrar)
(referrer)(referrer_percent)
(name)(owner)(active)(options)
)
FC_REFLECT( graphene::chain::account_update_operation,
(fee)(account)(owner)(active)(new_options)
)
FC_REFLECT( graphene::chain::account_upgrade_operation,
(fee)(account_to_upgrade)(upgrade_to_lifetime_member) )
FC_REFLECT( graphene::chain::account_whitelist_operation, (fee)(authorizing_account)(account_to_list)(new_listing))
FC_REFLECT( graphene::chain::account_create_operation::fee_parameters_type, (basic_fee)(premium_fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::account_whitelist_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::account_update_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::account_upgrade_operation::fee_parameters_type, (membership_annual_fee)(membership_lifetime_fee) )
FC_REFLECT( graphene::chain::account_transfer_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::account_transfer_operation, (fee)(account_id)(new_owner) )

View file

@ -0,0 +1,73 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* Used to verify that account_id->name is equal to the given string literal.
*/
struct account_name_eq_lit_predicate
{
account_id_type account_id;
string name;
/**
* Perform state-independent checks. Verify
* account_name is a valid account name.
*/
bool validate()const;
};
/**
* Used to verify that asset_id->symbol is equal to the given string literal.
*/
struct asset_symbol_eq_lit_predicate
{
asset_id_type asset_id;
string symbol;
/**
* Perform state independent checks. Verify symbol is a
* valid asset symbol.
*/
bool validate()const;
};
/**
* When defining predicates do not make the protocol dependent upon
* implementation details.
*/
typedef static_variant<
account_name_eq_lit_predicate,
asset_symbol_eq_lit_predicate
> predicate;
/**
* @brief assert that some conditions are true.
* @ingroup operations
*
* This operation performs no changes to the database state, but can but used to verify
* pre or post conditions for other operations.
*/
struct assert_operation : public base_operation
{
struct fee_parameters_type { share_type fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type fee_paying_account;
vector<predicate> predicates;
flat_set<account_id_type> required_auths;
account_id_type fee_payer()const { return fee_paying_account; }
void validate()const;
};
} } // graphene::chain
FC_REFLECT( graphene::chain::assert_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::account_name_eq_lit_predicate, (account_id)(name) )
FC_REFLECT( graphene::chain::asset_symbol_eq_lit_predicate, (asset_id)(symbol) )
FC_REFLECT_TYPENAME( graphene::chain::predicate )
FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths) )

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/config.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/config.hpp>
#include <graphene/chain/protocol/types.hpp>
namespace graphene { namespace chain {

View file

@ -0,0 +1,444 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/memo.hpp>
namespace graphene { namespace chain {
bool is_valid_symbol( const string& symbol );
/**
* @brief The asset_options struct contains options available on all assets in the network
*
* @note Changes to this struct will break protocol compatibility
*/
struct asset_options {
/// The maximum supply of this asset which may exist at any given time. This can be as large as
/// GRAPHENE_MAX_SHARE_SUPPLY
share_type max_supply = GRAPHENE_MAX_SHARE_SUPPLY;
/// When this asset is traded on the markets, this percentage of the total traded will be exacted and paid
/// to the issuer. This is a fixed point value, representing hundredths of a percent, i.e. a value of 100
/// in this field means a 1% fee is charged on market trades of this asset.
uint16_t market_fee_percent = 0;
/// Market fees calculated as @ref market_fee_percent of the traded volume are capped to this value
share_type max_market_fee = GRAPHENE_MAX_SHARE_SUPPLY;
/// The flags which the issuer has permission to update. See @ref asset_issuer_permission_flags
uint16_t issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
/// The currently active flags on this permission. See @ref asset_issuer_permission_flags
uint16_t flags = 0;
/// When a non-core asset is used to pay a fee, the blockchain must convert that asset to core asset in
/// order to accept the fee. If this asset's fee pool is funded, the chain will automatically deposite fees
/// in this asset to its accumulated fees, and withdraw from the fee pool the same amount as converted at
/// the core exchange rate.
price core_exchange_rate;
/// A set of accounts which maintain whitelists to consult for this asset. If enforce_white_list() returns
/// true, an account may only send, receive, trade, etc. in this asset if one of these accounts appears in
/// its account_object::whitelisting_accounts field.
flat_set<account_id_type> whitelist_authorities;
/// A set of accounts which maintain blacklists to consult for this asset. If enforce_white_list() returns
/// true, an account may only send, receive, trade, etc. in this asset if none of these accounts appears in
/// its account_object::blacklisting_accounts field. If the account is blacklisted, it may not transact in
/// this asset even if it is also whitelisted.
flat_set<account_id_type> blacklist_authorities;
/** defines the assets that this asset may be traded against in the market */
flat_set<asset_id_type> whitelist_markets;
/** defines the assets that this asset may not be traded against in the market, must not overlap whitelist */
flat_set<asset_id_type> blacklist_markets;
/**
* data that describes the meaning/purpose of this asset, fee will be charged proportional to
* size of description.
*/
string description;
/// Perform internal consistency checks.
/// @throws fc::exception if any check fails
void validate()const;
};
/**
* @brief The bitasset_options struct contains configurable options available only to BitAssets.
*
* @note Changes to this struct will break protocol compatibility
*/
struct bitasset_options {
/// Time before a price feed expires
uint32_t feed_lifetime_sec = GRAPHENE_DEFAULT_PRICE_FEED_LIFETIME;
/// Minimum number of unexpired feeds required to extract a median feed from
uint8_t minimum_feeds = 1;
/// This is the delay between the time a long requests settlement and the chain evaluates the settlement
uint32_t force_settlement_delay_sec = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY;
/// This is the percent to adjust the feed price in the short's favor in the event of a forced settlement
uint16_t force_settlement_offset_percent = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_OFFSET;
/// Force settlement volume can be limited such that only a certain percentage of the total existing supply
/// of the asset may be force-settled within any given chain maintenance interval. This field stores the
/// percentage of the current supply which may be force settled within the current maintenance interval. If
/// force settlements come due in an interval in which the maximum volume has already been settled, the new
/// settlements will be enqueued and processed at the beginning of the next maintenance interval.
uint16_t maximum_force_settlement_volume = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_MAX_VOLUME;
/// This speicifies which asset type is used to collateralize short sales
/// This field may only be updated if the current supply of the asset is zero.
asset_id_type short_backing_asset;
/// Perform internal consistency checks.
/// @throws fc::exception if any check fails
void validate()const;
};
/**
* @ingroup operations
*/
struct asset_create_operation : public base_operation
{
struct fee_parameters_type {
uint64_t symbol3 = 500000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t symbol4 = 300000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint64_t long_symbol = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10; /// only required for large memos.
};
asset fee;
/// This account must sign and pay the fee for this operation. Later, this account may update the asset
account_id_type issuer;
/// The ticker symbol of this asset
string symbol;
/// Number of digits to the right of decimal point, must be less than or equal to 12
uint8_t precision = 0;
/// Options common to all assets.
///
/// @note common_options.core_exchange_rate technically needs to store the asset ID of this new asset. Since this
/// ID is not known at the time this operation is created, create this price as though the new asset has instance
/// ID 1, and the chain will overwrite it with the new asset's ID.
asset_options common_options;
/// Options only available for BitAssets. MUST be non-null if and only if the @ref market_issued flag is set in
/// common_options.flags
optional<bitasset_options> bitasset_options;
/// For BitAssets, set this to true if the asset implements a @ref prediction_market; false otherwise
bool is_prediction_market = false;
account_id_type fee_payer()const { return issuer; }
void validate()const;
share_type calculate_fee( const fee_parameters_type& k )const;
};
/**
* @brief allows global settling of bitassets (black swan or prediction markets)
*
* In order to use this operation, @ref asset_to_settle must have the global_settle flag set
*
* When this operation is executed all balances are converted into the backing asset at the
* settle_price and all open margin positions are called at the settle price. If this asset is
* used as backing for other bitassets, those bitassets will be force settled at their current
* feed price.
*/
struct asset_global_settle_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 500 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type issuer; ///< must equal @ref asset_to_settle->issuer
asset_id_type asset_to_settle;
price settle_price;
account_id_type fee_payer()const { return issuer; }
void validate()const;
};
/**
* @brief Schedules a market-issued asset for automatic settlement
* @ingroup operations
*
* Holders of market-issued assests may request a forced settlement for some amount of their asset. This means that
* the specified sum will be locked by the chain and held for the settlement period, after which time the chain will
* choose a margin posision holder and buy the settled asset using the margin's collateral. The price of this sale
* will be based on the feed price for the market-issued asset being settled. The exact settlement price will be the
* feed price at the time of settlement with an offset in favor of the margin position, where the offset is a
* blockchain parameter set in the global_property_object.
*
* The fee is paid by @ref account, and @ref account must authorize this operation
*/
struct asset_settle_operation : public base_operation
{
struct fee_parameters_type {
/** this fee should be high to encourage small settlement requests to
* be performed on the market rather than via forced settlement.
*
* Note that in the event of a black swan or prediction market close out
* everyone will have to pay this fee.
*/
uint64_t fee = 100 * GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
/// Account requesting the force settlement. This account pays the fee
account_id_type account;
/// Amount of asset to force settle. This must be a market-issued asset
asset amount;
account_id_type fee_payer()const { return account; }
void validate()const;
};
/**
* @ingroup operations
*/
struct asset_fund_fee_pool_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee; ///< core asset
account_id_type from_account;
asset_id_type asset_id;
share_type amount; ///< core asset
account_id_type fee_payer()const { return from_account; }
void validate()const;
};
/**
* @brief Update options common to all assets
* @ingroup operations
*
* There are a number of options which all assets in the network use. These options are enumerated in the @ref
* asset_options struct. This operation is used to update these options for an existing asset.
*
* @note This operation cannot be used to update BitAsset-specific options. For these options, use @ref
* asset_update_bitasset_operation instead.
*
* @pre @ref issuer SHALL be an existing account and MUST match asset_object::issuer on @ref asset_to_update
* @pre @ref fee SHALL be nonnegative, and @ref issuer MUST have a sufficient balance to pay it
* @pre @ref new_options SHALL be internally consistent, as verified by @ref validate()
* @post @ref asset_to_update will have options matching those of new_options
*/
struct asset_update_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 500 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10;
};
asset_update_operation(){}
/// Initializes the operation to apply changes to the provided asset, and copies old.options into @ref new_options
/// TODO: operations should not depend upon data model objects, reverse the dependency
// asset_update_operation(const asset_object& old);
asset fee;
account_id_type issuer;
asset_id_type asset_to_update;
/// If the asset is to be given a new issuer, specify his ID here.
optional<account_id_type> new_issuer;
asset_options new_options;
account_id_type fee_payer()const { return issuer; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
/**
* @brief Update options specific to BitAssets
* @ingroup operations
*
* BitAssets have some options which are not relevant to other asset types. This operation is used to update those
* options an an existing BitAsset.
*
* @pre @ref issuer MUST be an existing account and MUST match asset_object::issuer on @ref asset_to_update
* @pre @ref asset_to_update MUST be a BitAsset, i.e. @ref asset_object::is_market_issued() returns true
* @pre @ref fee MUST be nonnegative, and @ref issuer MUST have a sufficient balance to pay it
* @pre @ref new_options SHALL be internally consistent, as verified by @ref validate()
* @post @ref asset_to_update will have BitAsset-specific options matching those of new_options
*/
struct asset_update_bitasset_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 500 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type issuer;
asset_id_type asset_to_update;
bitasset_options new_options;
account_id_type fee_payer()const { return issuer; }
void validate()const;
};
/**
* @brief Update the set of feed-producing accounts for a BitAsset
* @ingroup operations
*
* BitAssets have price feeds selected by taking the median values of recommendations from a set of feed producers.
* This operation is used to specify which accounts may produce feeds for a given BitAsset.
*
* @pre @ref issuer MUST be an existing account, and MUST match asset_object::issuer on @ref asset_to_update
* @pre @ref issuer MUST NOT be the genesis account
* @pre @ref asset_to_update MUST be a BitAsset, i.e. @ref asset_object::is_market_issued() returns true
* @pre @ref fee MUST be nonnegative, and @ref issuer MUST have a sufficient balance to pay it
* @pre Cardinality of @ref new_feed_producers MUST NOT exceed @ref chain_parameters::maximum_asset_feed_publishers
* @post @ref asset_to_update will have a set of feed producers matching @ref new_feed_producers
* @post All valid feeds supplied by feed producers in @ref new_feed_producers, which were already feed producers
* prior to execution of this operation, will be preserved
*/
struct asset_update_feed_producers_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 500 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type issuer;
asset_id_type asset_to_update;
flat_set<account_id_type> new_feed_producers;
account_id_type fee_payer()const { return issuer; }
void validate()const;
};
/**
* @brief Publish price feeds for market-issued assets
* @ingroup operations
*
* Price feed providers use this operation to publish their price feeds for market-issued assets. A price feed is
* used to tune the market for a particular market-issued asset. For each value in the feed, the median across all
* delegate feeds for that asset is calculated and the market for the asset is configured with the median of that
* value.
*
* The feed in the operation contains three prices: a call price limit, a short price limit, and a settlement price.
* The call limit price is structured as (collateral asset) / (debt asset) and the short limit price is structured
* as (asset for sale) / (collateral asset). Note that the asset IDs are opposite to eachother, so if we're
* publishing a feed for USD, the call limit price will be CORE/USD and the short limit price will be USD/CORE. The
* settlement price may be flipped either direction, as long as it is a ratio between the market-issued asset and
* its collateral.
*/
struct asset_publish_feed_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee; ///< paid for by publisher
account_id_type publisher;
asset_id_type asset_id; ///< asset for which the feed is published
price_feed feed;
account_id_type fee_payer()const { return publisher; }
void validate()const;
};
/**
* @ingroup operations
*/
struct asset_issue_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
account_id_type issuer; ///< Must be asset_to_issue->asset_id->issuer
asset asset_to_issue;
account_id_type issue_to_account;
/** user provided data encrypted to the memo key of the "to" account */
optional<memo_data> memo;
account_id_type fee_payer()const { return issuer; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
/**
* @brief used to take an asset out of circulation, returning to the issuer
* @ingroup operations
*
* @note You cannot burn market-issued assets.
*/
struct asset_reserve_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type payer;
asset amount_to_reserve;
account_id_type fee_payer()const { return payer; }
void validate()const;
};
} } // graphene::chain
FC_REFLECT( graphene::chain::asset_options,
(max_supply)
(market_fee_percent)
(max_market_fee)
(issuer_permissions)
(flags)
(core_exchange_rate)
(whitelist_authorities)
(blacklist_authorities)
(whitelist_markets)
(blacklist_markets)
(description)
)
FC_REFLECT( graphene::chain::bitasset_options,
(feed_lifetime_sec)
(minimum_feeds)
(force_settlement_delay_sec)
(force_settlement_offset_percent)
(maximum_force_settlement_volume)
(short_backing_asset)
)
FC_REFLECT( graphene::chain::asset_create_operation::fee_parameters_type, (symbol3)(symbol4)(long_symbol)(price_per_kbyte) )
FC_REFLECT( graphene::chain::asset_global_settle_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_settle_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_fund_fee_pool_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_update_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::asset_update_bitasset_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_update_feed_producers_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_publish_feed_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_issue_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::asset_reserve_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_create_operation,
(fee)
(issuer)
(symbol)
(precision)
(common_options)
(bitasset_options)
(is_prediction_market)
)
FC_REFLECT( graphene::chain::asset_update_operation,
(fee)
(issuer)
(asset_to_update)
(new_issuer)
(new_options)
)
FC_REFLECT( graphene::chain::asset_update_bitasset_operation,
(fee)
(issuer)
(asset_to_update)
(new_options)
)
FC_REFLECT( graphene::chain::asset_update_feed_producers_operation,
(fee)(issuer)(asset_to_update)(new_feed_producers)
)
FC_REFLECT( graphene::chain::asset_publish_feed_operation,
(fee)(publisher)(asset_id)(feed) )
FC_REFLECT( graphene::chain::asset_settle_operation, (fee)(account)(amount) )
FC_REFLECT( graphene::chain::asset_global_settle_operation, (fee)(issuer)(asset_to_settle)(settle_price) )
FC_REFLECT( graphene::chain::asset_issue_operation,
(fee)(issuer)(asset_to_issue)(issue_to_account)(memo) )
FC_REFLECT( graphene::chain::asset_reserve_operation,
(fee)(payer)(amount_to_reserve) )
FC_REFLECT( graphene::chain::asset_fund_fee_pool_operation, (fee)(from_account)(asset_id)(amount) );

View file

@ -16,8 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <fc/io/varint.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/types.hpp>
namespace graphene { namespace chain {

View file

@ -0,0 +1,32 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* @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 not exceed @ref balance_object::available at the time of evaluation. If
* the object contains a non-vesting balance, @ref total_claimed must be the full balance of the object.
*/
struct balance_claim_operation : public base_operation
{
struct fee_parameters_type {};
asset fee;
account_id_type deposit_to_account;
balance_id_type balance_to_claim;
public_key_type balance_owner_key;
asset total_claimed;
account_id_type fee_payer()const { return deposit_to_account; }
share_type calculate_fee(const fee_parameters_type& )const { return 0; }
void validate()const;
};
}} // graphene::chain
FC_REFLECT( graphene::chain::balance_claim_operation::fee_parameters_type, )
FC_REFLECT( graphene::chain::balance_claim_operation,
(fee)(deposit_to_account)(balance_to_claim)(balance_owner_key)(total_claimed) )

View file

@ -0,0 +1,83 @@
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/protocol/asset.hpp>
#include <graphene/chain/protocol/authority.hpp>
namespace graphene { namespace chain {
/**
* @defgroup operations Operations
* @ingroup transactions Transactions
* @brief A set of valid comands for mutating the globally shared state.
*
* An operation can be thought of like a function that will modify the global
* shared state of the blockchain. The members of each struct are like function
* arguments and each operation can potentially generate a return value.
*
* Operations can be grouped into transactions (@ref transaction) to ensure that they occur
* in a particular order and that all operations apply successfully or
* no operations apply.
*
* Each operation is a fully defined state transition and can exist in a transaction on its own.
*
* @section operation_design_principles Design Principles
*
* Operations have been carefully designed to include all of the information necessary to
* interpret them outside the context of the blockchain. This means that information about
* current chain state is included in the operation even though it could be inferred from
* a subset of the data. This makes the expected outcome of each operation well defined and
* easily understood without access to chain state.
*
* @subsection balance_calculation Balance Calculation Principle
*
* We have stipulated that the current account balance may be entirely calculated from
* just the subset of operations that are relevant to that account. There should be
* no need to process the entire blockchain inorder to know your account's balance.
*
* @subsection fee_calculation Explicit Fee Principle
*
* Blockchain fees can change from time to time and it is important that a signed
* transaction explicitly agree to the fees it will be paying. This aids with account
* balance updates and ensures that the sender agreed to the fee prior to making the
* transaction.
*
* @subsection defined_authority Explicit Authority
*
* Each operation shall contain enough information to know which accounts must authorize
* the operation. This principle enables authority verification to occur in a centralized,
* optimized, and parallel manner.
*
* @subsection relevancy_principle Explicit Relevant Accounts
*
* Each operation contains enough information to enumerate all accounts for which the
* operation should apear in its account history. This principle enables us to easily
* define and enforce the @balance_calculation. This is superset of the @ref defined_authority
*
* @{
*/
struct void_result{};
typedef fc::static_variant<void_result,object_id_type,asset> operation_result;
struct base_operation
{
template<typename T>
share_type calculate_fee(const T& params)const
{
return params.fee;
}
void get_required_authorities( vector<authority>& )const{}
void get_required_active_authorities( flat_set<account_id_type>& )const{}
void get_required_owner_authorities( flat_set<account_id_type>& )const{}
void get_impacted_accounts( flat_set<account_id_type>& )const{}
void validate()const{}
static uint64_t calculate_data_fee( uint64_t bytes, uint64_t price_per_kbyte );
};
///@}
} }
FC_REFLECT_TYPENAME( graphene::chain::operation_result )
FC_REFLECT( graphene::chain::void_result, )

View file

@ -16,8 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/types.hpp>
#include <graphene/chain/transaction.hpp>
#include <graphene/chain/protocol/transaction.hpp>
namespace graphene { namespace chain {

View file

@ -16,14 +16,24 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/fee_schedule.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <fc/smart_ref_fwd.hpp>
namespace graphene { namespace chain { struct fee_schedule; } }
/*
namespace fc {
template<typename Stream, typename T> inline void pack( Stream& s, const graphene::chain::fee_schedule& value );
template<typename Stream, typename T> inline void unpack( Stream& s, graphene::chain::fee_schedule& value );
} // namespace fc
*/
namespace graphene { namespace chain {
typedef static_variant<> parameter_extension;
struct chain_parameters
{
fee_schedule current_fees; ///< current schedule of fees
/** using a smart ref breaks the circular dependency created between operations and the fee schedule */
smart_ref<fee_schedule> current_fees; ///< current schedule of fees
uint8_t block_interval = GRAPHENE_DEFAULT_BLOCK_INTERVAL; ///< interval in seconds between blocks
uint32_t maintenance_interval = GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL; ///< interval in sections between blockchain maintenance events
uint32_t genesis_proposal_review_period = GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC; ///< minimum time in seconds that a proposed transaction requiring genesis authority may not be signed, prior to expiration

View file

@ -0,0 +1,2 @@
#pragma once
#include <graphene/chain/config.hpp>

View file

@ -0,0 +1,35 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* @brief provides a generic way to add higher level protocols on top of witness consensus
* @ingroup operations
*
* There is no validation for this operation other than that required auths are valid and a fee
* is paid that is appropriate for the data contained.
*/
struct custom_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10;
};
asset fee;
account_id_type payer;
flat_set<account_id_type> required_auths;
uint16_t id;
vector<char> data;
account_id_type fee_payer()const { return payer; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
} } // namespace graphene::chain
FC_REFLECT( graphene::chain::custom_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)(data) )

View file

@ -0,0 +1,59 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/chain_parameters.hpp>
namespace graphene { namespace chain {
/**
* @brief Create a delegate object, as a bid to hold a delegate seat on the network.
* @ingroup operations
*
* Accounts which wish to become delegates may use this operation to create a delegate object which stakeholders may
* vote on to approve its position as a delegate.
*/
struct delegate_create_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
/// The account which owns the delegate. This account pays the fee for this operation.
account_id_type delegate_account;
string url;
account_id_type fee_payer()const { return delegate_account; }
void validate()const;
};
/**
* @brief Used by delegates to update the global parameters of the blockchain.
* @ingroup operations
*
* This operation allows the delegates to update the global parameters on the blockchain. These control various
* tunable aspects of the chain, including block and maintenance intervals, maximum data sizes, the fees charged by
* the network, etc.
*
* This operation may only be used in a proposed transaction, and a proposed transaction which contains this
* operation must have a review period specified in the current global parameters before it may be accepted.
*/
struct delegate_update_global_parameters_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
chain_parameters new_parameters;
account_id_type fee_payer()const { return account_id_type(); }
void validate()const;
};
/// TODO: delegate_resign_operation : public base_operation
} } // graphene::chain
FC_REFLECT( graphene::chain::delegate_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::delegate_update_global_parameters_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::delegate_create_operation,
(fee)(delegate_account)(url) )
FC_REFLECT( graphene::chain::delegate_update_global_parameters_operation, (fee)(new_parameters) );

View file

@ -1,5 +1,5 @@
#pragma once
#include <graphene/chain/operations.hpp>
#include <graphene/chain/protocol/operations.hpp>
namespace graphene { namespace chain {
@ -27,6 +27,8 @@ namespace graphene { namespace chain {
asset calculate_fee( const operation& op, const price& core_exchange_rate = price::unit_price() )const;
void set_fee( operation& op, const price& core_exchange_rate = price::unit_price() )const;
void set_all_fees( uint64_t fee_amount );
/**
* Validates all of the parameters are present and accounted for.
*/
@ -46,7 +48,3 @@ namespace graphene { namespace chain {
FC_REFLECT_TYPENAME( graphene::chain::fee_parameters )
FC_REFLECT( graphene::chain::fee_schedule, (parameters) )
} }

View file

@ -0,0 +1,147 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* @class limit_order_create_operation
* @brief instructs the blockchain to attempt to sell one asset for another
* @ingroup operations
*
* The blockchain will atempt to sell amount_to_sell.asset_id for as
* much min_to_receive.asset_id as possible. The fee will be paid by
* the seller's account. Market fees will apply as specified by the
* issuer of both the selling asset and the receiving asset as
* a percentage of the amount exchanged.
*
* If either the selling asset or the receiving asset is white list
* restricted, the order will only be created if the seller is on
* the white list of the restricted asset type.
*
* Market orders are matched in the order they are included
* in the block chain.
*/
struct limit_order_create_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 5 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type seller;
asset amount_to_sell;
asset min_to_receive;
/// The order will be removed from the books if not filled by expiration
/// Upon expiration, all unsold asset will be returned to seller
time_point_sec expiration = time_point_sec::maximum();
/// If this flag is set the entire order must be filled or the operation is rejected
bool fill_or_kill = false;
pair<asset_id_type,asset_id_type> get_market()const
{
return amount_to_sell.asset_id < min_to_receive.asset_id ?
std::make_pair(amount_to_sell.asset_id, min_to_receive.asset_id) :
std::make_pair(min_to_receive.asset_id, amount_to_sell.asset_id);
}
account_id_type fee_payer()const { return seller; }
void validate()const;
price get_price()const { return amount_to_sell / min_to_receive; }
};
/**
* @ingroup operations
* Used to cancel an existing limit order. Both fee_pay_account and the
* account to receive the proceeds must be the same as order->seller.
*
* @return the amount actually refunded
*/
struct limit_order_cancel_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
limit_order_id_type order;
/** must be order->seller */
account_id_type fee_paying_account;
account_id_type fee_payer()const { return fee_paying_account; }
void validate()const;
};
/**
* @ingroup operations
*
* This operation can be used to add collateral, cover, and adjust the margin call price for a particular user.
*
* For prediction markets the collateral and debt must always be equal.
*
* This operation will fail if it would trigger a margin call that couldn't be filled. If the margin call hits
* the call price limit then it will fail if the call price is above the settlement price.
*
* @note this operation can be used to force a market order using the collateral without requiring outside funds.
*/
struct call_order_update_operation : public base_operation
{
/** this is slightly more expensive than limit orders, this pricing impacts prediction markets */
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type funding_account; ///< pays fee, collateral, and cover
asset delta_collateral; ///< the amount of collateral to add to the margin position
asset delta_debt; ///< the amount of the debt to be paid off, may be negative to issue new debt
account_id_type fee_payer()const { return funding_account; }
void validate()const;
};
/**
* @ingroup operations
*
* @note This is a virtual operation that is created while matching orders and
* emitted for the purpose of accurately tracking account history, accelerating
* a reindex.
*/
struct fill_order_operation : public base_operation
{
struct fee_parameters_type {};
fill_order_operation(){}
fill_order_operation( object_id_type o, account_id_type a, asset p, asset r, asset f )
:order_id(o),account_id(a),pays(p),receives(r),fee(f){}
object_id_type order_id;
account_id_type account_id;
asset pays;
asset receives;
asset fee; // paid by receiving account
pair<asset_id_type,asset_id_type> get_market()const
{
return pays.asset_id < receives.asset_id ?
std::make_pair( pays.asset_id, receives.asset_id ) :
std::make_pair( receives.asset_id, pays.asset_id );
}
account_id_type fee_payer()const { return account_id; }
void validate()const { FC_ASSERT( !"virtual operation" ); }
/// This is a virtual operation; there is no fee
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
} } // graphene::chain
FC_REFLECT( graphene::chain::limit_order_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::limit_order_cancel_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::call_order_update_operation::fee_parameters_type, (fee) )
/// THIS IS THE ONLY VIRTUAL OPERATION THUS FAR...
FC_REFLECT( graphene::chain::fill_order_operation::fee_parameters_type, )
FC_REFLECT( graphene::chain::limit_order_create_operation,(fee)(seller)(amount_to_sell)(min_to_receive)(expiration)(fill_or_kill))
FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order) )
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(delta_collateral)(delta_debt) )
FC_REFLECT( graphene::chain::fill_order_operation, (fee)(order_id)(account_id)(pays)(receives) )

View file

@ -0,0 +1,68 @@
#pragma once
#include <graphene/chain/protocol/types.hpp>
namespace graphene { namespace chain {
/**
* @brief defines the keys used to derive the shared secret
*
* Because account authorities and keys can change at any time, each memo must
* capture the specific keys used to derive the shared secret. In order to read
* the cipher message you will need one of the two private keys.
*
* If @ref from == @ref to and @ref from == 0 then no encryption is used, the memo is public.
* If @ref from == @ref to and @ref from != 0 then invalid memo data
*
*/
struct memo_data
{
public_key_type from;
public_key_type to;
/**
* 64 bit nonce format:
* [ 8 bits | 56 bits ]
* [ entropy | timestamp ]
* Timestamp is number of microseconds since the epoch
* Entropy is a byte taken from the hash of a new private key
*
* This format is not mandated or verified; it is chosen to ensure uniqueness of key-IV pairs only. This should
* be unique with high probability as long as the generating host has a high-resolution clock OR a strong source
* of entropy for generating private keys.
*/
uint64_t nonce;
/**
* This field contains the AES encrypted packed @ref memo_message
*/
vector<char> message;
/// @note custom_nonce is for debugging only; do not set to a nonzero value in production
void set_message(const fc::ecc::private_key& priv,
const fc::ecc::public_key& pub, const string& msg, uint64_t custom_nonce = 0);
std::string get_message(const fc::ecc::private_key& priv,
const fc::ecc::public_key& pub)const;
};
/**
* @brief defines a message and checksum to enable validation of successful decryption
*
* When encrypting/decrypting a checksum is required to determine whether or not
* decryption was successful.
*/
struct memo_message
{
memo_message(){}
memo_message( uint32_t checksum, const std::string& text )
:checksum(checksum),text(text){}
uint32_t checksum = 0;
std::string text;
string serialize() const;
static memo_message deserialize(const string& serial);
};
} } // namespace graphene::chain
FC_REFLECT( graphene::chain::memo_message, (checksum)(text) )
FC_REFLECT( graphene::chain::memo_data, (from)(to)(nonce)(message) )

View file

@ -0,0 +1,117 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/account.hpp>
#include <graphene/chain/protocol/assert.hpp>
#include <graphene/chain/protocol/asset_ops.hpp>
#include <graphene/chain/protocol/balance.hpp>
#include <graphene/chain/protocol/custom.hpp>
#include <graphene/chain/protocol/delegate.hpp>
#include <graphene/chain/protocol/market.hpp>
#include <graphene/chain/protocol/proposal.hpp>
#include <graphene/chain/protocol/transfer.hpp>
#include <graphene/chain/protocol/vesting.hpp>
#include <graphene/chain/protocol/withdraw_permission.hpp>
#include <graphene/chain/protocol/witness.hpp>
#include <graphene/chain/protocol/worker.hpp>
namespace graphene { namespace chain {
/**
* @ingroup operations
*
* Defines the set of valid operations as a discriminated union type.
*/
typedef fc::static_variant<
transfer_operation,
limit_order_create_operation,
limit_order_cancel_operation,
call_order_update_operation,
fill_order_operation,
account_create_operation,
account_update_operation,
account_whitelist_operation,
account_upgrade_operation,
account_transfer_operation,
asset_create_operation,
asset_update_operation,
asset_update_bitasset_operation,
asset_update_feed_producers_operation,
asset_issue_operation,
asset_reserve_operation,
asset_fund_fee_pool_operation,
asset_settle_operation,
asset_global_settle_operation,
asset_publish_feed_operation,
witness_create_operation,
witness_withdraw_pay_operation,
proposal_create_operation,
proposal_update_operation,
proposal_delete_operation,
withdraw_permission_create_operation,
withdraw_permission_update_operation,
withdraw_permission_claim_operation,
withdraw_permission_delete_operation,
delegate_create_operation,
delegate_update_global_parameters_operation,
vesting_balance_create_operation,
vesting_balance_withdraw_operation,
worker_create_operation,
custom_operation,
assert_operation,
balance_claim_operation,
override_transfer_operation
> operation;
/// @} // operations group
/**
* Appends required authorites to the result vector. The authorities appended are not the
* same as those returned by get_required_auth
*
* @return a set of required authorities for @ref op
*/
void operation_get_required_authorities( const operation& op,
flat_set<account_id_type>& active,
flat_set<account_id_type>& owner,
vector<authority>& other );
void operation_get_impacted_accounts( const operation& op,
flat_set<account_id_type>& accounts );
void operation_validate( const operation& op );
/**
* Used to track the result of applying an operation and when it was applied.
*
* TODO: this doesn't belong here.
*/
struct applied_operation
{
operation op;
operation_result result;
uint32_t block_num;
uint16_t transaction_num;
uint16_t op_num;
};
/**
* @brief necessary to support nested operations inside the proposal_create_operation
*/
struct op_wrapper
{
public:
op_wrapper(const operation& op = operation()):op(op){}
operation op;
};
} } // graphene::chain
FC_REFLECT_TYPENAME( graphene::chain::operation )
FC_REFLECT( graphene::chain::op_wrapper, (op) )

View file

@ -0,0 +1,145 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* @defgroup proposed_transactions The Graphene Transaction Proposal Protocol
* @ingroup operations
*
* Graphene allows users to propose a transaction which requires approval of multiple accounts in order to execute.
* The user proposes a transaction using proposal_create_operation, then signatory accounts use
* proposal_update_operations to add or remove their approvals from this operation. When a sufficient number of
* approvals have been granted, the operations in the proposal are used to create a virtual transaction which is
* subsequently evaluated. Even if the transaction fails, the proposal will be kept until the expiration time, at
* which point, if sufficient approval is granted, the transaction will be evaluated a final time. This allows
* transactions which will not execute successfully until a given time to still be executed through the proposal
* mechanism. The first time the proposed transaction succeeds, the proposal will be regarded as resolved, and all
* future updates will be invalid.
*
* The proposal system allows for arbitrarily complex or recursively nested authorities. If a recursive authority
* (i.e. an authority which requires approval of 'nested' authorities on other accounts) is required for a
* proposal, then a second proposal can be used to grant the nested authority's approval. That is, a second
* proposal can be created which, when sufficiently approved, adds the approval of a nested authority to the first
* proposal. This multiple-proposal scheme can be used to acquire approval for an arbitrarily deep authority tree.
*
* Note that at any time, a proposal can be approved in a single transaction if sufficient signatures are available
* on the proposal_update_operation, as long as the authority tree to approve the proposal does not exceed the
* maximum recursion depth. In practice, however, it is easier to use proposals to acquire all approvals, as this
* leverages on-chain notification of all relevant parties that their approval is required. Off-chain
* multi-signature approval requires some off-chain mechanism for acquiring several signatures on a single
* transaction. This off-chain synchronization can be avoided using proposals.
* @{
*/
/**
* op_wrapper is used to get around the circular definition of operation and proposals that contain them.
*/
struct op_wrapper;
/**
* @brief The proposal_create_operation creates a transaction proposal, for use in multi-sig scenarios
* @ingroup operations
*
* Creates a transaction proposal. The operations which compose the transaction are listed in order in proposed_ops,
* and expiration_time specifies the time by which the proposal must be accepted or it will fail permanently. The
* expiration_time cannot be farther in the future than the maximum expiration time set in the global properties
* object.
*/
struct proposal_create_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10;
};
asset fee;
account_id_type fee_paying_account;
vector<op_wrapper> proposed_ops;
time_point_sec expiration_time;
optional<uint32_t> review_period_seconds;
/// Constructs a proposal_create_operation suitable for genesis proposals, with fee, expiration time and review
/// period set appropriately.
static proposal_create_operation genesis_proposal(const chain_parameters& param, fc::time_point_sec head_block_time );
account_id_type fee_payer()const { return fee_paying_account; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
/**
* @brief The proposal_update_operation updates an existing transaction proposal
* @ingroup operations
*
* This operation allows accounts to add or revoke approval of a proposed transaction. Signatures sufficient to
* satisfy the authority of each account in approvals are required on the transaction containing this operation.
*
* If an account with a multi-signature authority is listed in approvals_to_add or approvals_to_remove, either all
* required signatures to satisfy that account's authority must be provided in the transaction containing this
* operation, or a secondary proposal must be created which contains this operation.
*
* NOTE: If the proposal requires only an account's active authority, the account must not update adding its owner
* authority's approval. This is considered an error. An owner approval may only be added if the proposal requires
* the owner's authority.
*
* If an account's owner and active authority are both required, only the owner authority may approve. An attempt to
* add or remove active authority approval to such a proposal will fail.
*/
struct proposal_update_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10;
};
account_id_type fee_paying_account;
asset fee;
proposal_id_type proposal;
flat_set<account_id_type> active_approvals_to_add;
flat_set<account_id_type> active_approvals_to_remove;
flat_set<account_id_type> owner_approvals_to_add;
flat_set<account_id_type> owner_approvals_to_remove;
flat_set<public_key_type> key_approvals_to_add;
flat_set<public_key_type> key_approvals_to_remove;
account_id_type fee_payer()const { return fee_paying_account; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
/**
* @brief The proposal_delete_operation deletes an existing transaction proposal
* @ingroup operations
*
* This operation allows the early veto of a proposed transaction. It may be used by any account which is a required
* authority on the proposed transaction, when that account's holder feels the proposal is ill-advised and he decides
* he will never approve of it and wishes to put an end to all discussion of the issue. Because he is a required
* authority, he could simply refuse to add his approval, but this would leave the topic open for debate until the
* proposal expires. Using this operation, he can prevent any further breath from being wasted on such an absurd
* proposal.
*/
struct proposal_delete_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
account_id_type fee_paying_account;
bool using_owner_authority = false;
asset fee;
proposal_id_type proposal;
account_id_type fee_payer()const { return fee_paying_account; }
void validate()const;
};
///@}
}} // graphene::chain
FC_REFLECT( graphene::chain::proposal_create_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::proposal_update_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::proposal_delete_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::proposal_create_operation, (fee)(fee_paying_account)(expiration_time)
(proposed_ops)(review_period_seconds) )
FC_REFLECT( graphene::chain::proposal_update_operation, (fee)(fee_paying_account)(proposal)
(active_approvals_to_add)(active_approvals_to_remove)(owner_approvals_to_add)(owner_approvals_to_remove)
(key_approvals_to_add)(key_approvals_to_remove) )
FC_REFLECT( graphene::chain::proposal_delete_operation, (fee)(fee_paying_account)(using_owner_authority)(proposal) )

View file

@ -16,8 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/types.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/protocol/operations.hpp>
#include <numeric>

View file

@ -0,0 +1,83 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/memo.hpp>
namespace graphene { namespace chain {
/**
* @ingroup operations
*
* @brief Transfers an amount of one asset from one account to another
*
* Fees are paid by the "from" account
*
* @pre amount.amount > 0
* @pre fee.amount >= 0
* @pre from != to
* @post from account's balance will be reduced by fee and amount
* @post to account's balance will be increased by amount
* @return n/a
*/
struct transfer_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10; /// only required for large memos.
};
asset fee;
/// Account to transfer asset from
account_id_type from;
/// Account to transfer asset to
account_id_type to;
/// The amount of asset to transfer from @ref from to @ref to
asset amount;
/// User provided data encrypted to the memo key of the "to" account
optional<memo_data> memo;
account_id_type fee_payer()const { return from; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
/**
* @class override_transfer_operation
* @brief Allows the issuer of an asset to transfer an asset from any account to any account if they have override_authority
* @ingroup operations
*
* @pre amount.asset_id->issuer == issuer
* @pre issuer != from because this is pointless, use a normal transfer operation
*/
struct override_transfer_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10; /// only required for large memos.
};
asset fee;
account_id_type issuer;
/// Account to transfer asset from
account_id_type from;
/// Account to transfer asset to
account_id_type to;
/// The amount of asset to transfer from @ref from to @ref to
asset amount;
/// User provided data encrypted to the memo key of the "to" account
optional<memo_data> memo;
account_id_type fee_payer()const { return issuer; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
}} // graphene::chain
FC_REFLECT( graphene::chain::transfer_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::override_transfer_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::override_transfer_operation, (fee)(issuer)(from)(to)(amount)(memo) )
FC_REFLECT( graphene::chain::transfer_operation, (fee)(from)(to)(amount)(memo) )

View file

@ -29,11 +29,14 @@
#include <fc/string.hpp>
#include <fc/io/raw.hpp>
#include <fc/uint128.hpp>
#include <fc/static_variant.hpp>
#include <fc/smart_ref_fwd.hpp>
#include <memory>
#include <vector>
#include <deque>
#include <cstdint>
#include <graphene/chain/address.hpp>
#include <graphene/chain/protocol/address.hpp>
#include <graphene/db/object_id.hpp>
namespace graphene { namespace chain {
@ -53,6 +56,7 @@ namespace graphene { namespace chain {
using std::tie;
using std::make_pair;
using fc::smart_ref;
using fc::variant_object;
using fc::variant;
using fc::enum_type;
@ -349,8 +353,9 @@ namespace fc
void to_variant( const graphene::chain::vote_id_type& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo );
}
FC_REFLECT_TYPENAME( graphene::chain::vote_id_type::vote_type )
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(VOTE_TYPE_COUNT) )
FC_REFLECT( graphene::chain::vote_id_type, (content) )

View file

@ -0,0 +1,96 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
struct linear_vesting_policy_initializer
{
/** while vesting begins on begin_timestamp, none may be claimed before vesting_cliff_seconds have passed */
fc::time_point_sec begin_timestamp;
uint32_t vesting_cliff_seconds = 0;
uint32_t vesting_duration_seconds = 0;
};
struct cdd_vesting_policy_initializer
{
/** while coindays may accrue over time, none may be claimed before the start_claim time */
fc::time_point_sec start_claim;
uint32_t vesting_seconds = 0;
cdd_vesting_policy_initializer( uint32_t vest_sec = 0, fc::time_point_sec sc = fc::time_point_sec() ):start_claim(sc),vesting_seconds(vest_sec){}
};
typedef fc::static_variant<linear_vesting_policy_initializer, cdd_vesting_policy_initializer> vesting_policy_initializer;
/**
* @brief Create a vesting balance.
* @ingroup operations
*
* The chain allows a user to create a vesting balance.
* Normally, vesting balances are created automatically as part
* of cashback and worker operations. This operation allows
* vesting balances to be created manually as well.
*
* Manual creation of vesting balances can be used by a stakeholder
* to publicly demonstrate that they are committed to the chain.
* It can also be used as a building block to create transactions
* that function like public debt. Finally, it is useful for
* testing vesting balance functionality.
*
* @return ID of newly created vesting_balance_object
*/
struct vesting_balance_create_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type creator; ///< Who provides funds initially
account_id_type owner; ///< Who is able to withdraw the balance
asset amount;
vesting_policy_initializer policy;
account_id_type fee_payer()const { return creator; }
void validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount.amount > 0 );
}
};
/**
* @brief Withdraw from a vesting balance.
* @ingroup operations
*
* Withdrawal from a not-completely-mature vesting balance
* will result in paying fees.
*
* @return Nothing
*/
struct vesting_balance_withdraw_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 20*GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
vesting_balance_id_type vesting_balance;
account_id_type owner; ///< Must be vesting_balance.owner
asset amount;
account_id_type fee_payer()const { return owner; }
void validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount.amount > 0 );
}
};
}} // graphene::chain
FC_REFLECT( graphene::chain::vesting_balance_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount) )
FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) )
FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) )
FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer )

View file

@ -0,0 +1,158 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/memo.hpp>
namespace graphene { namespace chain {
/**
* @brief Create a new withdrawal permission
* @ingroup operations
*
* This operation creates a withdrawal permission, which allows some authorized account to withdraw from an
* authorizing account. This operation is primarily useful for scheduling recurring payments.
*
* Withdrawal permissions define withdrawal periods, which is a span of time during which the authorized account may
* make a withdrawal. Any number of withdrawals may be made so long as the total amount withdrawn per period does
* not exceed the limit for any given period.
*
* Withdrawal permissions authorize only a specific pairing, i.e. a permission only authorizes one specified
* authorized account to withdraw from one specified authorizing account. Withdrawals are limited and may not exceet
* the withdrawal limit. The withdrawal must be made in the same asset as the limit; attempts with withdraw any
* other asset type will be rejected.
*
* The fee for this operation is paid by withdraw_from_account, and this account is required to authorize this
* operation.
*/
struct withdraw_permission_create_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
/// The account authorizing withdrawals from its balances
account_id_type withdraw_from_account;
/// The account authorized to make withdrawals from withdraw_from_account
account_id_type authorized_account;
/// The maximum amount authorized_account is allowed to withdraw in a given withdrawal period
asset withdrawal_limit;
/// Length of the withdrawal period in seconds
uint32_t withdrawal_period_sec;
/// The number of withdrawal periods this permission is valid for
uint32_t periods_until_expiration;
/// Time at which the first withdrawal period begins; must be in the future
time_point_sec period_start_time;
account_id_type fee_payer()const { return withdraw_from_account; }
void validate()const;
};
/**
* @brief Update an existing withdraw permission
* @ingroup operations
*
* This oeration is used to update the settings for an existing withdrawal permission. The accounts to withdraw to
* and from may never be updated. The fields which may be updated are the withdrawal limit (both amount and asset
* type may be updated), the withdrawal period length, the remaining number of periods until expiration, and the
* starting time of the new period.
*
* Fee is paid by withdraw_from_account, which is required to authorize this operation
*/
struct withdraw_permission_update_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
/// This account pays the fee. Must match permission_to_update->withdraw_from_account
account_id_type withdraw_from_account;
/// The account authorized to make withdrawals. Must match permission_to_update->authorized_account
account_id_type authorized_account;
/// ID of the permission which is being updated
withdraw_permission_id_type permission_to_update;
/// New maximum amount the withdrawer is allowed to charge per withdrawal period
asset withdrawal_limit;
/// New length of the period between withdrawals
uint32_t withdrawal_period_sec;
/// New beginning of the next withdrawal period; must be in the future
time_point_sec period_start_time;
/// The new number of withdrawal periods for which this permission will be valid
uint32_t periods_until_expiration;
account_id_type fee_payer()const { return withdraw_from_account; }
void validate()const;
};
/**
* @brief Withdraw from an account which has published a withdrawal permission
* @ingroup operations
*
* This operation is used to withdraw from an account which has authorized such a withdrawal. It may be executed at
* most once per withdrawal period for the given permission. On execution, amount_to_withdraw is transferred from
* withdraw_from_account to withdraw_to_account, assuming amount_to_withdraw is within the withdrawal limit. The
* withdrawal permission will be updated to note that the withdrawal for the current period has occurred, and
* further withdrawals will not be permitted until the next withdrawal period, assuming the permission has not
* expired. This operation may be executed at any time within the current withdrawal period.
*
* Fee is paid by withdraw_to_account, which is required to authorize this operation
*/
struct withdraw_permission_claim_operation : public base_operation
{
struct fee_parameters_type {
uint64_t fee = 20*GRAPHENE_BLOCKCHAIN_PRECISION;
uint32_t price_per_kbyte = 10;
};
/// Paid by withdraw_to_account
asset fee;
/// ID of the permission authorizing this withdrawal
withdraw_permission_id_type withdraw_permission;
/// Must match withdraw_permission->withdraw_from_account
account_id_type withdraw_from_account;
/// Must match withdraw_permision->authorized_account
account_id_type withdraw_to_account;
/// Amount to withdraw. Must not exceed withdraw_permission->withdrawal_limit
asset amount_to_withdraw;
/// Memo for withdraw_from_account. Should generally be encrypted with withdraw_from_account->memo_key
optional<memo_data> memo;
account_id_type fee_payer()const { return withdraw_to_account; }
void validate()const;
share_type calculate_fee(const fee_parameters_type& k)const;
};
/**
* @brief Delete an existing withdrawal permission
* @ingroup operations
*
* This operation cancels a withdrawal permission, thus preventing any future withdrawals using that permission.
*
* Fee is paid by withdraw_from_account, which is required to authorize this operation
*/
struct withdraw_permission_delete_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
/// Must match withdrawal_permission->withdraw_from_account. This account pays the fee.
account_id_type withdraw_from_account;
/// The account previously authorized to make withdrawals. Must match withdrawal_permission->authorized_account
account_id_type authorized_account;
/// ID of the permission to be revoked.
withdraw_permission_id_type withdrawal_permission;
account_id_type fee_payer()const { return withdraw_from_account; }
void validate()const;
};
} } // graphene::chain
FC_REFLECT( graphene::chain::withdraw_permission_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::withdraw_permission_update_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::withdraw_permission_claim_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::withdraw_permission_delete_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::withdraw_permission_create_operation, (fee)(withdraw_from_account)(authorized_account)
(withdrawal_limit)(withdrawal_period_sec)(periods_until_expiration)(period_start_time) )
FC_REFLECT( graphene::chain::withdraw_permission_update_operation, (fee)(withdraw_from_account)(authorized_account)
(permission_to_update)(withdrawal_limit)(withdrawal_period_sec)(period_start_time)(periods_until_expiration) )
FC_REFLECT( graphene::chain::withdraw_permission_claim_operation, (fee)(withdraw_permission)(withdraw_from_account)(withdraw_to_account)(amount_to_withdraw)(memo) );
FC_REFLECT( graphene::chain::withdraw_permission_delete_operation, (fee)(withdraw_from_account)(authorized_account)
(withdrawal_permission) )

View file

@ -0,0 +1,59 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* @brief Create a witness object, as a bid to hold a witness position on the network.
* @ingroup operations
*
* Accounts which wish to become witnesses may use this operation to create a witness object which stakeholders may
* vote on to approve its position as a witness.
*/
struct witness_create_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
/// The account which owns the delegate. This account pays the fee for this operation.
account_id_type witness_account;
string url;
public_key_type block_signing_key;
secret_hash_type initial_secret;
account_id_type fee_payer()const { return witness_account; }
void validate()const;
};
/**
* @ingroup operations
* Used to move witness pay from accumulated_income to their account balance.
*
* TODO: remove this operation, send witness pay into a vesting balance object and
* have the witness claim the funds from there.
*/
struct witness_withdraw_pay_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
/// The account to pay. Must match from_witness->witness_account. This account pays the fee for this operation.
account_id_type to_account;
witness_id_type from_witness;
share_type amount;
account_id_type fee_payer()const { return to_account; }
void validate()const;
};
/// TODO: witness_resign_operation : public base_operation
} } // graphene::chain
FC_REFLECT( graphene::chain::witness_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::witness_withdraw_pay_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::witness_create_operation, (fee)(witness_account)(url)(block_signing_key)(initial_secret) )
FC_REFLECT( graphene::chain::witness_withdraw_pay_operation, (fee)(from_witness)(to_account)(amount) )

View file

@ -0,0 +1,82 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
namespace graphene { namespace chain {
/**
* @defgroup workers The Blockchain Worker System
* @ingroup operations
*
* Graphene blockchains allow the creation of special "workers" which are elected positions paid by the blockchain
* for services they provide. There may be several types of workers, and the semantics of how and when they are paid
* are defined by the @ref worker_type_enum enumeration. All workers are elected by core stakeholder approval, by
* voting for or against them.
*
* Workers are paid from the blockchain's daily budget if their total approval (votes for - votes against) is
* positive, ordered from most positive approval to least, until the budget is exhausted. Payments are processed at
* the blockchain maintenance interval. If a worker does not have positive approval during payment processing, or if
* the chain's budget is exhausted before the worker is paid, that worker is simply not paid at that interval.
* Payment is not prorated based on percentage of the interval the worker was approved. If the chain attempts to pay
* a worker, but the budget is insufficient to cover its entire pay, the worker is paid the remaining budget funds,
* even though this does not fulfill his total pay. The worker will not receive extra pay to make up the difference
* later. Worker pay is placed in a vesting balance and vests over the number of days specified at the worker's
* creation.
*
* Once created, a worker is immutable and will be kept by the blockchain forever.
*
* @{
*/
struct vesting_balance_worker_initializer
{
uint16_t pay_vesting_period_days = 0;
};
struct burn_worker_initializer
{};
struct refund_worker_initializer
{};
typedef static_variant<
refund_worker_initializer,
vesting_balance_worker_initializer,
burn_worker_initializer > worker_initializer;
/**
* @brief Create a new worker object
* @ingroup operations
*/
struct worker_create_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 5000*GRAPHENE_BLOCKCHAIN_PRECISION; };
asset fee;
account_id_type owner;
time_point_sec work_begin_date;
time_point_sec work_end_date;
share_type daily_pay;
string name;
string url;
/// This should be set to the initializer appropriate for the type of worker to be created.
worker_initializer initializer;
account_id_type fee_payer()const { return owner; }
void validate()const;
};
///@}
} }
FC_REFLECT( graphene::chain::vesting_balance_worker_initializer, (pay_vesting_period_days) )
FC_REFLECT( graphene::chain::burn_worker_initializer, )
FC_REFLECT( graphene::chain::refund_worker_initializer, )
FC_REFLECT_TYPENAME( graphene::chain::worker_initializer )
FC_REFLECT( graphene::chain::worker_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::worker_create_operation,
(fee)(owner)(work_begin_date)(work_end_date)(daily_pay)(name)(url)(initializer) )

View file

@ -16,9 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/operations.hpp>
#include <graphene/chain/authority.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/operations.hpp>
namespace graphene { namespace chain {
class database;

View file

@ -18,7 +18,7 @@
#pragma once
#include <fc/io/raw.hpp>
#include <graphene/chain/transaction.hpp>
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/db/index.hpp>
#include <graphene/db/generic_index.hpp>
#include <fc/uint128.hpp>

View file

@ -16,8 +16,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/database.hpp>
namespace graphene { namespace chain {

View file

@ -17,14 +17,16 @@
*/
#pragma once
#include <algorithm>
#include <graphene/chain/protocol/asset.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
#include <fc/static_variant.hpp>
#include <fc/uint128.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
#include <algorithm>
namespace graphene { namespace chain {
using namespace graphene::db;

View file

@ -16,8 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/authority.hpp>
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/authority.hpp>
#include <graphene/db/generic_index.hpp>
namespace graphene { namespace chain {

View file

@ -16,7 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/asset.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>

View file

@ -20,7 +20,7 @@
// needed to serialize witness_scheduler
#include <fc/container/deque.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/witness_scheduler.hpp>
#include <graphene/chain/witness_scheduler_rng.hpp>

View file

@ -17,10 +17,121 @@
*/
#pragma once
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/worker_object.hpp>
namespace graphene { namespace chain {
/**
* @defgroup worker_types Implementations of the various worker types in the system
*
* The system has various worker types, which do different things with the money they are paid. These worker types
* and their semantics are specified here.
*
* All worker types exist as a struct containing the data this worker needs to evaluate, as well as a method
* pay_worker, which takes a pay amount and a non-const database reference, and applies the worker's specific pay
* semantics to the worker_type struct and/or the database. Furthermore, all worker types have an initializer,
* which is a struct containing the data needed to create that kind of worker.
*
* Each initializer type has a method, init, which takes a non-const database reference, a const reference to the
* worker object being created, and a non-const reference to the specific *_worker_type object to initialize. The
* init method creates any further objects, and initializes the worker_type object as necessary according to the
* semantics of that particular worker type.
*
* To create a new worker type, define a my_new_worker_type struct with a pay_worker method which updates the
* my_new_worker_type object and/or the database. Create a my_new_worker_type::initializer struct with an init
* method and any data members necessary to create a new worker of this type. Reflect my_new_worker_type and
* my_new_worker_type::initializer into FC's type system, and add them to @ref worker_type and @ref
* worker_initializer respectively. Make sure the order of types in @ref worker_type and @ref worker_initializer
* remains the same.
* @{
*/
/**
* @brief A worker who returns all of his pay to the reserve
*
* This worker type pays everything he receives back to the network's reserve funds pool.
*/
struct refund_worker_type
{
/// Record of how much this worker has burned in his lifetime
share_type total_burned;
void pay_worker(share_type pay, database&);
};
/**
* @brief A worker who sends his pay to a vesting balance
*
* This worker type takes all of his pay and places it into a vesting balance
*/
struct vesting_balance_worker_type
{
/// The balance this worker pays into
vesting_balance_id_type balance;
void pay_worker(share_type pay, database& db);
};
/**
* @brief A worker who permanently destroys all of his pay
*
* This worker sends all pay he receives to the null account.
*/
struct burn_worker_type
{
/// Record of how much this worker has burned in his lifetime
share_type total_burned;
void pay_worker(share_type pay, database&);
};
///@}
// The ordering of types in these two static variants MUST be the same.
typedef static_variant<
refund_worker_type,
vesting_balance_worker_type,
burn_worker_type
> worker_type;
/**
* @brief Worker object contains the details of a blockchain worker. See @ref workers for details.
*/
class worker_object : public abstract_object<worker_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = worker_object_type;
/// ID of the account which owns this worker
account_id_type worker_account;
/// Time at which this worker begins receiving pay, if elected
time_point_sec work_begin_date;
/// Time at which this worker will cease to receive pay. Worker will be deleted at this time
time_point_sec work_end_date;
/// Amount in CORE this worker will be paid each day
share_type daily_pay;
/// ID of this worker's pay balance
worker_type worker;
/// Human-readable name for the worker
string name;
/// URL to a web page representing this worker
string url;
/// Voting ID which represents approval of this worker
vote_id_type vote_for;
/// Voting ID which represents disapproval of this worker
vote_id_type vote_against;
bool is_active(fc::time_point_sec now)const {
return now >= work_begin_date && now <= work_end_date;
}
share_type approving_stake(const vector<uint64_t>& stake_vote_tallies)const {
return stake_vote_tallies[vote_for] - stake_vote_tallies[vote_against];
}
};
typedef flat_index<worker_object> worker_index;
class worker_create_evaluator : public evaluator<worker_create_evaluator>
{
public:
@ -31,3 +142,19 @@ namespace graphene { namespace chain {
};
} } // graphene::chain
FC_REFLECT( graphene::chain::refund_worker_type, (total_burned) )
FC_REFLECT( graphene::chain::vesting_balance_worker_type, (balance) )
FC_REFLECT( graphene::chain::burn_worker_type, (total_burned) )
FC_REFLECT_TYPENAME( graphene::chain::worker_type )
FC_REFLECT_DERIVED( graphene::chain::worker_object, (graphene::db::object),
(worker_account)
(work_begin_date)
(work_end_date)
(daily_pay)
(worker)
(vote_for)
(vote_against)
(name)
(url)
)

View file

@ -1,230 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <graphene/chain/asset.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/flat_index.hpp>
#include <fc/static_variant.hpp>
namespace graphene { namespace chain {
using namespace graphene::db;
class database;
/**
* @defgroup worker_types Implementations of the various worker types in the system
*
* The system has various worker types, which do different things with the money they are paid. These worker types
* and their semantics are specified here.
*
* All worker types exist as a struct containing the data this worker needs to evaluate, as well as a method
* pay_worker, which takes a pay amount and a non-const database reference, and applies the worker's specific pay
* semantics to the worker_type struct and/or the database. Furthermore, all worker types have an initializer,
* which is a struct containing the data needed to create that kind of worker.
*
* Each initializer type has a method, init, which takes a non-const database reference, a const reference to the
* worker object being created, and a non-const reference to the specific *_worker_type object to initialize. The
* init method creates any further objects, and initializes the worker_type object as necessary according to the
* semantics of that particular worker type.
*
* To create a new worker type, define a my_new_worker_type struct with a pay_worker method which updates the
* my_new_worker_type object and/or the database. Create a my_new_worker_type::initializer struct with an init
* method and any data members necessary to create a new worker of this type. Reflect my_new_worker_type and
* my_new_worker_type::initializer into FC's type system, and add them to @ref worker_type and @ref
* worker_initializer respectively. Make sure the order of types in @ref worker_type and @ref worker_initializer
* remains the same.
* @{
*/
/**
* @brief A worker who returns all of his pay to the reserve
*
* This worker type pays everything he receives back to the network's reserve funds pool.
*/
struct refund_worker_type
{
/// Record of how much this worker has burned in his lifetime
share_type total_burned;
void pay_worker(share_type pay, database&);
struct initializer
{
void init(database&, const worker_object&, refund_worker_type&)const
{}
};
};
/**
* @brief A worker who sends his pay to a vesting balance
*
* This worker type takes all of his pay and places it into a vesting balance
*/
struct vesting_balance_worker_type
{
/// The balance this worker pays into
vesting_balance_id_type balance;
void pay_worker(share_type pay, database& db);
struct initializer
{
initializer(uint16_t vesting_period = 0)
: pay_vesting_period_days(vesting_period) {}
void init(database& db, const worker_object& obj, vesting_balance_worker_type& worker)const;
uint16_t pay_vesting_period_days;
};
};
/**
* @brief A worker who permanently destroys all of his pay
*
* This worker sends all pay he receives to the null account.
*/
struct burn_worker_type
{
/// Record of how much this worker has burned in his lifetime
share_type total_burned;
void pay_worker(share_type pay, database&);
struct initializer
{
void init(database&, const worker_object&, burn_worker_type& worker)const
{}
};
};
///@}
// The ordering of types in these two static variants MUST be the same.
typedef static_variant<
refund_worker_type,
vesting_balance_worker_type,
burn_worker_type
> worker_type;
typedef static_variant<
refund_worker_type::initializer,
vesting_balance_worker_type::initializer,
burn_worker_type::initializer
> worker_initializer;
/// @brief A visitor for @ref worker_type which initializes the worker within
struct worker_initialize_visitor
{
private:
const worker_object& worker_obj;
const worker_initializer& initializer;
database& db;
public:
worker_initialize_visitor(const worker_object& worker, const worker_initializer& initializer, database& db)
: worker_obj(worker),initializer(initializer),db(db) {}
typedef void result_type;
template<typename WorkerType>
void operator()( WorkerType& worker)const
{
static_assert(worker_type::tag<WorkerType>::value ==
worker_initializer::tag<typename WorkerType::initializer>::value,
"Tag values for worker_type and worker_initializer do not match! "
"Are the types in these static_variants in the same order?");
initializer.get<typename WorkerType::initializer>().init(db, worker_obj, worker);
}
};
/// @brief A visitor for @ref worker_type which calls pay_worker on the worker within
struct worker_pay_visitor
{
private:
share_type pay;
database& db;
public:
worker_pay_visitor(share_type pay, database& db)
: pay(pay), db(db) {}
typedef void result_type;
template<typename W>
void operator()(W& worker)const
{
worker.pay_worker(pay, db);
}
};
/**
* @brief Worker object contains the details of a blockchain worker. See @ref workers for details.
*/
class worker_object : public abstract_object<worker_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = worker_object_type;
/// ID of the account which owns this worker
account_id_type worker_account;
/// Time at which this worker begins receiving pay, if elected
time_point_sec work_begin_date;
/// Time at which this worker will cease to receive pay. Worker will be deleted at this time
time_point_sec work_end_date;
/// Amount in CORE this worker will be paid each day
share_type daily_pay;
/// ID of this worker's pay balance
worker_type worker;
/// Human-readable name for the worker
string name;
/// URL to a web page representing this worker
string url;
/// Voting ID which represents approval of this worker
vote_id_type vote_for;
/// Voting ID which represents disapproval of this worker
vote_id_type vote_against;
bool is_active(fc::time_point_sec now)const {
return now >= work_begin_date && now <= work_end_date;
}
share_type approving_stake(const vector<uint64_t>& stake_vote_tallies)const {
return stake_vote_tallies[vote_for] - stake_vote_tallies[vote_against];
}
};
typedef flat_index<worker_object> worker_index;
} } // graphene::chain
FC_REFLECT( graphene::chain::refund_worker_type, (total_burned) )
FC_REFLECT( graphene::chain::refund_worker_type::initializer, )
FC_REFLECT( graphene::chain::vesting_balance_worker_type, (balance) )
FC_REFLECT( graphene::chain::vesting_balance_worker_type::initializer, (pay_vesting_period_days) )
FC_REFLECT( graphene::chain::burn_worker_type, (total_burned) )
FC_REFLECT( graphene::chain::burn_worker_type::initializer, )
FC_REFLECT_TYPENAME( graphene::chain::worker_type )
FC_REFLECT_TYPENAME( graphene::chain::worker_initializer )
FC_REFLECT_DERIVED( graphene::chain::worker_object, (graphene::db::object),
(worker_account)
(work_begin_date)
(work_end_date)
(daily_pay)
(worker)
(vote_for)
(vote_against)
(name)
(url)
)

View file

@ -1,102 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/limit_order_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <fc/uint128.hpp>
namespace graphene { namespace chain {
void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_operation& op)
{ try {
database& d = db();
FC_ASSERT( op.expiration >= d.head_block_time() );
_seller = this->fee_paying_account;
_sell_asset = &op.amount_to_sell.asset_id(d);
_receive_asset = &op.min_to_receive.asset_id(d);
if( _sell_asset->options.whitelist_markets.size() )
FC_ASSERT( _sell_asset->options.whitelist_markets.find(_receive_asset->id) != _sell_asset->options.whitelist_markets.end() );
if( _sell_asset->options.blacklist_markets.size() )
FC_ASSERT( _sell_asset->options.blacklist_markets.find(_receive_asset->id) == _sell_asset->options.blacklist_markets.end() );
if( _sell_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_sell_asset ) );
if( _receive_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_receive_asset ) );
FC_ASSERT( d.get_balance( *_seller, *_sell_asset ) >= op.amount_to_sell, "insufficient balance",
("balance",d.get_balance(*_seller,*_sell_asset))("amount_to_sell",op.amount_to_sell) );
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
object_id_type limit_order_create_evaluator::do_apply(const limit_order_create_operation& op)
{ try {
const auto& seller_stats = _seller->statistics(db());
db().modify(seller_stats, [&](account_statistics_object& bal) {
if( op.amount_to_sell.asset_id == asset_id_type() )
{
bal.total_core_in_orders += op.amount_to_sell.amount;
}
});
db().adjust_balance(op.seller, -op.amount_to_sell);
const auto& new_order_object = db().create<limit_order_object>([&](limit_order_object& obj){
obj.seller = _seller->id;
obj.for_sale = op.amount_to_sell.amount;
obj.sell_price = op.get_price();
obj.expiration = op.expiration;
});
limit_order_id_type order_id = new_order_object.id; // save this because we may remove the object by filling it
bool filled = db().apply_order(new_order_object);
FC_ASSERT( !op.fill_or_kill || filled );
return order_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result limit_order_cancel_evaluator::do_evaluate(const limit_order_cancel_operation& o)
{ try {
database& d = db();
_order = &o.order(d);
FC_ASSERT( _order->seller == o.fee_paying_account );
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
asset limit_order_cancel_evaluator::do_apply(const limit_order_cancel_operation& o)
{ try {
database& d = db();
auto base_asset = _order->sell_price.base.asset_id;
auto quote_asset = _order->sell_price.quote.asset_id;
auto refunded = _order->amount_for_sale();
db().cancel_order(*_order, false /* don't create a virtual op*/);
// Possible optimization: order can be called by canceling a limit order iff the canceled order was at the top of the book.
// Do I need to check calls in both assets?
db().check_call_orders(base_asset(d));
db().check_call_orders(quote_asset(d));
return refunded;
} FC_CAPTURE_AND_RETHROW( (o) ) }
} } // graphene::chain

View file

@ -15,14 +15,88 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/database.hpp>
#include <graphene/chain/call_order_evaluator.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/limit_order_object.hpp>
#include <fc/uint128.hpp>
namespace graphene { namespace chain {
void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_operation& op)
{ try {
database& d = db();
FC_ASSERT( op.expiration >= d.head_block_time() );
_seller = this->fee_paying_account;
_sell_asset = &op.amount_to_sell.asset_id(d);
_receive_asset = &op.min_to_receive.asset_id(d);
if( _sell_asset->options.whitelist_markets.size() )
FC_ASSERT( _sell_asset->options.whitelist_markets.find(_receive_asset->id) != _sell_asset->options.whitelist_markets.end() );
if( _sell_asset->options.blacklist_markets.size() )
FC_ASSERT( _sell_asset->options.blacklist_markets.find(_receive_asset->id) == _sell_asset->options.blacklist_markets.end() );
if( _sell_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_sell_asset ) );
if( _receive_asset->enforce_white_list() ) FC_ASSERT( _seller->is_authorized_asset( *_receive_asset ) );
FC_ASSERT( d.get_balance( *_seller, *_sell_asset ) >= op.amount_to_sell, "insufficient balance",
("balance",d.get_balance(*_seller,*_sell_asset))("amount_to_sell",op.amount_to_sell) );
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
object_id_type limit_order_create_evaluator::do_apply(const limit_order_create_operation& op)
{ try {
const auto& seller_stats = _seller->statistics(db());
db().modify(seller_stats, [&](account_statistics_object& bal) {
if( op.amount_to_sell.asset_id == asset_id_type() )
{
bal.total_core_in_orders += op.amount_to_sell.amount;
}
});
db().adjust_balance(op.seller, -op.amount_to_sell);
const auto& new_order_object = db().create<limit_order_object>([&](limit_order_object& obj){
obj.seller = _seller->id;
obj.for_sale = op.amount_to_sell.amount;
obj.sell_price = op.get_price();
obj.expiration = op.expiration;
});
limit_order_id_type order_id = new_order_object.id; // save this because we may remove the object by filling it
bool filled = db().apply_order(new_order_object);
FC_ASSERT( !op.fill_or_kill || filled );
return order_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result limit_order_cancel_evaluator::do_evaluate(const limit_order_cancel_operation& o)
{ try {
database& d = db();
_order = &o.order(d);
FC_ASSERT( _order->seller == o.fee_paying_account );
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
asset limit_order_cancel_evaluator::do_apply(const limit_order_cancel_operation& o)
{ try {
database& d = db();
auto base_asset = _order->sell_price.base.asset_id;
auto quote_asset = _order->sell_price.quote.asset_id;
auto refunded = _order->amount_for_sale();
db().cancel_order(*_order, false /* don't create a virtual op*/);
// Possible optimization: order can be called by canceling a limit order iff the canceled order was at the top of the book.
// Do I need to check calls in both assets?
db().check_call_orders(base_asset(d));
db().check_call_orders(quote_asset(d));
return refunded;
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result call_order_update_evaluator::do_evaluate(const call_order_update_operation& o)
{ try {

View file

@ -1,965 +0,0 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/database.hpp>
#include <graphene/chain/operations.hpp>
#include <graphene/chain/predicate.hpp>
#include <fc/crypto/aes.hpp>
namespace graphene { namespace chain {
/**
* Valid symbols can contain [A, Z], and '.'
* They must start with [A, Z]
* They must end with [A, Z]
* They can contain a maximum of one '.'
*/
bool is_valid_symbol( 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 ) && isupper( c ) )
continue;
if( c == '.' )
{
if( dot_already_present )
return false;
dot_already_present = true;
continue;
}
return false;
}
return true;
}
/**
* Names must comply with the following grammar (RFC 1035):
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> | <subdomain> "." <label>
* <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
* <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> ::= <let-dig> | "-"
* <let-dig> ::= <letter> | <digit>
*
* Which is equivalent to the following:
*
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> ("." <label>)*
* <label> ::= <letter> [ [ <let-dig-hyp>+ ] <let-dig> ]
* <let-dig-hyp> ::= <let-dig> | "-"
* <let-dig> ::= <letter> | <digit>
*
* I.e. a valid name consists of a dot-separated sequence
* of one or more labels consisting of the following rules:
*
* - Each label is three characters or more
* - Each label begins with a letter
* - Each label ends with a letter or digit
* - Each label contains only letters, digits or hyphens
*
* In addition we require the following:
*
* - All letters are lowercase
* - Length is between (inclusive) GRAPHENE_MIN_ACCOUNT_NAME_LENGTH and GRAPHENE_MAX_ACCOUNT_NAME_LENGTH
*/
bool is_valid_name( const string& name )
{
const size_t len = name.size();
if( len < GRAPHENE_MIN_ACCOUNT_NAME_LENGTH )
return false;
if( len > GRAPHENE_MAX_ACCOUNT_NAME_LENGTH )
return false;
size_t begin = 0;
while( true )
{
size_t end = name.find_first_of( '.', begin );
if( end == std::string::npos )
end = len;
if( end - begin < 3 )
return false;
switch( name[begin] )
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
break;
default:
return false;
}
switch( name[end-1] )
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
case '8': case '9':
break;
default:
return false;
}
for( size_t i=begin+1; i<end-1; i++ )
{
switch( name[i] )
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
case '8': case '9':
case '-':
break;
default:
return false;
}
}
if( end == len )
break;
begin = end+1;
}
return true;
}
bool is_cheap_name( const string& n )
{
bool v = false;
for( auto c : n )
{
if( c >= '0' && c <= '9' ) return true;
if( c == '.' || c == '-' || c == '/' ) return true;
switch( c )
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
v = true;
}
}
if( !v )
return true;
return false;
}
share_type account_create_operation::calculate_fee( const fee_schedule_type& schedule )const
{
auto core_fee_required = schedule.account_create_fee;
uint32_t s = name.size();
if( is_cheap_name(name) )
s = 8;
if( s >= 8 )
core_fee_required = schedule.account_len8up_fee;
else if( s == 7 )
core_fee_required = schedule.account_len7_fee;
else if( s == 6 )
core_fee_required = schedule.account_len6_fee;
else if( s == 5 )
core_fee_required = schedule.account_len5_fee;
else if( s == 4 )
core_fee_required = schedule.account_len4_fee;
else if( s == 3 )
core_fee_required = schedule.account_len3_fee;
else if( s <= 2 )
core_fee_required = schedule.account_len2_fee;
// Authorities and vote lists can be arbitrarily large, so charge a data fee for big ones
core_fee_required += schedule.total_data_fee(active, owner, options.votes);
return core_fee_required;
}
share_type account_update_operation::calculate_fee( const fee_schedule_type& schedule )const
{
auto core_fee_required = schedule.account_update_fee + schedule.total_data_fee(owner, active);
if( new_options )
core_fee_required += schedule.total_data_fee(new_options->votes);
return core_fee_required;
}
void account_update_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( account != account_id_type() );
FC_ASSERT( owner || active || new_options );
if( owner )
{
FC_ASSERT( owner->num_auths() != 0 );
FC_ASSERT( owner->address_auths.size() == 0 );
}
if( active )
{
FC_ASSERT( active->num_auths() != 0 );
FC_ASSERT( active->address_auths.size() == 0 );
}
if( new_options )
new_options->validate();
}
share_type asset_create_operation::calculate_fee(const fee_schedule_type& schedule)const
{
auto core_fee_required = schedule.asset_create_fee;
switch(symbol.size()) {
case 3: core_fee_required += schedule.asset_len3_fee;
break;
case 4: core_fee_required += schedule.asset_len4_fee;
break;
case 5: core_fee_required += schedule.asset_len5_fee;
break;
case 6: core_fee_required += schedule.asset_len6_fee;
break;
default: core_fee_required += schedule.asset_len7up_fee;
}
// common_options contains several lists and a string. Charge fees for its size
core_fee_required += schedule.total_data_fee(common_options);
return core_fee_required;
}
share_type transfer_operation::calculate_fee( const fee_schedule_type& schedule )const
{
share_type core_fee_required = schedule.transfer_fee;
if( memo )
core_fee_required += schedule.total_data_fee(memo->message);
return core_fee_required;
}
share_type override_transfer_operation::calculate_fee( const fee_schedule_type& schedule )const
{
share_type core_fee_required = schedule.transfer_fee;
if( memo )
core_fee_required += schedule.total_data_fee(memo->message);
return core_fee_required;
}
void account_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( is_valid_name( name ) );
FC_ASSERT( referrer_percent <= GRAPHENE_100_PERCENT );
FC_ASSERT( owner.num_auths() != 0 );
FC_ASSERT( owner.address_auths.size() == 0 );
// TODO: this asset causes many tests to fail, those tests should probably be updated
//FC_ASSERT( active.num_auths() != 0 );
FC_ASSERT( active.address_auths.size() == 0 );
options.validate();
}
share_type asset_publish_feed_operation::calculate_fee( const fee_schedule_type& schedule )const
{
return schedule.publish_feed_fee;
}
void asset_publish_feed_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
feed.validate();
}
void transfer_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( from != to );
FC_ASSERT( amount.amount > 0 );
}
void override_transfer_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( from != to );
FC_ASSERT( amount.amount > 0 );
FC_ASSERT( issuer != from );
}
void asset_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( is_valid_symbol(symbol) );
common_options.validate();
if( common_options.issuer_permissions & (disable_force_settle|global_settle) )
FC_ASSERT( bitasset_options.valid() );
if( is_prediction_market )
{
FC_ASSERT( bitasset_options.valid(), "Cannot have a User-Issued Asset implement a prediction market." );
FC_ASSERT( common_options.issuer_permissions & global_settle );
}
if( bitasset_options ) bitasset_options->validate();
asset dummy = asset(1) * common_options.core_exchange_rate;
FC_ASSERT(dummy.asset_id == asset_id_type(1));
FC_ASSERT(precision <= 12);
}
asset_update_operation::asset_update_operation(const asset_object& old)
{
issuer = old.issuer;
asset_to_update = old.get_id();
new_options = old.options;
}
void asset_update_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
if( new_issuer )
FC_ASSERT(issuer != *new_issuer);
new_options.validate();
asset dummy = asset(1, asset_to_update) * new_options.core_exchange_rate;
FC_ASSERT(dummy.asset_id == asset_id_type());
}
share_type asset_update_operation::calculate_fee(const fee_schedule_type& k)const
{
return k.asset_update_fee + k.total_data_fee(new_options);
}
void asset_reserve_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount_to_reserve.amount.value <= GRAPHENE_MAX_SHARE_SUPPLY );
FC_ASSERT( amount_to_reserve.amount.value > 0 );
}
share_type asset_reserve_operation::calculate_fee(const fee_schedule_type& k)const
{
return k.asset_reserve_fee;
}
void asset_issue_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( asset_to_issue.amount.value <= GRAPHENE_MAX_SHARE_SUPPLY );
FC_ASSERT( asset_to_issue.amount.value > 0 );
FC_ASSERT( asset_to_issue.asset_id != 0 );
}
share_type asset_issue_operation::calculate_fee( const fee_schedule_type& k )const
{
return k.asset_issue_fee;
}
share_type delegate_create_operation::calculate_fee( const fee_schedule_type& k )const
{
return k.delegate_create_fee + k.total_data_fee(url);
}
void delegate_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT(url.size() < GRAPHENE_MAX_URL_LENGTH );
}
void asset_fund_fee_pool_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( fee.asset_id == asset_id_type() );
FC_ASSERT( amount > 0 );
}
share_type asset_fund_fee_pool_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.asset_fund_fee_pool_fee;
}
void limit_order_create_operation::validate()const
{
FC_ASSERT( amount_to_sell.asset_id != min_to_receive.asset_id );
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount_to_sell.amount > 0 );
FC_ASSERT( min_to_receive.amount > 0 );
}
share_type limit_order_create_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.limit_order_create_fee;
}
void limit_order_cancel_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type limit_order_cancel_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.get_extended_fee(fee_schedule_type::limit_order_cancel_fee_id);
}
void call_order_update_operation::validate()const
{ try {
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( delta_collateral.asset_id != delta_debt.asset_id );
FC_ASSERT( delta_collateral.amount != 0 || delta_debt.amount != 0 );
} FC_CAPTURE_AND_RETHROW((*this)) }
share_type call_order_update_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.call_order_fee;
}
proposal_create_operation proposal_create_operation::genesis_proposal(const database& db)
{
auto global_params = db.get_global_properties().parameters;
proposal_create_operation op = {account_id_type(), asset(), {},
db.head_block_time() + global_params.maximum_proposal_lifetime,
global_params.genesis_proposal_review_period};
op.fee = op.calculate_fee(global_params.current_fees);
return op;
}
void proposal_create_operation::validate() const
{
FC_ASSERT( !proposed_ops.empty() );
for( const auto& op : proposed_ops ) op.validate();
}
share_type proposal_create_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.proposal_create_fee + k.total_data_fee(proposed_ops);
}
void proposal_update_operation::validate() const
{
FC_ASSERT(fee.amount >= 0);
FC_ASSERT(!(active_approvals_to_add.empty() && active_approvals_to_remove.empty() &&
owner_approvals_to_add.empty() && owner_approvals_to_remove.empty() &&
key_approvals_to_add.empty() && key_approvals_to_remove.empty()));
for( auto a : active_approvals_to_add )
{
FC_ASSERT(active_approvals_to_remove.find(a) == active_approvals_to_remove.end(),
"Cannot add and remove approval at the same time.");
}
for( auto a : owner_approvals_to_add )
{
FC_ASSERT(owner_approvals_to_remove.find(a) == owner_approvals_to_remove.end(),
"Cannot add and remove approval at the same time.");
}
for( auto a : key_approvals_to_add )
{
FC_ASSERT(key_approvals_to_remove.find(a) == key_approvals_to_remove.end(),
"Cannot add and remove approval at the same time.");
}
}
share_type proposal_update_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.proposal_create_fee + k.total_data_fee(active_approvals_to_add,
active_approvals_to_remove,
owner_approvals_to_add,
owner_approvals_to_remove,
key_approvals_to_add,
key_approvals_to_remove);
}
share_type proposal_delete_operation::calculate_fee(const fee_schedule_type& k)const
{ return k.get_extended_fee( fee_schedule_type::proposal_delete_fee_id ); }
void account_transfer_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type account_transfer_operation::calculate_fee( const fee_schedule_type& k )const
{
return k.account_transfer_fee;
}
void proposal_delete_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
}
void witness_withdraw_pay_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount >= 0 );
}
share_type witness_withdraw_pay_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.witness_withdraw_pay_fee;
}
void global_parameters_update_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
new_parameters.validate();
}
share_type global_parameters_update_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.global_parameters_update_fee;
}
void witness_create_operation::validate() const
{
FC_ASSERT(fee.amount >= 0);
FC_ASSERT(url.size() < GRAPHENE_MAX_URL_LENGTH );
}
share_type witness_create_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.witness_create_fee + k.total_data_fee(url);
}
void withdraw_permission_update_operation::validate()const
{
FC_ASSERT( withdrawal_limit.amount > 0 );
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( withdrawal_period_sec > 0 );
FC_ASSERT( withdraw_from_account != authorized_account );
FC_ASSERT( periods_until_expiration > 0 );
}
share_type withdraw_permission_update_operation::calculate_fee( const fee_schedule_type& schedule )const
{
return schedule.withdraw_permission_update_fee;
}
void withdraw_permission_claim_operation::validate()const
{
FC_ASSERT( withdraw_to_account != withdraw_from_account );
FC_ASSERT( amount_to_withdraw.amount > 0 );
FC_ASSERT( fee.amount >= 0 );
}
share_type withdraw_permission_claim_operation::calculate_fee(const fee_schedule_type& k)const
{
share_type core_fee_required = k.withdraw_permission_claim_fee;
if( memo )
core_fee_required += k.total_data_fee(memo->message);
return core_fee_required;
}
void withdraw_permission_delete_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( withdraw_from_account != authorized_account );
}
share_type withdraw_permission_delete_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.get_extended_fee( fee_schedule_type::withdraw_permission_delete_fee_id );
}
void withdraw_permission_create_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( withdraw_from_account != authorized_account );
FC_ASSERT( withdrawal_limit.amount > 0 );
//TODO: better bounds checking on these values
FC_ASSERT( withdrawal_period_sec > 0 );
FC_ASSERT( periods_until_expiration > 0 );
}
share_type withdraw_permission_create_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.withdraw_permission_create_fee;
}
void asset_global_settle_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( asset_to_settle == settle_price.base.asset_id );
}
share_type asset_global_settle_operation::calculate_fee(const fee_schedule_type& k)const
{
return k.asset_global_settle_fee;
}
void asset_settle_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount.amount >= 0 );
}
share_type asset_settle_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.asset_settle_fee;
}
void asset_update_bitasset_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
new_options.validate();
}
share_type asset_update_bitasset_operation::calculate_fee(const fee_schedule_type& k) const
{
return k.asset_update_fee;
}
void asset_update_feed_producers_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type asset_update_feed_producers_operation::calculate_fee(const fee_schedule_type &k) const
{
return k.asset_update_fee + k.total_data_fee(new_feed_producers);
}
share_type vesting_balance_create_operation::calculate_fee(const fee_schedule_type& k)const
{
// We don't want to have custom inspection for each policy type; instead, charge a data fee for big ones
return k.vesting_balance_create_fee + k.total_data_fee(policy);
}
void vesting_balance_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount.amount > 0 );
}
void vesting_balance_withdraw_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount.amount > 0 );
}
share_type vesting_balance_withdraw_operation::calculate_fee(const fee_schedule_type& k)const
{
return k.vesting_balance_withdraw_fee;
}
void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub,
const string& msg, uint64_t custom_nonce)
{
if( from != public_key_type() )
{
if( custom_nonce == 0 )
{
uint64_t entropy = fc::sha224::hash(fc::ecc::private_key::generate())._hash[0];
entropy <<= 32;
entropy &= 0xff00000000000000;
nonce = (fc::time_point::now().time_since_epoch().count() & 0x00ffffffffffffff) | entropy;
} else
nonce = custom_nonce;
auto secret = priv.get_shared_secret(pub);
auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());
string text = memo_message(digest_type::hash(msg)._hash[0], msg).serialize();
message = fc::aes_encrypt( nonce_plus_secret, vector<char>(text.begin(), text.end()) );
}
else
{
auto text = memo_message(0, msg).serialize();
message = vector<char>(text.begin(), text.end());
}
}
string memo_data::get_message(const fc::ecc::private_key& priv,
const fc::ecc::public_key& pub)const
{
if( from != public_key_type() )
{
auto secret = priv.get_shared_secret(pub);
auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());
auto plain_text = fc::aes_decrypt( nonce_plus_secret, message );
auto result = memo_message::deserialize(string(plain_text.begin(), plain_text.end()));
FC_ASSERT( result.checksum == uint32_t(digest_type::hash(result.text)._hash[0]) );
return result.text;
}
else
{
return memo_message::deserialize(string(message.begin(), message.end())).text;
}
}
void custom_operation::validate()const
{
FC_ASSERT( fee.amount > 0 );
}
share_type custom_operation::calculate_fee(const fee_schedule_type& k)const
{
return k.custom_operation_fee + k.total_data_fee(required_auths, data);
}
void worker_create_operation::validate() const
{
FC_ASSERT(fee.amount >= 0);
FC_ASSERT(work_end_date > work_begin_date);
FC_ASSERT(daily_pay > 0);
FC_ASSERT(daily_pay < GRAPHENE_MAX_SHARE_SUPPLY);
FC_ASSERT(name.size() < GRAPHENE_MAX_WORKER_NAME_LENGTH );
FC_ASSERT(url.size() < GRAPHENE_MAX_URL_LENGTH );
}
share_type worker_create_operation::calculate_fee(const fee_schedule_type& k) const
{
// Charge data fees for excessively long name, URL, or large initializers
return k.worker_create_fee + k.total_data_fee(name, url, initializer);
}
string memo_message::serialize() const
{
auto serial_checksum = string(sizeof(checksum), ' ');
(uint32_t&)(*serial_checksum.data()) = checksum;
return serial_checksum + text;
}
memo_message memo_message::deserialize(const string& serial)
{
memo_message result;
FC_ASSERT( serial.size() >= sizeof(result.checksum) );
result.checksum = ((uint32_t&)(*serial.data()));
result.text = serial.substr(sizeof(result.checksum));
return result;
}
void account_upgrade_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type account_upgrade_operation::calculate_fee(const fee_schedule_type& k) const
{
if( upgrade_to_lifetime_member )
return k.membership_lifetime_fee;
return k.membership_annual_fee;
}
struct predicate_validator
{
typedef void result_type;
template<typename T>
void operator()( const T& p )const
{
p.validate();
}
};
void assert_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
for( const auto& item : predicates )
{
FC_ASSERT( item.size() > 0 );
fc::datastream<const char*> ds( item.data(), item.size() );
predicate p;
try {
fc::raw::unpack( ds, p );
}
catch ( const fc::exception& e )
{
continue;
}
p.visit( predicate_validator() );
}
}
/**
* The fee for assert operations is proportional to their size,
* but cheaper than a data fee because they require no storage
*/
share_type assert_operation::calculate_fee(const fee_schedule_type& k)const
{
return std::max(size_t(1), fc::raw::pack_size(*this) / 1024) * k.assert_op_fee;
}
void balance_claim_operation::validate()const
{
FC_ASSERT( fee == asset() );
FC_ASSERT( balance_owner_key != public_key_type() );
}
struct required_auth_visitor
{
typedef void result_type;
vector<authority>& result;
required_auth_visitor( vector<authority>& r ):result(r){}
/** for most operations this is a no-op */
template<typename T>
void operator()(const T& )const {}
void operator()( const balance_claim_operation& o )const
{
result.push_back( authority( 1, o.balance_owner_key, 1 ) );
}
};
struct required_active_visitor
{
typedef void result_type;
flat_set<account_id_type>& result;
required_active_visitor( flat_set<account_id_type>& r ):result(r){}
/** for most operations this is just the fee payer */
template<typename T>
void operator()(const T& o)const
{
result.insert( o.fee_payer() );
}
void operator()(const account_update_operation& o)const
{
/// if owner authority is required, no active authority is required
if( !(o.owner || o.active) ) /// TODO: document why active cannot be updated by active?
result.insert( o.fee_payer() );
}
void operator()( const proposal_delete_operation& o )const
{
if( !o.using_owner_authority )
result.insert( o.fee_payer() );
}
void operator()( const proposal_update_operation& o )const
{
result.insert( o.fee_payer() );
for( auto id : o.active_approvals_to_add )
result.insert(id);
for( auto id : o.active_approvals_to_remove )
result.insert(id);
}
void operator()( const custom_operation& o )const
{
result.insert( o.required_auths.begin(), o.required_auths.end() );
}
void operator()( const assert_operation& o )const
{
result.insert( o.fee_payer() );
result.insert( o.required_auths.begin(), o.required_auths.end() );
}
};
struct required_owner_visitor
{
typedef void result_type;
flat_set<account_id_type>& result;
required_owner_visitor( flat_set<account_id_type>& r ):result(r){}
/** for most operations this is a no-op */
template<typename T>
void operator()(const T& o)const {}
void operator()(const account_update_operation& o)const
{
if( o.owner || o.active ) /// TODO: document why active cannot be updated by active?
result.insert( o.account );
}
void operator()( const proposal_delete_operation& o )const
{
if( o.using_owner_authority )
result.insert( o.fee_payer() );
}
void operator()( const proposal_update_operation& o )const
{
for( auto id : o.owner_approvals_to_add )
result.insert(id);
for( auto id : o.owner_approvals_to_remove )
result.insert(id);
}
};
void operation_get_required_authorities( const operation& op, vector<authority>& result )
{
op.visit( required_auth_visitor( result ) );
}
void operation_get_required_active_authorities( const operation& op, flat_set<account_id_type>& result )
{
op.visit( required_active_visitor( result ) );
}
void operation_get_required_owner_authorities( const operation& op, flat_set<account_id_type>& result )
{
op.visit( required_owner_visitor( result ) );
}
/**
* @brief Used to validate operations in a polymorphic manner
*/
struct operation_validator
{
typedef void result_type;
template<typename T>
void operator()( const T& v )const { v.validate(); }
};
void operation_validate( const operation& op )
{
op.visit( operation_validator() );
}
void op_wrapper::validate()const
{
operation_validate(op);
}
} } // namespace graphene::chain

View file

@ -18,6 +18,7 @@
#include <graphene/chain/proposal_evaluator.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
namespace graphene { namespace chain {
@ -35,11 +36,14 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati
{
// If we're dealing with the genesis authority, make sure this transaction has a sufficient review period.
flat_set<account_id_type> auths;
vector<authority> other;
for( auto& op : o.proposed_ops )
{
operation_get_required_active_authorities(op.op, auths);
operation_get_required_owner_authorities(op.op, auths);
operation_get_required_authorities(op.op, auths, auths, other);
}
FC_ASSERT( other.size() == 0 ); // TODO: what about other???
if( auths.find(account_id_type()) != auths.end() )
FC_ASSERT( o.review_period_seconds
&& *o.review_period_seconds >= global_parameters.genesis_proposal_review_period );
@ -64,12 +68,11 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati
//Populate the required approval sets
flat_set<account_id_type> required_active;
vector<authority> other;
// TODO: consider caching values from evaluate?
for( auto& op : _proposed_trx.operations )
{
operation_get_required_active_authorities(op, required_active);
operation_get_required_owner_authorities(op, proposal.required_owner_approvals);
}
operation_get_required_authorities(op, required_active, proposal.required_owner_approvals, other);
//All accounts which must provide both owner and active authority should be omitted from the active authority set;
//owner authority approval implies active authority approval.

View file

@ -0,0 +1,198 @@
#include <graphene/chain/protocol/account.hpp>
namespace graphene { namespace chain {
/**
* Names must comply with the following grammar (RFC 1035):
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> | <subdomain> "." <label>
* <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
* <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> ::= <let-dig> | "-"
* <let-dig> ::= <letter> | <digit>
*
* Which is equivalent to the following:
*
* <domain> ::= <subdomain> | " "
* <subdomain> ::= <label> ("." <label>)*
* <label> ::= <letter> [ [ <let-dig-hyp>+ ] <let-dig> ]
* <let-dig-hyp> ::= <let-dig> | "-"
* <let-dig> ::= <letter> | <digit>
*
* I.e. a valid name consists of a dot-separated sequence
* of one or more labels consisting of the following rules:
*
* - Each label is three characters or more
* - Each label begins with a letter
* - Each label ends with a letter or digit
* - Each label contains only letters, digits or hyphens
*
* In addition we require the following:
*
* - All letters are lowercase
* - Length is between (inclusive) GRAPHENE_MIN_ACCOUNT_NAME_LENGTH and GRAPHENE_MAX_ACCOUNT_NAME_LENGTH
*/
bool is_valid_name( const string& name )
{
const size_t len = name.size();
if( len < GRAPHENE_MIN_ACCOUNT_NAME_LENGTH )
return false;
if( len > GRAPHENE_MAX_ACCOUNT_NAME_LENGTH )
return false;
size_t begin = 0;
while( true )
{
size_t end = name.find_first_of( '.', begin );
if( end == std::string::npos )
end = len;
if( end - begin < 3 )
return false;
switch( name[begin] )
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
break;
default:
return false;
}
switch( name[end-1] )
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
case '8': case '9':
break;
default:
return false;
}
for( size_t i=begin+1; i<end-1; i++ )
{
switch( name[i] )
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
case '8': case '9':
case '-':
break;
default:
return false;
}
}
if( end == len )
break;
begin = end+1;
}
return true;
}
bool is_cheap_name( const string& n )
{
bool v = false;
for( auto c : n )
{
if( c >= '0' && c <= '9' ) return true;
if( c == '.' || c == '-' || c == '/' ) return true;
switch( c )
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
v = true;
}
}
if( !v )
return true;
return false;
}
share_type account_create_operation::calculate_fee( const fee_parameters_type& k )const
{
auto core_fee_required = k.basic_fee;
if( !is_cheap_name(name) )
core_fee_required = k.premium_fee;
// Authorities and vote lists can be arbitrarily large, so charge a data fee for big ones
core_fee_required += calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte );
return core_fee_required;
}
void account_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( is_valid_name( name ) );
FC_ASSERT( referrer_percent <= GRAPHENE_100_PERCENT );
FC_ASSERT( owner.num_auths() != 0 );
FC_ASSERT( owner.address_auths.size() == 0 );
// TODO: this asset causes many tests to fail, those tests should probably be updated
//FC_ASSERT( active.num_auths() != 0 );
FC_ASSERT( active.address_auths.size() == 0 );
options.validate();
}
share_type account_update_operation::calculate_fee( const fee_parameters_type& k )const
{
auto core_fee_required = k.fee;
if( new_options )
core_fee_required += calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte );
return core_fee_required;
}
void account_update_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( account != account_id_type() );
FC_ASSERT( owner || active || new_options );
if( owner )
{
FC_ASSERT( owner->num_auths() != 0 );
FC_ASSERT( owner->address_auths.size() == 0 );
}
if( active )
{
FC_ASSERT( active->num_auths() != 0 );
FC_ASSERT( active->address_auths.size() == 0 );
}
if( new_options )
new_options->validate();
}
share_type account_upgrade_operation::calculate_fee(const fee_parameters_type& k) const
{
if( upgrade_to_lifetime_member )
return k.membership_lifetime_fee;
return k.membership_annual_fee;
}
void account_upgrade_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
}
void account_transfer_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
}
} } // graphene::chain

View file

@ -15,8 +15,8 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/address.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/protocol/address.hpp>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/base58.hpp>
#include <algorithm>

View file

@ -27,4 +27,32 @@ bool asset_symbol_eq_lit::evaluate( const database& db )const
return asset_id(db).symbol == symbol;
}
struct predicate_validator
{
typedef void result_type;
template<typename T>
void operator()( const T& p )const
{
p.validate();
}
};
void assert_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
for( const auto& item : predicates )
item.visit( predicate_validator() );
}
/**
* The fee for assert operations is proportional to their size,
* but cheaper than a data fee because they require no storage
*/
share_type assert_operation::calculate_fee(const fee_parameters_type& k)const
{
return k.fee * predicates.size();
}
} } }

View file

@ -15,7 +15,7 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/asset.hpp>
#include <graphene/chain/protocol/asset.hpp>
#include <fc/uint128.hpp>
#include <boost/rational.hpp>

View file

@ -0,0 +1,196 @@
#include <graphene/chain/protocol/asset_ops.hpp>
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( 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;
}
share_type asset_create_operation::calculate_fee(const asset_create_operation::fee_parameters_type& param)const
{
auto core_fee_required = param.long_symbol;
switch(symbol.size()) {
case 3: core_fee_required = param.symbol3;
break;
case 4: core_fee_required = param.symbol4;
break;
default:
break;
}
// common_options contains several lists and a string. Charge fees for its size
core_fee_required += calculate_data_fee( fc::raw::pack_size(*this), param.price_per_kbyte );
return core_fee_required;
}
void asset_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( is_valid_symbol(symbol) );
common_options.validate();
if( common_options.issuer_permissions & (disable_force_settle|global_settle) )
FC_ASSERT( bitasset_options.valid() );
if( is_prediction_market )
{
FC_ASSERT( bitasset_options.valid(), "Cannot have a User-Issued Asset implement a prediction market." );
FC_ASSERT( common_options.issuer_permissions & global_settle );
}
if( bitasset_options ) bitasset_options->validate();
asset dummy = asset(1) * common_options.core_exchange_rate;
FC_ASSERT(dummy.asset_id == asset_id_type(1));
FC_ASSERT(precision <= 12);
}
/*
asset_update_operation::asset_update_operation(const asset_object& old)
{
issuer = old.issuer;
asset_to_update = old.get_id();
new_options = old.options;
}
*/
void asset_update_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
if( new_issuer )
FC_ASSERT(issuer != *new_issuer);
new_options.validate();
asset dummy = asset(1, asset_to_update) * new_options.core_exchange_rate;
FC_ASSERT(dummy.asset_id == asset_id_type());
}
share_type asset_update_operation::calculate_fee(const asset_update_operation::fee_parameters_type& k)const
{
return k.fee + calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte );
}
void asset_publish_feed_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
feed.validate();
}
void asset_reserve_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount_to_reserve.amount.value <= GRAPHENE_MAX_SHARE_SUPPLY );
FC_ASSERT( amount_to_reserve.amount.value > 0 );
}
void asset_issue_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( asset_to_issue.amount.value <= GRAPHENE_MAX_SHARE_SUPPLY );
FC_ASSERT( asset_to_issue.amount.value > 0 );
FC_ASSERT( asset_to_issue.asset_id != 0 );
}
void asset_fund_fee_pool_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( fee.asset_id == asset_id_type() );
FC_ASSERT( amount > 0 );
}
void asset_settle_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount.amount >= 0 );
}
void asset_update_bitasset_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
new_options.validate();
}
void asset_update_feed_producers_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
}
void asset_global_settle_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( asset_to_settle == settle_price.base.asset_id );
}
void bitasset_options::validate() const
{
FC_ASSERT(minimum_feeds > 0);
FC_ASSERT(force_settlement_offset_percent <= GRAPHENE_100_PERCENT);
FC_ASSERT(maximum_force_settlement_volume <= GRAPHENE_100_PERCENT);
}
void asset_options::validate()const
{
FC_ASSERT( max_supply > 0 );
FC_ASSERT( max_supply <= GRAPHENE_MAX_SHARE_SUPPLY );
FC_ASSERT( market_fee_percent <= GRAPHENE_100_PERCENT );
FC_ASSERT( max_market_fee >= 0 && max_market_fee <= GRAPHENE_MAX_SHARE_SUPPLY );
// There must be no high bits in permissions whose meaning is not known.
FC_ASSERT( !(issuer_permissions & ~ASSET_ISSUER_PERMISSION_MASK) );
// There must be no high bits in flags which are not also high in permissions.
FC_ASSERT( !(flags & ~issuer_permissions ) );
// The global_settle flag may never be set (this is a permission only)
FC_ASSERT( !(flags & global_settle) );
core_exchange_rate.validate();
FC_ASSERT( core_exchange_rate.base.asset_id.instance.value == 0 ||
core_exchange_rate.quote.asset_id.instance.value == 0 );
if(!whitelist_authorities.empty() || !blacklist_authorities.empty())
FC_ASSERT( flags & white_list );
for( auto item : whitelist_markets )
{
FC_ASSERT( blacklist_markets.find(item) == blacklist_markets.end() );
}
for( auto item : blacklist_markets )
{
FC_ASSERT( whitelist_markets.find(item) == whitelist_markets.end() );
}
}
} } // namespace graphene::chain

View file

@ -15,7 +15,7 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/block.hpp>
#include <graphene/chain/protocol/block.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>

View file

@ -0,0 +1,14 @@
#include <graphene/chain/protocol/custom.hpp>
namespace graphene { namespace chain {
void custom_operation::validate()const
{
FC_ASSERT( fee.amount > 0 );
}
share_type custom_operation::calculate_fee(const fee_parameters_type& k)const
{
return k.fee + calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte );
}
} }

View file

@ -0,0 +1,19 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#include <graphene/chain/protocol/delegate.hpp>
namespace graphene { namespace chain {
void delegate_create_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT(url.size() < GRAPHENE_MAX_URL_LENGTH );
}
void delegate_update_global_parameters_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
new_parameters.validate();
}
} } // graphene::chain

View file

@ -0,0 +1,26 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#include <graphene/chain/protocol/market.hpp>
namespace graphene { namespace chain {
void limit_order_create_operation::validate()const
{
FC_ASSERT( amount_to_sell.asset_id != min_to_receive.asset_id );
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount_to_sell.amount > 0 );
FC_ASSERT( min_to_receive.amount > 0 );
}
void limit_order_cancel_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
}
void call_order_update_operation::validate()const
{ try {
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( delta_collateral.asset_id != delta_debt.asset_id );
FC_ASSERT( delta_collateral.amount != 0 || delta_debt.amount != 0 );
} FC_CAPTURE_AND_RETHROW((*this)) }
} } // graphene::chain

View file

@ -0,0 +1,65 @@
#include <graphene/chain/protocol/memo.hpp>
#include <fc/crypto/aes.hpp>
namespace graphene { namespace chain {
void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub,
const string& msg, uint64_t custom_nonce)
{
if( from != public_key_type() )
{
if( custom_nonce == 0 )
{
uint64_t entropy = fc::sha224::hash(fc::ecc::private_key::generate())._hash[0];
entropy <<= 32;
entropy &= 0xff00000000000000;
nonce = (fc::time_point::now().time_since_epoch().count() & 0x00ffffffffffffff) | entropy;
} else
nonce = custom_nonce;
auto secret = priv.get_shared_secret(pub);
auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());
string text = memo_message(digest_type::hash(msg)._hash[0], msg).serialize();
message = fc::aes_encrypt( nonce_plus_secret, vector<char>(text.begin(), text.end()) );
}
else
{
auto text = memo_message(0, msg).serialize();
message = vector<char>(text.begin(), text.end());
}
}
string memo_data::get_message(const fc::ecc::private_key& priv,
const fc::ecc::public_key& pub)const
{
if( from != public_key_type() )
{
auto secret = priv.get_shared_secret(pub);
auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());
auto plain_text = fc::aes_decrypt( nonce_plus_secret, message );
auto result = memo_message::deserialize(string(plain_text.begin(), plain_text.end()));
FC_ASSERT( result.checksum == uint32_t(digest_type::hash(result.text)._hash[0]) );
return result.text;
}
else
{
return memo_message::deserialize(string(message.begin(), message.end())).text;
}
}
string memo_message::serialize() const
{
auto serial_checksum = string(sizeof(checksum), ' ');
(uint32_t&)(*serial_checksum.data()) = checksum;
return serial_checksum + text;
}
memo_message memo_message::deserialize(const string& serial)
{
memo_message result;
FC_ASSERT( serial.size() >= sizeof(result.checksum) );
result.checksum = ((uint32_t&)(*serial.data()));
result.text = serial.substr(sizeof(result.checksum));
return result;
}
} } // graphene::chain

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2015, Cryptonomex, Inc.
* All rights reserved.
*
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
* are permitted until September 8, 2015, provided that the following conditions are met:
*
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/protocol/operations.hpp>
namespace graphene { namespace chain {
uint64_t base_operation::calculate_data_fee( uint64_t bytes, uint64_t price_per_kbyte )
{
auto result = (fc::uint128(bytes) * price_per_kbyte) / 1024;
FC_ASSERT( result <= GRAPHENE_MAX_SHARE_SUPPLY );
return result.to_uint64();
}
void balance_claim_operation::validate()const
{
FC_ASSERT( fee == asset() );
FC_ASSERT( balance_owner_key != public_key_type() );
}
struct required_auth_visitor
{
typedef void result_type;
vector<authority>& result;
required_auth_visitor( vector<authority>& r ):result(r){}
/** for most operations this is a no-op */
template<typename T>
void operator()(const T& )const {}
void operator()( const balance_claim_operation& o )const
{
result.push_back( authority( 1, o.balance_owner_key, 1 ) );
}
};
struct required_active_visitor
{
typedef void result_type;
flat_set<account_id_type>& result;
required_active_visitor( flat_set<account_id_type>& r ):result(r){}
/** for most operations this is just the fee payer */
template<typename T>
void operator()(const T& o)const
{
result.insert( o.fee_payer() );
}
void operator()(const account_update_operation& o)const
{
/// if owner authority is required, no active authority is required
if( !(o.owner || o.active) ) /// TODO: document why active cannot be updated by active?
result.insert( o.fee_payer() );
}
void operator()( const proposal_delete_operation& o )const
{
if( !o.using_owner_authority )
result.insert( o.fee_payer() );
}
void operator()( const proposal_update_operation& o )const
{
result.insert( o.fee_payer() );
for( auto id : o.active_approvals_to_add )
result.insert(id);
for( auto id : o.active_approvals_to_remove )
result.insert(id);
}
void operator()( const custom_operation& o )const
{
result.insert( o.required_auths.begin(), o.required_auths.end() );
}
void operator()( const assert_operation& o )const
{
result.insert( o.fee_payer() );
result.insert( o.required_auths.begin(), o.required_auths.end() );
}
};
struct required_owner_visitor
{
typedef void result_type;
flat_set<account_id_type>& result;
required_owner_visitor( flat_set<account_id_type>& r ):result(r){}
/** for most operations this is a no-op */
template<typename T>
void operator()(const T& o)const {}
void operator()(const account_update_operation& o)const
{
if( o.owner || o.active ) /// TODO: document why active cannot be updated by active?
result.insert( o.account );
}
void operator()( const proposal_delete_operation& o )const
{
if( o.using_owner_authority )
result.insert( o.fee_payer() );
}
void operator()( const proposal_update_operation& o )const
{
for( auto id : o.owner_approvals_to_add )
result.insert(id);
for( auto id : o.owner_approvals_to_remove )
result.insert(id);
}
};
void operation_get_required_authorities( const operation& op, vector<authority>& result )
{
op.visit( required_auth_visitor( result ) );
}
void operation_get_required_active_authorities( const operation& op, flat_set<account_id_type>& result )
{
op.visit( required_active_visitor( result ) );
}
void operation_get_required_owner_authorities( const operation& op, flat_set<account_id_type>& result )
{
op.visit( required_owner_visitor( result ) );
}
/**
* @brief Used to validate operations in a polymorphic manner
*/
struct operation_validator
{
typedef void result_type;
template<typename T>
void operator()( const T& v )const { v.validate(); }
};
void operation_validate( const operation& op )
{
op.visit( operation_validator() );
}
} } // namespace graphene::chain

View file

@ -0,0 +1,59 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
namespace graphene { namespace chain {
proposal_create_operation proposal_create_operation::genesis_proposal(const chain_parameters& global_params, fc::time_point_sec head_block_time )
{
proposal_create_operation op;
op.expiration_time = head_block_time + global_params.maximum_proposal_lifetime;
op.review_period_seconds = global_params.genesis_proposal_review_period;
return op;
}
void proposal_create_operation::validate() const
{
FC_ASSERT( !proposed_ops.empty() );
for( const auto& op : proposed_ops ) operation_validate( op.op );
}
share_type proposal_create_operation::calculate_fee(const fee_parameters_type& k) const
{
return k.fee + calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte );
}
void proposal_update_operation::validate() const
{
FC_ASSERT(fee.amount >= 0);
FC_ASSERT(!(active_approvals_to_add.empty() && active_approvals_to_remove.empty() &&
owner_approvals_to_add.empty() && owner_approvals_to_remove.empty() &&
key_approvals_to_add.empty() && key_approvals_to_remove.empty()));
for( auto a : active_approvals_to_add )
{
FC_ASSERT(active_approvals_to_remove.find(a) == active_approvals_to_remove.end(),
"Cannot add and remove approval at the same time.");
}
for( auto a : owner_approvals_to_add )
{
FC_ASSERT(owner_approvals_to_remove.find(a) == owner_approvals_to_remove.end(),
"Cannot add and remove approval at the same time.");
}
for( auto a : key_approvals_to_add )
{
FC_ASSERT(key_approvals_to_remove.find(a) == key_approvals_to_remove.end(),
"Cannot add and remove approval at the same time.");
}
}
void proposal_delete_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type proposal_update_operation::calculate_fee(const fee_parameters_type& k) const
{
return k.fee + calculate_data_fee( fc::raw::pack_size(*this), k.price_per_kbyte );
}
} } // graphene::chain

View file

@ -15,7 +15,8 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/transaction.hpp>
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
@ -91,11 +92,7 @@ void transaction::set_expiration( const block_id_type& reference_block, unsigned
void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )
{
for( const auto& op : operations )
{
operation_get_required_active_authorities( op, active );
operation_get_required_owner_authorities( op, owner );
operation_get_required_authorities( op, other );
}
operation_get_required_authorities( op, active, owner, other );
}
} } // graphene::chain

View file

@ -0,0 +1,41 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#include <graphene/chain/protocol/transfer.hpp>
namespace graphene { namespace chain {
share_type transfer_operation::calculate_fee( const fee_parameters_type& schedule )const
{
share_type core_fee_required = schedule.fee;
if( memo )
core_fee_required += calculate_data_fee( fc::raw::pack_size(memo), schedule.price_per_kbyte );
return core_fee_required;
}
void transfer_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( from != to );
FC_ASSERT( amount.amount > 0 );
}
share_type override_transfer_operation::calculate_fee( const fee_parameters_type& schedule )const
{
share_type core_fee_required = schedule.fee;
if( memo )
core_fee_required += calculate_data_fee( fc::raw::pack_size(memo), schedule.price_per_kbyte );
return core_fee_required;
}
void override_transfer_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( from != to );
FC_ASSERT( amount.amount > 0 );
FC_ASSERT( issuer != from );
}
} } // graphene::chain

View file

@ -16,7 +16,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/config.hpp>
#include <graphene/chain/types.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <fc/crypto/base58.hpp>
#include <fc/crypto/ripemd160.hpp>

View file

@ -0,0 +1,48 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#include <graphene/chain/protocol/withdraw_permission.hpp>
namespace graphene { namespace chain {
void withdraw_permission_update_operation::validate()const
{
FC_ASSERT( withdrawal_limit.amount > 0 );
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( withdrawal_period_sec > 0 );
FC_ASSERT( withdraw_from_account != authorized_account );
FC_ASSERT( periods_until_expiration > 0 );
}
void withdraw_permission_claim_operation::validate()const
{
FC_ASSERT( withdraw_to_account != withdraw_from_account );
FC_ASSERT( amount_to_withdraw.amount > 0 );
FC_ASSERT( fee.amount >= 0 );
}
share_type withdraw_permission_claim_operation::calculate_fee(const fee_parameters_type& k)const
{
share_type core_fee_required = k.fee;
if( memo )
core_fee_required += calculate_data_fee( fc::raw::pack_size(memo), k.price_per_kbyte );
return core_fee_required;
}
void withdraw_permission_create_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( withdraw_from_account != authorized_account );
FC_ASSERT( withdrawal_limit.amount > 0 );
//TODO: better bounds checking on these values
FC_ASSERT( withdrawal_period_sec > 0 );
FC_ASSERT( periods_until_expiration > 0 );
}
void withdraw_permission_delete_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( withdraw_from_account != authorized_account );
}
} } // graphene::chain

View file

@ -0,0 +1,19 @@
/* Copyright (C) Cryptonomex, Inc - All Rights Reserved **/
#include <graphene/chain/protocol/witness.hpp>
namespace graphene { namespace chain {
void witness_create_operation::validate() const
{
FC_ASSERT(fee.amount >= 0);
FC_ASSERT(url.size() < GRAPHENE_MAX_URL_LENGTH );
}
void witness_withdraw_pay_operation::validate() const
{
FC_ASSERT( fee.amount >= 0 );
FC_ASSERT( amount >= 0 );
}
} } // graphene::chain

View file

@ -0,0 +1,15 @@
#include <graphene/chain/protocol/worker.hpp>
namespace graphene { namespace chain {
void worker_create_operation::validate() const
{
FC_ASSERT(fee.amount >= 0);
FC_ASSERT(work_end_date > work_begin_date);
FC_ASSERT(daily_pay > 0);
FC_ASSERT(daily_pay < GRAPHENE_MAX_SHARE_SUPPLY);
FC_ASSERT(name.size() < GRAPHENE_MAX_WORKER_NAME_LENGTH );
FC_ASSERT(url.size() < GRAPHENE_MAX_URL_LENGTH );
}
} }

Some files were not shown because too many files have changed in this diff Show more