diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index 6ec2cc2c413..86720776331 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -1065,13 +1065,13 @@ uint32_t chain_controller::producer_participation_rate()const return uint64_t(config::Percent100) * __builtin_popcountll(dpo.recent_slots_filled) / 64; } -void chain_controller::set_validate_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, message_validate_handler v ) { +void chain_controller::set_validate_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, message_validate_handler v ) { message_validate_handlers[contract][std::make_pair(scope,action)] = v; } -void chain_controller::set_precondition_validate_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, precondition_validate_handler v ) { +void chain_controller::set_precondition_validate_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, precondition_validate_handler v ) { precondition_validate_handlers[contract][std::make_pair(scope,action)] = v; } -void chain_controller::set_apply_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, apply_handler v ) { +void chain_controller::set_apply_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, apply_handler v ) { apply_handlers[contract][std::make_pair(scope,action)] = v; } diff --git a/libraries/chain/include/eos/chain/chain_controller.hpp b/libraries/chain/include/eos/chain/chain_controller.hpp index 17fdfba423e..0a46a1d795d 100644 --- a/libraries/chain/include/eos/chain/chain_controller.hpp +++ b/libraries/chain/include/eos/chain/chain_controller.hpp @@ -78,9 +78,9 @@ namespace eos { namespace chain { * The controller can override any script endpoint with native code. */ ///@{ - void set_validate_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, message_validate_handler v ); - void set_precondition_validate_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, precondition_validate_handler v ); - void set_apply_handler( const AccountName& contract, const AccountName& scope, const TypeName& action, apply_handler v ); + void set_validate_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, message_validate_handler v ); + void set_precondition_validate_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, precondition_validate_handler v ); + void set_apply_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, apply_handler v ); //@} enum validation_steps @@ -305,7 +305,7 @@ namespace eos { namespace chain { node_property_object _node_property_object; - typedef pair handler_key; + typedef pair handler_key; map< AccountName, map > message_validate_handlers; map< AccountName, map > precondition_validate_handlers; map< AccountName, map > apply_handlers; diff --git a/libraries/chain/include/eos/chain/types.hpp b/libraries/chain/include/eos/chain/types.hpp index dd8ffdfc27c..840cdb9dde0 100644 --- a/libraries/chain/include/eos/chain/types.hpp +++ b/libraries/chain/include/eos/chain/types.hpp @@ -63,11 +63,10 @@ : id(0) BOOST_PP_SEQ_FOR_EACH(OBJECT_CTOR2_MACRO, _, FIELDS) \ { c(*this); } #define OBJECT_CTOR(...) BOOST_PP_OVERLOAD(OBJECT_CTOR, __VA_ARGS__)(__VA_ARGS__) - -#define EOS_SYSTEM_CONTRACT_FUNCTIONS (CreateAccount)(SetCode) -#define EOS_CONTRACT_FUNCTIONS (Transfer)(TransferToLocked) +#define EOS_SYSTEM_CONTRACT_FUNCTIONS (newaccount)(setcode) +#define EOS_CONTRACT_FUNCTIONS (transfer)(lock) #define EOS_STAKED_BALANCE_CONTRACT_FUNCTIONS \ - (CreateProducer)(UpdateProducer)(ApproveProducer)(SetVoteProxy)(AllowVoteProxying) + (setproducer)(okproducer)(setproxy) namespace eos { namespace chain { using std::map; @@ -112,6 +111,8 @@ namespace eos { namespace chain { using private_key_type = fc::ecc::private_key; using chain_id_type = fc::sha256; + using eos::types::Name; + using ActionName = Name; using eos::types::AccountName; using eos::types::PermissionName; using eos::types::Asset; diff --git a/libraries/native_contract/eos_contract.cpp b/libraries/native_contract/eos_contract.cpp index 6b4cf0c5d66..0c6f624ee44 100644 --- a/libraries/native_contract/eos_contract.cpp +++ b/libraries/native_contract/eos_contract.cpp @@ -2,51 +2,89 @@ #include #include +#include #include #include +namespace native { namespace eos { -using namespace chain; +using namespace ::eos::chain; +namespace config = ::eos::config; +namespace chain = ::eos::chain; -void CreateAccount_Notify_Eos::validate_preconditions(precondition_validate_context& context) { - auto create = context.msg.as(); +/** + * This method is called when the newaccount message is delivered to @system and @eos is notified. + * + * validate_system_newaccount requires that @eos be notified so we can safely rely on this method + * always being called when a new account is created. + * + * The purpose of this call is to verify the new account has the sufficient funds to populate the + * @staked balance required to reserve the space for the new account. + */ +void precondition_system_newaccount(chain::precondition_validate_context& context ) { + auto create = context.msg.as(); const auto& creatorBalance = context.db.get(create.creator); EOS_ASSERT(creatorBalance.balance >= create.deposit.amount, message_validate_exception, "Creator '${c}' has insufficient funds to make account creation deposit of ${a}", ("c", create.creator)("a", create.deposit)); } -void ClaimUnlockedEos_Notify_Eos::apply(apply_context& context) { - auto claim = context.msg.as(); - const auto& claimant = context.db.get(claim.account); - context.mutable_db.modify(claimant, [&claim](BalanceObject& a) { - a.balance += claim.amount; +/** + * This method is called assuming precondition_system_newaccount succeeds and proceeds to + * deduct the balance of the account creator by deposit, this deposit is supposed to be + * credited to the staked balance the new account in the @staked contract. + */ +void apply_system_newaccount(apply_context& context) { + auto create = context.msg.as(); + + const auto& creatorBalance = context.mutable_db.get(create.creator); + context.mutable_db.modify(creatorBalance, [&create](BalanceObject& b) { + b.balance -= create.deposit.amount; }); -} -void CreateAccount_Notify_Eos::apply(apply_context& context) { - auto create = context.msg.as(); context.mutable_db.create([&create](BalanceObject& b) { b.ownerName = create.name; - b.balance = create.deposit.amount; + b.balance = 0; //create.deposit.amount; TODO: make sure we credit this in @staked }); - const auto& creatorBalance = context.mutable_db.get(create.creator); - context.mutable_db.modify(creatorBalance, [&create](BalanceObject& b) { - b.balance -= create.deposit.amount; +} + +/** + * This method is called when the claim message is delivered to @staked + * staked::validate_staked_claim must require that @eos be notified. + * + * This method trusts that staked::precondition_staked_claim verifies that claim.amount is + * available. + */ +void apply_staked_claim(apply_context& context) { + auto claim = context.msg.as(); + const auto& claimant = context.db.get(claim.account); + context.mutable_db.modify(claimant, [&claim](BalanceObject& a) { + a.balance += claim.amount; }); } -void Transfer::validate(message_validate_context& context) { - auto transfer = context.msg.as(); +/** + * + * @ingroup native_eos + * @defgroup eos_eos_transfer eos::eos_transfer + */ +///@{ +/** + * When transferring EOS the amount must be positive and the receiver must be notified. + */ +void validate_eos_transfer(message_validate_context& context) { +#warning TODO: should transfer validate that the sender is in the provided authorites + auto transfer = context.msg.as(); try { EOS_ASSERT(transfer.amount > Asset(0), message_validate_exception, "Must transfer a positive amount"); EOS_ASSERT(context.msg.has_notify(transfer.to), message_validate_exception, "Must notify recipient of transfer"); } FC_CAPTURE_AND_RETHROW((transfer)) } -void Transfer::validate_preconditions(precondition_validate_context& context) { + +void precondition_eos_transfer(precondition_validate_context& context) { const auto& db = context.db; - auto transfer = context.msg.as(); + auto transfer = context.msg.as(); try { db.get(transfer.to); ///< make sure this exists @@ -56,9 +94,9 @@ void Transfer::validate_preconditions(precondition_validate_context& context) { } FC_CAPTURE_AND_RETHROW((transfer)) } -void Transfer::apply(apply_context& context) { +void apply_eos_transfer(apply_context& context) { auto& db = context.mutable_db; - auto transfer = context.msg.as(); + auto transfer = context.msg.as(); const auto& from = db.get(transfer.from); const auto& to = db.get(transfer.to); db.modify(from, [&](BalanceObject& a) { @@ -68,9 +106,21 @@ void Transfer::apply(apply_context& context) { a.balance += transfer.amount.amount; }); } +///@} + -void TransferToLocked::validate(message_validate_context& context) { - auto lock = context.msg.as(); +/** + * When the lock action is delivered to @eos the account should debit the locked amount + * and then require that @staked be notified. @staked will credit the amount to the + * locked balance and adjust votes accordingly. + * + * The locked amount must be possitive. + * + * @defgroup eos_eos_lock eos::eos_lock + */ +///@{ +void validate_eos_lock(message_validate_context& context) { + auto lock = context.msg.as(); EOS_ASSERT(lock.amount > 0, message_validate_exception, "Locked amount must be positive"); EOS_ASSERT(lock.to == lock.from || context.msg.has_notify(lock.to), message_validate_exception, "Recipient account must be notified"); @@ -78,8 +128,11 @@ void TransferToLocked::validate(message_validate_context& context) { "Staked Balance Contract (${name}) must be notified", ("name", config::StakedBalanceContractName)); } -void TransferToLocked::validate_preconditions(precondition_validate_context& context) { - auto lock = context.msg.as(); +/** + * The the from account must have sufficient balance + */ +void precondition_eos_lock(precondition_validate_context& context) { + auto lock = context.msg.as(); ShareType balance; try { const auto& sender = context.db.get(lock.from); @@ -90,12 +143,17 @@ void TransferToLocked::validate_preconditions(precondition_validate_context& con "Account ${a} lacks sufficient funds to lock ${amt} EOS", ("a", lock.from)("amt", lock.amount)); } -void TransferToLocked::apply(apply_context& context) { - auto lock = context.msg.as(); +/** + * Deduct the balance from the from account. + */ +void apply_eos_lock(apply_context& context) { + auto lock = context.msg.as(); const auto& locker = context.db.get(lock.from); context.mutable_db.modify(locker, [&lock](BalanceObject& a) { a.balance -= lock.amount; }); } +///@} } // namespace eos +} // namespace native diff --git a/libraries/native_contract/include/eos/native_contract/balance_object.hpp b/libraries/native_contract/include/eos/native_contract/balance_object.hpp index f2ba583976f..dfe91498cf3 100644 --- a/libraries/native_contract/include/eos/native_contract/balance_object.hpp +++ b/libraries/native_contract/include/eos/native_contract/balance_object.hpp @@ -7,7 +7,11 @@ #include +namespace native { namespace eos { +namespace chain = ::eos::chain; +namespace types = ::eos::types; +namespace config = ::eos::config; /** * @brief The BalanceObject class tracks the EOS balance for accounts @@ -34,6 +38,6 @@ using BalanceMultiIndex = chainbase::shared_multi_index_container< > >; -} // namespace eos +} } // namespace native::eos -CHAINBASE_SET_INDEX_TYPE(eos::BalanceObject, eos::BalanceMultiIndex) +CHAINBASE_SET_INDEX_TYPE(native::eos::BalanceObject, native::eos::BalanceMultiIndex) diff --git a/libraries/native_contract/include/eos/native_contract/eos_contract.hpp b/libraries/native_contract/include/eos/native_contract/eos_contract.hpp index 61341ac1171..996d713d81c 100644 --- a/libraries/native_contract/include/eos/native_contract/eos_contract.hpp +++ b/libraries/native_contract/include/eos/native_contract/eos_contract.hpp @@ -4,30 +4,29 @@ #include -namespace eos { +namespace native { +namespace eos { ///< eos native currency contract +namespace chain = ::eos::chain; +namespace types = ::eos::types; -struct CreateAccount_Notify_Eos { - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; +/// handle apply the newaccount message to the system contract when we are notified +void precondition_system_newaccount(chain::precondition_validate_context& context); +void apply_system_newaccount(chain::apply_context& context); -struct ClaimUnlockedEos_Notify_Eos { - static void validate_preconditions(chain::precondition_validate_context&) {} - static void apply(chain::apply_context& context); -}; +/* +void precondition_staked_unlock(chain::precondition_validate_context&) {} +void apply_staked_unlock(chain::apply_context& context); +*/ -struct Transfer { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; +void validate_eos_transfer(chain::message_validate_context& context); +void precondition_eos_transfer(chain::precondition_validate_context& context); +void apply_eos_transfer(chain::apply_context& context); -struct TransferToLocked { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; +void validate_eos_lock(chain::message_validate_context& context); +void precondition_eos_lock(chain::precondition_validate_context& context); +void apply_eos_lock(chain::apply_context& context); -void ClaimUnlockedEos_Notify_Eos(chain::apply_context& context); +void apply_staked_claim(chain::apply_context&); } // namespace eos +} // namespace native diff --git a/libraries/native_contract/include/eos/native_contract/producer_objects.hpp b/libraries/native_contract/include/eos/native_contract/producer_objects.hpp index a6f014aea76..c6be2ae641b 100644 --- a/libraries/native_contract/include/eos/native_contract/producer_objects.hpp +++ b/libraries/native_contract/include/eos/native_contract/producer_objects.hpp @@ -11,7 +11,13 @@ #include -namespace eos { +namespace native { +namespace staked { + +using namespace ::eos::chain; +namespace config = ::eos::config; +namespace chain = ::eos::chain; +namespace types = ::eos::types; FC_DECLARE_EXCEPTION(ProducerRaceOverflowException, 10000000, "Producer Virtual Race time has overflowed"); @@ -217,8 +223,8 @@ using ProducerScheduleMultiIndex = chainbase::shared_multi_index_container< > >; -} // namespace eos +} } // namespace native::staked -CHAINBASE_SET_INDEX_TYPE(eos::ProducerVotesObject, eos::ProducerVotesMultiIndex) -CHAINBASE_SET_INDEX_TYPE(eos::ProxyVoteObject, eos::ProxyVoteMultiIndex) -CHAINBASE_SET_INDEX_TYPE(eos::ProducerScheduleObject, eos::ProducerScheduleMultiIndex) +CHAINBASE_SET_INDEX_TYPE(native::staked::ProducerVotesObject, native::staked::ProducerVotesMultiIndex) +CHAINBASE_SET_INDEX_TYPE(native::staked::ProxyVoteObject, native::staked::ProxyVoteMultiIndex) +CHAINBASE_SET_INDEX_TYPE(native::staked::ProducerScheduleObject, native::staked::ProducerScheduleMultiIndex) diff --git a/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp b/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp index 03cea1fa8ed..03b3e83701e 100644 --- a/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp +++ b/libraries/native_contract/include/eos/native_contract/staked_balance_contract.hpp @@ -4,58 +4,53 @@ #include -namespace eos { - -struct CreateAccount_Notify_Staked { - static void validate_preconditions(chain::precondition_validate_context&) {} - static void apply(chain::apply_context& context); -}; - -struct TransferToLocked_Notify_Staked { - static void validate_preconditions(chain::precondition_validate_context&) {} - static void apply(chain::apply_context& context); -}; - -struct StartUnlockEos { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -struct ClaimUnlockedEos { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -struct CreateProducer { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -struct UpdateProducer { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -struct ApproveProducer { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -struct AllowVoteProxying { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -struct SetVoteProxy { - static void validate(chain::message_validate_context&) {} - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; - -} // namespace eos +namespace native { namespace staked { +using namespace ::eos::chain; +namespace chain = ::eos::chain; +namespace types = ::eos::types; + +/** + * Handle actions delivered to @system account when @staked account is notified + */ +///@{ +//void precondition_system_newaccount(chain::precondition_validate_context&); +void apply_system_newaccount(chain::apply_context& context); +///@} + +/** + * Handle actions delivered to @eos account when @staked account is notified + */ +///@{ +//void precondition_eos_lock(chain::precondition_validate_context&); +void apply_eos_lock(chain::apply_context& context); +///@} + + +/** + * Handle actions delivered to @staked account when @staked account is notified + */ +///@{ +void validate_staked_claim(chain::message_validate_context& context); +void precondition_staked_claim(chain::precondition_validate_context& context); +void apply_staked_claim(chain::apply_context& context); + +void validate_staked_unlock(chain::message_validate_context& context); +void precondition_staked_unlock(chain::precondition_validate_context& context); +void apply_staked_unlock(chain::apply_context& context); + +void validate_staked_setproducer(chain::message_validate_context& context); +void precondition_staked_setproducer(chain::precondition_validate_context& context); +void apply_staked_setproducer(chain::apply_context& context); + + +void validate_staked_okproducer(chain::message_validate_context& context); +void precondition_staked_okproducer(chain::precondition_validate_context& context); +void apply_staked_okproducer(chain::apply_context& context); + +//void validate_staked_setproxy(chain::message_validate_context&) {} +void precondition_staked_setproxy(chain::precondition_validate_context& context); +void apply_staked_setproxy(chain::apply_context& context); +///@} + + +} } // namespace native::staked diff --git a/libraries/native_contract/include/eos/native_contract/staked_balance_objects.hpp b/libraries/native_contract/include/eos/native_contract/staked_balance_objects.hpp index 9afdf1a83a1..8e7da969626 100644 --- a/libraries/native_contract/include/eos/native_contract/staked_balance_objects.hpp +++ b/libraries/native_contract/include/eos/native_contract/staked_balance_objects.hpp @@ -9,7 +9,14 @@ #include -namespace eos { +namespace native { +namespace staked { + +using namespace ::eos::chain; +namespace config = ::eos::config; +namespace chain = ::eos::chain; +namespace types = ::eos::types; + /** * @brief The ProducerSlate struct stores a list of producers voted on by an account */ @@ -95,6 +102,6 @@ using StakedBalanceMultiIndex = chainbase::shared_multi_index_container< > >; -} // namespace eos +} } // namespace native::staked -CHAINBASE_SET_INDEX_TYPE(eos::StakedBalanceObject, eos::StakedBalanceMultiIndex) +CHAINBASE_SET_INDEX_TYPE(native::staked::StakedBalanceObject, native::staked::StakedBalanceMultiIndex) diff --git a/libraries/native_contract/include/eos/native_contract/system_contract.hpp b/libraries/native_contract/include/eos/native_contract/system_contract.hpp index 081fe714f20..b67bc2df39c 100644 --- a/libraries/native_contract/include/eos/native_contract/system_contract.hpp +++ b/libraries/native_contract/include/eos/native_contract/system_contract.hpp @@ -4,18 +4,19 @@ #include -namespace eos { +namespace native { +namespace system { +using namespace ::eos::chain; +namespace chain = ::eos::chain; +namespace types = ::eos::types; -struct SetCode { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; +void validate_system_setcode(chain::message_validate_context& context); +void precondition_system_setcode(chain::precondition_validate_context& context); +void apply_system_setcode(chain::apply_context& context); -struct CreateAccount { - static void validate(chain::message_validate_context& context); - static void validate_preconditions(chain::precondition_validate_context& context); - static void apply(chain::apply_context& context); -}; +void validate_system_newaccount(chain::message_validate_context& context); +void precondition_system_newaccount(chain::precondition_validate_context& context); +void apply_system_newaccount(chain::apply_context& context); -} // namespace eos +} // namespace system +} // namespace native diff --git a/libraries/native_contract/native_contract_chain_administrator.cpp b/libraries/native_contract/native_contract_chain_administrator.cpp index fffd16d3dcc..d22c620998c 100644 --- a/libraries/native_contract/native_contract_chain_administrator.cpp +++ b/libraries/native_contract/native_contract_chain_administrator.cpp @@ -12,7 +12,7 @@ namespace eos { namespace native_contract { using administrator = native_contract_chain_administrator; ProducerRound administrator::get_next_round(chainbase::database& db) { - return ProducerScheduleObject::get(db).calculateNextRound(db); + return native::staked::ProducerScheduleObject::get(db).calculateNextRound(db); } chain::BlockchainConfiguration administrator::get_blockchain_configuration(const chainbase::database& db, diff --git a/libraries/native_contract/native_contract_chain_initializer.cpp b/libraries/native_contract/native_contract_chain_initializer.cpp index 6a73120b5d2..1c137fa9582 100644 --- a/libraries/native_contract/native_contract_chain_initializer.cpp +++ b/libraries/native_contract/native_contract_chain_initializer.cpp @@ -11,6 +11,7 @@ namespace eos { namespace native_contract { using namespace chain; +namespace chain = ::eos::chain; types::Time native_contract_chain_initializer::get_chain_start_time() { return genesis.initial_timestamp; @@ -29,38 +30,59 @@ std::array native_contract_chain_ini void native_contract_chain_initializer::register_types(chain_controller& chain, chainbase::database& db) { // Install the native contract's indexes; we can't do anything until our objects are recognized - db.add_index(); - db.add_index(); - db.add_index(); - db.add_index(); - db.add_index(); - - // Install the native contract's message handlers - // First, set message handlers -#define SET_HANDLERS(contractname, handlername) \ - chain.set_validate_handler(contractname, contractname, #handlername, &handlername::validate); \ - chain.set_precondition_validate_handler(contractname, contractname, #handlername, &handlername::validate_preconditions); \ - chain.set_apply_handler(contractname, contractname, #handlername, &handlername::apply); -#define FWD_SET_HANDLERS(r, data, elem) SET_HANDLERS(data, elem) - BOOST_PP_SEQ_FOR_EACH(FWD_SET_HANDLERS, config::SystemContractName, EOS_SYSTEM_CONTRACT_FUNCTIONS) - BOOST_PP_SEQ_FOR_EACH(FWD_SET_HANDLERS, config::EosContractName, EOS_CONTRACT_FUNCTIONS) - BOOST_PP_SEQ_FOR_EACH(FWD_SET_HANDLERS, config::StakedBalanceContractName, EOS_STAKED_BALANCE_CONTRACT_FUNCTIONS) -#undef FWD_SET_HANDLERS -#undef SET_HANDLERS - - // Second, set notify handlers - auto SetNotifyHandlers = [&chain](auto recipient, auto scope, auto message, auto validate, auto apply) { - chain.set_precondition_validate_handler(recipient, scope, message, validate); - chain.set_apply_handler(recipient, scope, message, apply); - }; - SetNotifyHandlers(config::EosContractName, config::StakedBalanceContractName, "TransferToLocked", - &TransferToLocked_Notify_Staked::validate_preconditions, &TransferToLocked_Notify_Staked::apply); - SetNotifyHandlers(config::StakedBalanceContractName, config::EosContractName, "ClaimUnlockedEos", - &ClaimUnlockedEos_Notify_Eos::validate_preconditions, &ClaimUnlockedEos_Notify_Eos::apply); - SetNotifyHandlers(config::SystemContractName, config::EosContractName, "CreateAccount", - &CreateAccount_Notify_Eos::validate_preconditions, &CreateAccount_Notify_Eos::apply); - SetNotifyHandlers(config::SystemContractName, config::StakedBalanceContractName, "CreateAccount", - &CreateAccount_Notify_Staked::validate_preconditions, &CreateAccount_Notify_Staked::apply); + db.add_index(); + db.add_index(); + db.add_index(); + db.add_index(); + + db.add_index(); + +#define SET_PRE_HANDLER( contract, scope, action ) \ + chain.set_precondition_validate_handler( Name(#contract), Name(#scope), Name(#action), BOOST_PP_CAT(&native::contract::precondition_, BOOST_PP_CAT( BOOST_PP_CAT(scope, _), action)) ) +#define SET_VAL_HANDLER( contract, scope, action ) \ + chain.set_validate_handler( #contract, #scope, #action, &BOOST_PP_CAT(native::contract::validate_, BOOST_PP_CAT(scope, BOOST_PP_CAT(_,action) ) ) ) +#define SET_APP_HANDLER( contract, scope, action ) \ + chain.set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(native::contract::apply_, BOOST_PP_CAT(scope, BOOST_PP_CAT(_,action) ) ) ) + + SET_PRE_HANDLER( eos, system, newaccount ); + SET_APP_HANDLER( eos, system, newaccount ); + + SET_APP_HANDLER( eos, staked, claim ); + + SET_VAL_HANDLER( eos, eos, transfer ); + SET_PRE_HANDLER( eos, eos, transfer ); + SET_APP_HANDLER( eos, eos, transfer ); + + SET_VAL_HANDLER( eos, eos, lock ); + SET_PRE_HANDLER( eos, eos, lock ); + SET_APP_HANDLER( eos, eos, lock ); + + SET_APP_HANDLER( staked, system, newaccount ); + SET_APP_HANDLER( staked, eos, lock ); + + SET_VAL_HANDLER( staked, staked, claim ); + SET_PRE_HANDLER( staked, staked, claim ); + SET_APP_HANDLER( staked, staked, claim ); + + SET_VAL_HANDLER( staked, staked, unlock ); + SET_PRE_HANDLER( staked, staked, unlock ); + SET_APP_HANDLER( staked, staked, unlock ); + + SET_VAL_HANDLER( staked, staked, okproducer ); + SET_PRE_HANDLER( staked, staked, okproducer ); + SET_APP_HANDLER( staked, staked, okproducer ); + +// SET_VAL_HANDLER( staked, staked, setproxy ); + SET_PRE_HANDLER( staked, staked, setproxy ); + SET_APP_HANDLER( staked, staked, setproxy ); + + SET_VAL_HANDLER( system, system, setcode ); + SET_PRE_HANDLER( system, system, setcode ); + SET_APP_HANDLER( system, system, setcode ); + + SET_VAL_HANDLER( system, system, newaccount ); + SET_PRE_HANDLER( system, system, newaccount ); + SET_APP_HANDLER( system, system, newaccount ); } std::vector native_contract_chain_initializer::prepare_database(chain_controller& chain, @@ -68,7 +90,7 @@ std::vector native_contract_chain_initializer::prepare_database( std::vector messages_to_process; // Create the singleton object, ProducerScheduleObject - db.create([](const auto&){}); + db.create([](const auto&){}); /// Create the native contract accounts manually; sadly, we can't run their contracts to make them create themselves auto CreateNativeAccount = [this, &db](auto name, auto liquidBalance) { @@ -76,11 +98,11 @@ std::vector native_contract_chain_initializer::prepare_database( a.name = name; a.creation_date = genesis.initial_timestamp; }); - db.create([&name, liquidBalance](BalanceObject& b) { + db.create([&name, liquidBalance]( auto& b) { b.ownerName = name; b.balance = liquidBalance; }); - db.create([&name](StakedBalanceObject& sb) { sb.ownerName = name; }); + db.create([&name](auto& sb) { sb.ownerName = name; }); }; CreateNativeAccount(config::SystemContractName, config::InitialTokenSupply); CreateNativeAccount(config::EosContractName, 0); @@ -93,7 +115,7 @@ std::vector native_contract_chain_initializer::prepare_database( for (const auto& acct : genesis.initial_accounts) { chain::Message message(config::SystemContractName, config::SystemContractName, {config::EosContractName, config::StakedBalanceContractName}, - "CreateAccount", types::CreateAccount(config::SystemContractName, acct.name, + "newaccount", types::newaccount(config::SystemContractName, acct.name, KeyAuthority(acct.owner_key), KeyAuthority(acct.active_key), KeyAuthority(acct.owner_key), @@ -101,7 +123,7 @@ std::vector native_contract_chain_initializer::prepare_database( messages_to_process.emplace_back(std::move(message)); if (acct.liquid_balance > 0) { message = chain::Message(config::SystemContractName, config::EosContractName, {}, - "Transfer", types::Transfer(config::SystemContractName, acct.name, + "transfer", types::transfer(config::SystemContractName, acct.name, acct.liquid_balance, "Genesis Allocation")); messages_to_process.emplace_back(std::move(message)); } @@ -110,7 +132,7 @@ std::vector native_contract_chain_initializer::prepare_database( // Create initial producers auto CreateProducer = boost::adaptors::transformed([config = genesis.initial_configuration](const auto& p) { return chain::Message(config::SystemContractName, config::StakedBalanceContractName, vector{}, - "CreateProducer", types::CreateProducer(p.owner_name, p.block_signing_key, config)); + "setproducer", types::setproducer(p.owner_name, p.block_signing_key, config)); }); boost::copy(genesis.initial_producers | CreateProducer, std::back_inserter(messages_to_process)); diff --git a/libraries/native_contract/producer_objects.cpp b/libraries/native_contract/producer_objects.cpp index 976708caa08..3b5bb26cb21 100644 --- a/libraries/native_contract/producer_objects.cpp +++ b/libraries/native_contract/producer_objects.cpp @@ -7,7 +7,8 @@ #include #include -namespace eos { +namespace native { +namespace staked { using namespace chain; using namespace types; @@ -141,4 +142,4 @@ void ProducerScheduleObject::resetProducerRace(chainbase::database& db) const { }); } -} // namespace eos +} } // namespace native::staked diff --git a/libraries/native_contract/staked_balance_contract.cpp b/libraries/native_contract/staked_balance_contract.cpp index fde36238dcd..7d08a513f34 100644 --- a/libraries/native_contract/staked_balance_contract.cpp +++ b/libraries/native_contract/staked_balance_contract.cpp @@ -10,30 +10,31 @@ #include #include -namespace eos { -using namespace chain; +namespace native { +namespace staked { -void CreateAccount_Notify_Staked::apply(apply_context& context) { - auto create = context.msg.as(); + +void apply_system_newaccount( apply_context& context ) { + auto create = context.msg.as(); context.mutable_db.create([&create](StakedBalanceObject& sbo) { sbo.ownerName = create.name; }); } -void TransferToLocked_Notify_Staked::apply(apply_context& context) { - auto lock = context.msg.as(); +void apply_eos_lock(apply_context& context) { + auto lock = context.msg.as(); const auto& balance = context.db.get(lock.to); balance.stakeTokens(lock.amount, context.mutable_db); } -void StartUnlockEos::validate(message_validate_context& context) { - auto unlock = context.msg.as(); +void validate_staked_unlock(message_validate_context& context) { + auto unlock = context.msg.as(); EOS_ASSERT(unlock.amount >= 0, message_validate_exception, "Unlock amount cannot be negative"); } -void StartUnlockEos::validate_preconditions(precondition_validate_context& context) { - auto unlock = context.msg.as(); +void precondition_staked_unlock(precondition_validate_context& context) { + auto unlock = context.msg.as(); ShareType balance; try { balance = context.db.get(unlock.account).stakedBalance; @@ -42,22 +43,22 @@ void StartUnlockEos::validate_preconditions(precondition_validate_context& conte "Insufficient locked funds to unlock ${a}", ("a", unlock.amount)); } -void StartUnlockEos::apply(apply_context& context) { - auto unlock = context.msg.as(); +void apply_staked_unlock(apply_context& context) { + auto unlock = context.msg.as(); const auto& balance = context.db.get(unlock.account); balance.beginUnstakingTokens(unlock.amount, context.mutable_db); } -void ClaimUnlockedEos::validate(message_validate_context& context) { - auto claim = context.msg.as(); +void validate_staked_claim(message_validate_context& context) { + auto claim = context.msg.as(); EOS_ASSERT(claim.amount > 0, message_validate_exception, "Claim amount must be positive"); EOS_ASSERT(context.msg.has_notify(config::EosContractName), message_validate_exception, "EOS Contract (${name}) must be notified", ("name", config::EosContractName)); } -void ClaimUnlockedEos::validate_preconditions(precondition_validate_context& context) { - auto claim = context.msg.as(); +void precondition_staked_claim(precondition_validate_context& context) { + auto claim = context.msg.as(); auto balance = context.db.find(claim.account); EOS_ASSERT(balance != nullptr, message_precondition_exception, "Could not find staked balance for ${name}", ("name", claim.account)); @@ -70,29 +71,29 @@ void ClaimUnlockedEos::validate_preconditions(precondition_validate_context& con ("claimAmount", claim.amount)("available", balance->unstakingBalance)); } -void ClaimUnlockedEos::apply(apply_context& context) { - auto claim = context.msg.as(); +void apply_staked_claim(apply_context& context) { + auto claim = context.msg.as(); context.mutable_db.modify(context.db.get(claim.account), [&claim](StakedBalanceObject& sbo) { sbo.unstakingBalance -= claim.amount; }); } -void CreateProducer::validate(message_validate_context& context) { - auto create = context.msg.as(); - EOS_ASSERT(create.name.size() > 0, message_validate_exception, "Producer owner name cannot be empty"); +void validate_staked_setproducer(message_validate_context& context) { + auto create = context.msg.as(); + EOS_ASSERT(create.name.good(), message_validate_exception, "Producer owner name cannot be empty"); } -void CreateProducer::validate_preconditions(precondition_validate_context& context) { - auto create = context.msg.as(); +void precondition_staked_setproducer(precondition_validate_context& context) { + auto create = context.msg.as(); const auto& db = context.db; auto producer = db.find(create.name); EOS_ASSERT(producer == nullptr, message_precondition_exception, "Account ${name} already has a block producer", ("name", create.name)); } -void CreateProducer::apply(apply_context& context) { - auto create = context.msg.as(); +void apply_staked_setproducer(apply_context& context) { + auto create = context.msg.as(); auto& db = context.mutable_db; db.create([&create](producer_object& p) { p.owner = create.name; @@ -106,9 +107,10 @@ void CreateProducer::apply(apply_context& context) { }); } +/* void UpdateProducer::validate(message_validate_context& context) { auto update = context.msg.as(); - EOS_ASSERT(update.name.size() > 0, message_validate_exception, "Producer owner name cannot be empty"); + EOS_ASSERT(update.name.good(), message_validate_exception, "Producer owner name cannot be empty"); } void UpdateProducer::validate_preconditions(precondition_validate_context& context) { @@ -129,18 +131,19 @@ void UpdateProducer::apply(apply_context& context) { p.configuration = update.configuration; }); } +*/ -void ApproveProducer::validate(message_validate_context& context) { - auto approve = context.msg.as(); +void validate_staked_okproducer(message_validate_context& context) { + auto approve = context.msg.as(); EOS_ASSERT(approve.approve == 0 || approve.approve == 1, message_validate_exception, "Unknown approval value: ${val}; must be either 0 or 1", ("val", approve.approve)); - EOS_ASSERT(approve.producer.size() != 0, message_validate_exception, + EOS_ASSERT(approve.producer.good(), message_validate_exception, "Approved producer's name cannot be empty"); } -void ApproveProducer::validate_preconditions(precondition_validate_context& context) { +void precondition_staked_okproducer(precondition_validate_context& context) { const auto& db = context.db; - auto approve = context.msg.as(); + auto approve = context.msg.as(); auto producer = db.find(approve.producer); auto voter = db.find(context.msg.sender); @@ -166,9 +169,9 @@ void ApproveProducer::validate_preconditions(precondition_validate_context& cont ("name", approve.producer)); } -void ApproveProducer::apply(apply_context& context) { +void apply_staked_okproducer(apply_context& context) { auto& db = context.mutable_db; - auto approve = context.msg.as(); + auto approve = context.msg.as(); const auto& producer = db.get(approve.producer); const auto& voter = db.get(context.msg.sender); auto raceTime = ProducerScheduleObject::get(db).currentRaceTime; @@ -195,39 +198,9 @@ void ApproveProducer::apply(apply_context& context) { }); } -void AllowVoteProxying::validate(message_validate_context& context) { - auto allow = context.msg.as(); - EOS_ASSERT(allow.allow == 0 || allow.allow == 1, message_validate_exception, - "Unknown allow value: ${val}; must be either 0 or 1", ("val", allow.allow)); -} - -void AllowVoteProxying::validate_preconditions(precondition_validate_context& context) { - auto allow = context.msg.as(); - auto proxy = context.db.find(context.msg.sender); - if (allow.allow) - EOS_ASSERT(proxy == nullptr, message_precondition_exception, - "Account '${name}' already allows vote proxying", ("name", context.msg.sender)); - else - EOS_ASSERT(proxy != nullptr, message_precondition_exception, - "Account '${name}' already disallows vote proxying", ("name", context.msg.sender)); -} - -void AllowVoteProxying::apply(apply_context& context) { - auto allow = context.msg.as(); - auto& db = context.mutable_db; - if (allow.allow) - db.create([target = context.msg.sender](ProxyVoteObject& pvo) { - pvo.proxyTarget = target; - }); - else { - const auto& proxy = db.get(context.msg.sender); - proxy.cancelProxies(db); - db.remove(proxy); - } -} -void SetVoteProxy::validate_preconditions(precondition_validate_context& context) { - auto svp = context.msg.as(); +void precondition_staked_setproxy(precondition_validate_context& context) { + auto svp = context.msg.as(); const auto& db = context.db; auto proxy = db.find(context.msg.sender); @@ -248,8 +221,8 @@ void SetVoteProxy::validate_preconditions(precondition_validate_context& context } } -void SetVoteProxy::apply(apply_context& context) { - auto svp = context.msg.as(); +void apply_staked_setproxy(apply_context& context) { + auto svp = context.msg.as(); auto& db = context.mutable_db; const auto& proxy = db.get(svp.proxy); const auto& balance = db.get(context.msg.sender); @@ -265,4 +238,4 @@ void SetVoteProxy::apply(apply_context& context) { } } -} // namespace eos +} } // namespace native::staked diff --git a/libraries/native_contract/staked_balance_objects.cpp b/libraries/native_contract/staked_balance_objects.cpp index 0fbc4648bbf..94e1119cb26 100644 --- a/libraries/native_contract/staked_balance_objects.cpp +++ b/libraries/native_contract/staked_balance_objects.cpp @@ -5,7 +5,8 @@ #include -namespace eos { +namespace native { +namespace staked { using namespace chain; using namespace types; @@ -46,4 +47,4 @@ void StakedBalanceObject::propagateVotes(ShareType stakeDelta, chainbase::databa } } -} // namespace eos +} } // namespace native::staked diff --git a/libraries/native_contract/system_contract.cpp b/libraries/native_contract/system_contract.cpp index 54699ff4360..01c731f3f4d 100644 --- a/libraries/native_contract/system_contract.cpp +++ b/libraries/native_contract/system_contract.cpp @@ -7,32 +7,32 @@ #include -namespace eos { +namespace native { +namespace system { using namespace chain; +namespace config = ::eos::config; - -void SetCode::validate(message_validate_context& context) { - auto msg = context.msg.as(); +void validate_system_setcode(message_validate_context& context) { + auto msg = context.msg.as(); FC_ASSERT( msg.vmtype == 0 ); FC_ASSERT( msg.vmversion == 0 ); - // TODO: verify code compiles and is properly sanitized +#warning TODO: verify code compiles and is properly sanitized } -void SetCode::validate_preconditions(precondition_validate_context& context) +void precondition_system_setcode(precondition_validate_context& context) { try { - auto& db = context.db; - auto msg = context.msg.as(); - // db.get( boost::make_tuple(msg.account, msg.type)) - + //auto& db = context.db; + //auto msg = context.msg.as(); } FC_CAPTURE_AND_RETHROW() } -void SetCode::apply(apply_context& context) { +void apply_system_setcode(apply_context& context) { auto& db = context.mutable_db; - auto msg = context.msg.as(); + auto msg = context.msg.as(); const auto& account = db.get(msg.account); wlog( "set code: ${size}", ("size",msg.code.size())); db.modify( account, [&]( auto& a ) { - #warning TODO: update SetCode message to include the hash, then validate it in validate + /** TODO: consider whether a microsecond level local timestamp is sufficient */ + #warning TODO: update setcode message to include the hash, then validate it in validate a.code_version = fc::sha256::hash( msg.code.data(), msg.code.size() ); a.code.resize( msg.code.size() ); memcpy( a.code.data(), msg.code.data(), msg.code.size() ); @@ -42,8 +42,8 @@ void SetCode::apply(apply_context& context) { wasm_interface::get().init( init_context ); } -void CreateAccount::validate(message_validate_context& context) { - auto create = context.msg.as(); +void validate_system_newaccount(message_validate_context& context) { + auto create = context.msg.as(); EOS_ASSERT(context.msg.has_notify(config::EosContractName), message_validate_exception, "Must notify EOS Contract (${name})", ("name", config::EosContractName)); @@ -55,9 +55,9 @@ void CreateAccount::validate(message_validate_context& context) { EOS_ASSERT( eos::validate(create.recovery), message_validate_exception, "Invalid recovery authority"); } -void CreateAccount::validate_preconditions(precondition_validate_context& context) { +void precondition_system_newaccount(precondition_validate_context& context) { const auto& db = context.db; - auto create = context.msg.as(); + auto create = context.msg.as(); db.get(create.creator); ///< make sure it exists @@ -77,9 +77,9 @@ void CreateAccount::validate_preconditions(precondition_validate_context& contex validate_authority_preconditions(create.recovery); } -void CreateAccount::apply(apply_context& context) { +void apply_system_newaccount(apply_context& context) { auto& db = context.mutable_db; - auto create = context.msg.as(); + auto create = context.msg.as(); const auto& new_account = db.create([&create, &db](account_object& a) { a.name = create.name; a.creation_date = db.get(dynamic_global_property_object::id_type()).time; @@ -98,4 +98,4 @@ void CreateAccount::apply(apply_context& context) { }); } -} // namespace eos +} } // namespace native::system diff --git a/libraries/types/TypeParser.cpp b/libraries/types/TypeParser.cpp index c632a157735..b9907b7c199 100644 --- a/libraries/types/TypeParser.cpp +++ b/libraries/types/TypeParser.cpp @@ -11,7 +11,7 @@ namespace alg = boost::algorithm; bool AbstractSymbolTable::isValidTypeName(const TypeName& name, bool allowArray) const { std::string mutable_name = name; - if (mutable_name.empty() || !std::isupper(mutable_name[0])) return false; + if (mutable_name.empty() ) return false; // If appropriate, remove trailing [] if (allowArray && alg::ends_with(mutable_name, "[]")) diff --git a/libraries/types/include/eos/types/TypeParser.hpp b/libraries/types/include/eos/types/TypeParser.hpp index 031480c8a2e..e47a0465583 100644 --- a/libraries/types/include/eos/types/TypeParser.hpp +++ b/libraries/types/include/eos/types/TypeParser.hpp @@ -42,7 +42,7 @@ class AbstractSymbolTable { class SimpleSymbolTable : public AbstractSymbolTable { public: SimpleSymbolTable(): - known({ "Field", "Struct", "Asset", "ShareType", "FixedString16", "FixedString32", + known({ "Field", "Struct", "Asset", "ShareType", "Name", "FixedString16", "FixedString32", "UInt8", "UInt16", "UInt32", "UInt64", "UInt128", "Checksum", "UInt256", "UInt512", "Int8", "Int16", "Int32", "Int64", diff --git a/libraries/types/include/eos/types/native.hpp b/libraries/types/include/eos/types/native.hpp index c4faa3a8ead..63033b5b148 100644 --- a/libraries/types/include/eos/types/native.hpp +++ b/libraries/types/include/eos/types/native.hpp @@ -34,7 +34,7 @@ namespace eos { namespace types { using FieldName = fc::fixed_string<>; using FixedString32 = fc::fixed_string>;// std::tuple>; using FixedString16 = fc::fixed_string<>; - using TypeName = FixedString32; + using TypeName = FixedString32;; using Bytes = Vector; template @@ -57,13 +57,25 @@ namespace eos { namespace types { struct Name { uint64_t value = 0; - Name( const String& str ) { + bool valid()const { return 0 == (value >> 60); } + bool empty()const { return 0 == value; } + bool good()const { return !empty() && valid(); } + + Name( const char* str ) { try { + const auto len = strnlen(str,14); + FC_ASSERT( len <= 12 ); + for( uint32_t i = 0; i < len; ++i ) { + value <<= 5; + value |= char_to_symbol( str[ len -1 - i ] ); + } + } FC_CAPTURE_AND_RETHROW( (str) ) } + Name( const String& str ) { try { FC_ASSERT( str.size() <= 12 ); for( uint32_t i = 0; i < str.size(); ++i ) { value <<= 5; value |= char_to_symbol( str[ str.size() -1 - i ] ); } - } + } FC_CAPTURE_AND_RETHROW((str)) } char char_to_symbol( char c ) const { if( c >= 'a' && c <= 'z' ) return (c - 'a') + 1; @@ -77,7 +89,7 @@ namespace eos { namespace types { FC_ASSERT( !(v>>(5*12)), "invalid name id" ); }; - operator String()const { + explicit operator String()const { static const char* charmap = ".abcdefghijklmnopqrstuvwxyz12345"; String str; uint64_t tmp = value; @@ -100,10 +112,26 @@ namespace eos { namespace types { value = Name(n).value; return *this; } + Name& operator=( const char* n ) { + value = Name(n).value; + return *this; + } + + template + friend Stream& operator << ( Stream& out, const Name& n ) { + return out << String(n); + } + friend bool operator < ( const Name& a, const Name& b ) { return a.value < b.value; } + friend bool operator > ( const Name& a, const Name& b ) { return a.value > b.value; } + friend bool operator == ( const Name& a, const Name& b ) { return a.value == b.value; } + friend bool operator != ( const Name& a, const Name& b ) { return a.value != b.value; } + + operator bool()const { return value; } operator uint64_t()const { return value; } }; + struct Field { FieldName name; TypeName type; diff --git a/libraries/types/test.cpp b/libraries/types/test.cpp index 144faf372a1..1874dc4e664 100644 --- a/libraries/types/test.cpp +++ b/libraries/types/test.cpp @@ -17,7 +17,7 @@ int main( int argc, char** argv ) { idump( (m) ); - eos::types::Transfer t; + eos::types::transfer t; t.from = m.sender; t.to = "other"; diff --git a/libraries/types/types.eos b/libraries/types/types.eos index f822d845d3e..c6e0e81a74b 100644 --- a/libraries/types/types.eos +++ b/libraries/types/types.eos @@ -1,5 +1,6 @@ -typedef FixedString32 AccountName -typedef FixedString16 PermissionName +typedef Name AccountName +typedef Name PermissionName +typedef Name FuncName typedef FixedString32 MessageName typedef FixedString32 TypeName @@ -9,7 +10,7 @@ struct Message sender AccountName # testing recipient AccountName notify AccountName[] - type TypeName + type FuncName data Bytes struct AccountPermission @@ -49,26 +50,26 @@ struct BlockchainConfiguration minEosBalance ShareType maxTrxLifetime UInt32 -struct Transfer +struct transfer from AccountName # may not be the message.sender if message.sender has delegated authority by from to AccountName amount Asset memo String -struct TransferToLocked +struct lock from AccountName to AccountName amount ShareType -struct StartUnlockEos +struct unlock account AccountName amount ShareType -struct ClaimUnlockedEos +struct claim account AccountName amount ShareType -struct CreateAccount +struct newaccount creator AccountName name AccountName owner Authority @@ -76,38 +77,29 @@ struct CreateAccount recovery Authority deposit Asset -struct SetCode +struct setcode account AccountName # the account that is handling the message vmtype UInt8 # the virtual machine type vmversion UInt8 # the virtual machine version code Bytes # the apply -struct CreateProducer - name AccountName - key PublicKey - configuration BlockchainConfiguration -struct UpdateProducer +struct setproducer name AccountName - newKey PublicKey + key PublicKey configuration BlockchainConfiguration # implies message.sender account -struct ApproveProducer +struct okproducer producer AccountName approve Int8 # 0 or 1 # implies message.sender account -struct AllowVoteProxying - allow Int8 # 0 or 1 # implies message.sender account -struct SetVoteProxy +struct setproxy proxy AccountName -struct DefineStruct - scope AccountName - definition Struct struct UpdatePermission account AccountName