提交 2693d1d9 编写于 作者: B Bucky Kittinger

Fixed merge conflicts

......@@ -35,23 +35,23 @@ EOS.IO currently supports the following operating systems:
1. [Getting Started](#gettingstarted)
2. [Setting up a build/development environment](#setup)
1. [Automated build script](#autobuild)
1. [Automated build script](#autobuild)
1. [Clean install Linux (Amazon, Centos, Fedora, Mint, & Ubuntu) for a local testnet](#autoubuntulocal)
2. [Clean install Linux (Amazon, Centos, Fedora, Mint, & Ubuntu) for the public testnet](#autoubuntupublic)
3. [MacOS for a local testnet](#automaclocal)
4. [MacOS for the public testnet](#automacpublic)
3. [Building EOS and running a node](#runanode)
1. [Getting the code](#getcode)
2. [Building from source code](#build)
3. [Creating and launching a single-node testnet](#singlenode)
4. [Next steps](#nextsteps)
1. [Getting the code](#getcode)
2. [Building from source code](#build)
3. [Creating and launching a single-node testnet](#singlenode)
4. [Next steps](#nextsteps)
4. [Example Currency Contract Walkthrough](#smartcontracts)
1. [Example Contracts](#smartcontractexample)
2. [Setting up a wallet and importing account key](#walletimport)
3. [Creating accounts for your smart contracts](#createaccounts)
4. [Upload sample contract to blockchain](#uploadsmartcontract)
5. [Pushing a message to a sample contract](#pushamessage)
6. [Reading Currency Contract Balance](#readingcontract)
1. [Example Contracts](#smartcontractexample)
2. [Setting up a wallet and importing account key](#walletimport)
3. [Creating accounts for your smart contracts](#createaccounts)
4. [Upload sample contract to blockchain](#uploadsmartcontract)
5. [Pushing a message to a sample contract](#pushamessage)
6. [Reading Currency Contract Balance](#readingcontract)
5. [Running local testnet](#localtestnet)
6. [Running a node on the public testnet](#publictestnet)
7. [Doxygen documentation](#doxygen)
......@@ -622,12 +622,12 @@ cd ~
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
tar xf mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( nproc )
sudo make install
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
sudo make -j$( nproc )
```
......@@ -745,12 +745,12 @@ cd ~
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
tar xf mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( nproc )
sudo make install
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
sudo make -j$( nproc )
```
......@@ -819,12 +819,12 @@ cd ~
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
tar xf mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( nproc )
sudo make install
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
sudo make -j$( nproc )
```
......@@ -893,12 +893,12 @@ cd ~
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
tar xf mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( nproc )
sudo make install
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
sudo make -j$( nproc )
```
......@@ -969,7 +969,7 @@ curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=darwin --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --enable-ssl=darwin --disable-automatic-init-and-cleanup --prefix=/usr/local
make -j$( sysctl -in machdep.cpu.core_count )
sudo make install
cd ..
......@@ -977,7 +977,7 @@ rm -rf mongo-c-driver-1.9.3
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j$( sysctl -in machdep.cpu.core_count )
sudo make install
cd ..
......
......@@ -256,13 +256,7 @@ namespace eosiosystem {
r.request_time = now();
});
}
//cancel previous deferred transaction if we have one
//because of an implementation bug currently it would cancel transaction
//that will be created later in this action
//commenting out for now
//cancel_deferred( del.from );
//create new deferred transaction
//create or replace deferred transaction
const auto self = receiver; //current_receiver();
refund act;
act.owner = del.from;
......
......@@ -100,6 +100,7 @@
{"name":"max_inline_depth", "type":"uint16"},
{"name":"max_inline_action_size", "type":"uint32"},
{"name":"max_generated_transaction_size", "type":"uint32"},
{"name":"max_generated_transaction_count", "type":"uint32"},
{"name":"percent_of_max_inflation_rate", "type":"uint32"},
{"name":"storage_reserve_ratio", "type":"uint32"}
]
......
......@@ -255,6 +255,7 @@ namespace eosiosystem {
std::array<uint16_t, 21> max_inline_depth;
std::array<uint32_t, 21> max_inline_action_size;
std::array<uint32_t, 21> max_generated_transaction_size;
std::array<uint32_t, 21> max_generated_transaction_count;
std::array<uint32_t, 21> percent_of_max_inflation_rate;
std::array<uint32_t, 21> storage_reserve_ratio;
......@@ -284,6 +285,7 @@ namespace eosiosystem {
max_inline_depth[n] = it->prefs.max_inline_depth;
max_inline_action_size[n] = it->prefs.max_inline_action_size;
max_generated_transaction_size[n] = it->prefs.max_generated_transaction_size;
max_generated_transaction_count[n] = it->prefs.max_generated_transaction_count;
storage_reserve_ratio[n] = it->prefs.storage_reserve_ratio;
percent_of_max_inflation_rate[n] = it->prefs.percent_of_max_inflation_rate;
......@@ -307,6 +309,7 @@ namespace eosiosystem {
std::sort( max_inline_depth.begin(), max_inline_depth.begin()+n );
std::sort( max_inline_action_size.begin(), max_inline_action_size.begin()+n );
std::sort( max_generated_transaction_size.begin(), max_generated_transaction_size.begin()+n );
std::sort( max_generated_transaction_count.begin(), max_generated_transaction_count.begin()+n );
std::sort( storage_reserve_ratio.begin(), storage_reserve_ratio.begin()+n );
std::sort( percent_of_max_inflation_rate.begin(), percent_of_max_inflation_rate.begin()+n );
}
......@@ -332,6 +335,7 @@ namespace eosiosystem {
parameters.max_inline_depth = max_inline_depth[median];
parameters.max_inline_action_size = max_inline_action_size[median];
parameters.max_generated_transaction_size = max_generated_transaction_size[median];
parameters.max_generated_transaction_count = max_generated_transaction_count[median];
parameters.storage_reserve_ratio = storage_reserve_ratio[median];
parameters.percent_of_max_inflation_rate = percent_of_max_inflation_rate[median];
......
......@@ -22,11 +22,13 @@ namespace eosio {
uint16_t max_inline_depth;
uint32_t max_inline_action_size;
uint32_t max_generated_transaction_size;
uint32_t max_generated_transaction_count;
EOSLIB_SERIALIZE( blockchain_parameters, (target_block_size)(max_block_size)(target_block_acts_per_scope)
(max_block_acts_per_scope)(target_block_acts)(max_block_acts)(max_storage_size)
(max_transaction_lifetime)(max_transaction_exec_time)(max_authority_depth)
(max_inline_depth)(max_inline_action_size)(max_generated_transaction_size)
(max_generated_transaction_count)
)
};
......
......@@ -119,6 +119,9 @@ extern "C" {
WASM_TEST_HANDLER(test_transaction, send_transaction_empty);
WASM_TEST_HANDLER(test_transaction, send_transaction_large);
WASM_TEST_HANDLER(test_transaction, send_action_sender);
WASM_TEST_HANDLER(test_transaction, deferred_print);
WASM_TEST_HANDLER(test_transaction, send_deferred_transaction);
WASM_TEST_HANDLER(test_transaction, cancel_deferred_transaction);
WASM_TEST_HANDLER(test_transaction, send_cf_action);
WASM_TEST_HANDLER(test_transaction, send_cf_action_fail);
WASM_TEST_HANDLER(test_transaction, read_inline_action);
......
......@@ -200,6 +200,9 @@ struct test_transaction {
static void send_transaction_max();
static void send_transaction_large();
static void send_action_sender();
static void deferred_print();
static void send_deferred_transaction();
static void cancel_deferred_transaction();
static void send_cf_action();
static void send_cf_action_fail();
static void read_inline_action();
......
......@@ -210,6 +210,26 @@ void test_transaction::send_transaction_large() {
eosio_assert(false, "send_transaction_large() should've thrown an error");
}
/**
* deferred transaction
*/
void test_transaction::deferred_print() {
eosio::print("deferred executed\n");
}
void test_transaction::send_deferred_transaction() {
using namespace eosio;
auto trx = transaction();
test_action_action<N(testapi), WASM_TEST_ACTION("test_transaction", "deferred_print")> test_action;
trx.actions.emplace_back(vector<permission_level>{{N(testapi), N(active)}}, test_action);
trx.send( 0xffffffffffffffff, now()+2 );
}
void test_transaction::cancel_deferred_transaction() {
using namespace eosio;
cancel_deferred( 0xffffffffffffffff ); //use the same id (0) as in send_deferred_transaction
}
void test_transaction::send_cf_action() {
using namespace eosio;
test_action_action<N(dummy), N(event1)> cfa;
......
......@@ -224,7 +224,10 @@ void apply_context::require_recipient( account_name code ) {
void apply_context::execute_inline( action&& a ) {
if ( !privileged ) {
if( a.account != receiver ) {
controller.check_authorization({a}, flat_set<public_key_type>(), false, {receiver});
const auto delay = controller.check_authorization({a}, flat_set<public_key_type>(), false, {receiver});
FC_ASSERT( trx_meta.published + delay <= controller.head_block_time(),
"inline action uses a permission that imposes a delay that is not met, add an action of mindelay with delay of atleast ${delay}",
("delay", delay.sec_since_epoch()) );
}
}
_inline_actions.emplace_back( move(a) );
......@@ -241,12 +244,11 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
"transaction is expired when created" );
FC_ASSERT( trx.execute_after < trx.expiration, "transaction expires before it can execute" );
/// TODO: make default_max_gen_trx_count a producer parameter
FC_ASSERT( results.generated_transactions.size() < config::default_max_gen_trx_count );
FC_ASSERT( !trx.actions.empty(), "transaction must have at least one action");
const auto& gpo = controller.get_global_properties();
FC_ASSERT( results.deferred_transactions_count < gpo.configuration.max_generated_transaction_count );
// privileged accounts can do anything, no need to check auth
if( !privileged ) {
......@@ -259,20 +261,24 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
break;
}
}
if( check_auth )
controller.check_authorization(trx.actions, flat_set<public_key_type>(), false, {receiver});
if( check_auth ) {
const auto delay = controller.check_authorization(trx.actions, flat_set<public_key_type>(), false, {receiver});
FC_ASSERT( trx_meta.published + delay <= controller.head_block_time(),
"deferred transaction uses a permission that imposes a delay that is not met, add an action of mindelay with delay of atleast ${delay}",
("delay", delay.sec_since_epoch()) );
}
}
trx.sender = receiver; // "Attempting to send from another account"
trx.set_reference_block(controller.head_block_id());
/// TODO: make sure there isn't already a deferred transaction with this ID or senderID?
results.generated_transactions.emplace_back(move(trx));
results.deferred_transaction_requests.push_back(move(trx));
results.deferred_transactions_count++;
} FC_CAPTURE_AND_RETHROW((trx));
}
void apply_context::cancel_deferred( uint64_t sender_id ) {
results.canceled_deferred.emplace_back(receiver, sender_id);
results.deferred_transaction_requests.push_back(deferred_reference(receiver, sender_id));
}
const contracts::table_id_object* apply_context::find_table( name code, name scope, name table ) {
......@@ -382,10 +388,31 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b
return s;
}
uint32_t apply_context::get_next_sender_id() {
const uint64_t id = N(config::eosio_auth_scope);
const auto table = N(deferred.seq);
const auto payer = config::system_account_name;
const auto iter = db_find_i64(config::system_account_name, config::eosio_auth_scope, table, id);
if (iter == -1) {
const uint32_t next_serial = 1;
db_store_i64(config::system_account_name, config::eosio_auth_scope, table, payer, id, (const char*)&next_serial, sizeof(next_serial));
return 0;
}
uint32_t next_serial = 0;
db_get_i64(iter, (char*)&next_serial, sizeof(next_serial));
const auto result = next_serial++;
db_update_i64(iter, payer, (const char*)&next_serial, sizeof(next_serial));
return result;
}
int apply_context::db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
return db_store_i64( receiver, scope, table, payer, id, buffer, buffer_size);
}
int apply_context::db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
require_write_lock( scope );
const auto& tab = find_or_create_table( receiver, scope, table );
const auto& tab = find_or_create_table( code, scope, table );
auto tableid = tab.id;
FC_ASSERT( payer != account_name(), "must specify a valid account to pay for new record" );
......
......@@ -46,6 +46,8 @@ void chain_initializer::register_types(chain_controller& chain, chainbase::datab
SET_APP_HANDLER( eosio, eosio, postrecovery, eosio );
SET_APP_HANDLER( eosio, eosio, passrecovery, eosio );
SET_APP_HANDLER( eosio, eosio, vetorecovery, eosio );
SET_APP_HANDLER( eosio, eosio, canceldelay, eosio );
SET_APP_HANDLER( eosio, eosio, mindelay, eosio );
}
......@@ -73,6 +75,8 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
eos_abi.actions.push_back( action_def{name("vetorecovery"), "vetorecovery"} );
eos_abi.actions.push_back( action_def{name("onerror"), "onerror"} );
eos_abi.actions.push_back( action_def{name("onblock"), "onblock"} );
eos_abi.actions.push_back( action_def{name("canceldelay"), "canceldelay"} );
eos_abi.actions.push_back( action_def{name("mindelay"), "mindelay"} );
// ACTION PAYLOADS
......@@ -99,6 +103,7 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
{"permission", "permission_name"},
{"parent", "permission_name"},
{"data", "authority"},
{"delay", "uint32"}
}
});
......@@ -156,6 +161,18 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
}
});
eos_abi.structs.emplace_back( struct_def {
"canceldelay", "", {
{"sender_id", "uint32"},
}
});
eos_abi.structs.emplace_back( struct_def {
"mindelay", "", {
{"delay", "uint32"},
}
});
// DATABASE RECORDS
eos_abi.structs.emplace_back( struct_def {
......
......@@ -14,6 +14,7 @@
#include <eosio/chain/account_object.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/producer_object.hpp>
......@@ -198,6 +199,7 @@ void apply_eosio_updateauth(apply_context& context) {
po.auth = update.data;
po.parent = parent_id;
po.last_updated = context.controller.head_block_time();
po.delay = time_point_sec(update.delay.convert_to<uint64_t>());
});
} else {
// TODO/QUESTION: If we are creating a new permission, should we check if the message declared
......@@ -208,6 +210,7 @@ void apply_eosio_updateauth(apply_context& context) {
po.auth = update.data;
po.parent = parent_id;
po.last_updated = context.controller.head_block_time();
po.delay = time_point_sec(update.delay.convert_to<uint64_t>());
});
}
}
......@@ -312,24 +315,6 @@ static optional<variant> get_pending_recovery(apply_context& context, account_na
return optional<variant_object>();
}
static uint32_t get_next_sender_id(apply_context& context) {
const uint64_t id = N(config::eosio_auth_scope);
const auto table = N(deferred.seq);
const auto payer = config::system_account_name;
const auto iter = context.db_find_i64(config::system_account_name, config::eosio_auth_scope, table, id);
if (iter == -1) {
const uint32_t next_serial = 1;
context.db_store_i64(config::eosio_auth_scope, table, payer, id, (const char*)&next_serial, sizeof(next_serial));
return 0;
}
uint32_t next_serial = 0;
context.db_get_i64(iter, (char*)&next_serial, sizeof(next_serial));
const auto result = next_serial++;
context.db_update_i64(iter, payer, (const char*)&next_serial, sizeof(next_serial));
return result;
}
static auto get_account_creation(const apply_context& context, const account_name& account) {
auto const& accnt = context.db.get<account_object, by_name>(account);
return (time_point)accnt.creation_date;
......@@ -392,7 +377,7 @@ void apply_eosio_postrecovery(apply_context& context) {
.data = recover_act.data
}, update);
uint32_t request_id = get_next_sender_id(context);
uint32_t request_id = context.get_next_sender_id();
auto record_data = mutable_variant_object()
("account", account)
......@@ -472,5 +457,38 @@ void apply_eosio_vetorecovery(apply_context& context) {
context.console_append_formatted("Recovery for account ${account} vetoed!\n", mutable_variant_object()("account", account));
}
void apply_eosio_canceldelay(apply_context& context) {
auto cancel = context.act.data_as<canceldelay>();
const auto sender_id = cancel.sender_id.convert_to<uint32_t>();
const auto& generated_transaction_idx = context.controller.get_database().get_index<generated_transaction_multi_index>();
const auto& generated_index = generated_transaction_idx.indices().get<by_sender_id>();
const auto& itr = generated_index.lower_bound(boost::make_tuple(config::system_account_name, sender_id));
FC_ASSERT (itr == generated_index.end() || itr->sender != config::system_account_name || itr->sender_id != sender_id,
"cannot cancel sender_id=${sid}, there is no deferred transaction with that sender_id",("sid",sender_id));
auto dtrx = fc::raw::unpack<deferred_transaction>(itr->packed_trx.data(), itr->packed_trx.size());
set<account_name> accounts;
for (const auto& act : dtrx.actions) {
for (const auto& auth : act.authorization) {
accounts.insert(auth.actor);
}
}
bool found = false;
for (const auto& auth : context.act.authorization) {
if (auth.permission == config::active_name && accounts.count(auth.actor)) {
found = true;
break;
}
}
FC_ASSERT (found, "canceldelay action must be signed with the \"active\" permission for one of the actors"
" provided in the authorizations on the original transaction");
context.cancel_deferred(sender_id);
}
void apply_eosio_mindelay(apply_context& context) {
// all processing is performed in chain_controller::check_authorization
}
} } } // namespace eosio::chain::contracts
......@@ -505,6 +505,8 @@ class apply_context {
const bytes& get_packed_transaction();
uint32_t get_next_sender_id();
const chain_controller& controller;
const chainbase::database& db; ///< database where state is stored
const action& act; ///< message being applied
......@@ -523,9 +525,9 @@ class apply_context {
const transaction_metadata& trx_meta;
struct apply_results {
vector<action_trace> applied_actions;
vector<deferred_transaction> generated_transactions;
vector<deferred_reference> canceled_deferred;
vector<action_trace> applied_actions;
vector<fc::static_variant<deferred_transaction, deferred_reference>> deferred_transaction_requests;
size_t deferred_transactions_count = 0;
};
apply_results results;
......@@ -575,9 +577,9 @@ class apply_context {
iterator_cache<key_value_object> keyval_cache;
void append_results(apply_results &&other) {
fc::move_append(results.applied_actions, move(other.applied_actions));
fc::move_append(results.generated_transactions, move(other.generated_transactions));
fc::move_append(results.canceled_deferred, move(other.canceled_deferred));
fc::move_append(results.applied_actions, std::move(other.applied_actions));
fc::move_append(results.deferred_transaction_requests, std::move(other.deferred_transaction_requests));
results.deferred_transactions_count += other.deferred_transactions_count;
}
void exec_one();
......@@ -586,6 +588,8 @@ class apply_context {
const table_id_object* find_table( name code, name scope, name table );
const table_id_object& find_or_create_table( name code, name scope, name table );
int db_store_i64( uint64_t code, uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size );
vector<account_name> _notified; ///< keeps track of new accounts to be notifed of current message
vector<action> _inline_actions; ///< queued inline messages
vector<action> _cfa_inline_actions; ///< queued inline messages
......@@ -600,4 +604,4 @@ using apply_handler = std::function<void(apply_context&)>;
} } // namespace eosio::chain
FC_REFLECT(eosio::chain::apply_context::apply_results, (applied_actions)(generated_transactions))
FC_REFLECT(eosio::chain::apply_context::apply_results, (applied_actions)(deferred_transaction_requests)(deferred_transactions_count))
......@@ -50,10 +50,11 @@ namespace detail {
* @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding
* authority
*/
template<typename PermissionToAuthorityFunc>
template<typename PermissionToAuthorityFunc, typename PermissionVisitorFunc>
class authority_checker {
private:
PermissionToAuthorityFunc permission_to_authority;
PermissionVisitorFunc permission_visitor;
uint16_t recursion_depth_limit;
vector<public_key_type> signing_keys;
flat_set<account_name> _provided_auths; /// accounts which have authorized the transaction at owner level
......@@ -79,6 +80,8 @@ namespace detail {
}
uint32_t operator()(const permission_level_weight& permission) {
if (recursion_depth < checker.recursion_depth_limit) {
checker.permission_visitor(permission.permission);
if( checker.has_permission( permission.permission.actor ) )
total_weight += permission.weight;
else if( checker.satisfied(permission.permission, recursion_depth + 1) )
......@@ -93,10 +96,12 @@ namespace detail {
}
public:
authority_checker( PermissionToAuthorityFunc permission_to_authority,
authority_checker( PermissionToAuthorityFunc permission_to_authority,
PermissionVisitorFunc permission_visitor,
uint16_t recursion_depth_limit, const flat_set<public_key_type>& signing_keys,
flat_set<account_name> provided_auths = flat_set<account_name>() )
: permission_to_authority(permission_to_authority),
permission_visitor(permission_visitor),
recursion_depth_limit(recursion_depth_limit),
signing_keys(signing_keys.begin(), signing_keys.end()),
_provided_auths(provided_auths.begin(), provided_auths.end()),
......@@ -146,14 +151,19 @@ namespace detail {
auto range = utilities::filter_data_by_marker(signing_keys, _used_keys, false);
return {range.begin(), range.end()};
}
const PermissionVisitorFunc& get_permission_visitor() {
return permission_visitor;
}
}; /// authority_checker
template<typename PermissionToAuthorityFunc>
auto make_auth_checker(PermissionToAuthorityFunc&& pta,
template<typename PermissionToAuthorityFunc, typename PermissionVisitorFunc>
auto make_auth_checker(PermissionToAuthorityFunc&& pta,
PermissionVisitorFunc&& permission_visitor,
uint16_t recursion_depth_limit,
const flat_set<public_key_type>& signing_keys,
const flat_set<account_name>& accounts = flat_set<account_name>() ) {
return authority_checker<PermissionToAuthorityFunc>(std::forward<PermissionToAuthorityFunc>(pta), recursion_depth_limit, signing_keys, accounts);
return authority_checker<PermissionToAuthorityFunc, PermissionVisitorFunc>(std::forward<PermissionToAuthorityFunc>(pta), std::forward<PermissionVisitorFunc>(permission_visitor), recursion_depth_limit, signing_keys, accounts);
}
} } // namespace eosio::chain
......@@ -33,6 +33,7 @@ struct chain_config {
uint16_t max_inline_depth;
uint32_t max_inline_action_size;
uint32_t max_generated_transaction_size;
uint32_t max_generated_transaction_count;
static chain_config get_median_values( vector<chain_config> votes );
......@@ -50,7 +51,8 @@ struct chain_config {
<< "Max Authority Depth: " << c.max_authority_depth << ", "
<< "Max Inline Depth: " << c.max_inline_depth << ", "
<< "Max Inline Action Size: " << c.max_inline_action_size << ", "
<< "Max Generated Transaction Size: " << c.max_generated_transaction_size << "\n";
<< "Max Generated Transaction Size: " << c.max_generated_transaction_size << "\n"
<< "Max Generated Transaction Count: " << c.max_generated_transaction_count << "\n";
}
};
......@@ -68,4 +70,6 @@ FC_REFLECT(eosio::chain::chain_config,
(max_block_acts)
(max_storage_size)
(max_transaction_lifetime)(max_transaction_exec_time)(max_authority_depth)
(max_inline_depth)(max_inline_action_size)(max_generated_transaction_size) )
(max_inline_depth)(max_inline_action_size)(max_generated_transaction_size)
(max_generated_transaction_count)
)
......@@ -87,7 +87,7 @@ namespace eosio { namespace chain {
void push_block( const signed_block& b, uint32_t skip = skip_nothing );
transaction_trace push_transaction( const packed_transaction& trx, uint32_t skip = skip_nothing );
void push_deferred_transactions( bool flush = false );
vector<transaction_trace> push_deferred_transactions( bool flush = false );
......@@ -284,13 +284,13 @@ namespace eosio { namespace chain {
* @param allow_unused_signatures - true if method should not assert on unused signatures
* @param provided_accounts - the set of accounts which have authorized the transaction (presumed to be owner)
*
* @return true if the provided keys and accounts are sufficient to authorize actions of the transaction
* @return time_point set to the max delay that this authorization requires to complete
*/
void check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures = false,
flat_set<account_name> provided_accounts = flat_set<account_name>()
)const;
time_point check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures = false,
flat_set<account_name> provided_accounts = flat_set<account_name>()
)const;
private:
......@@ -337,9 +337,10 @@ namespace eosio { namespace chain {
return f();
}
void check_transaction_authorization(const transaction& trx,
const vector<signature_type>& signatures,
bool allow_unused_signatures = false)const;
time_point check_transaction_authorization(const transaction& trx,
const vector<signature_type>& signatures,
const vector<bytes>& cfd = vector<bytes>(),
bool allow_unused_signatures = false)const;
void require_scope(const scope_name& name) const;
......@@ -352,7 +353,7 @@ namespace eosio { namespace chain {
template<typename T>
void validate_transaction(const T& trx) const {
try {
EOS_ASSERT(trx.actions.size() > 0, transaction_exception, "A transaction must have at least one message");
EOS_ASSERT(trx.actions.size() > 0, transaction_exception, "A transaction must have at least one action");
validate_expiration(trx);
validate_uniqueness(trx);
......@@ -380,6 +381,17 @@ namespace eosio { namespace chain {
scope_name code_account,
action_name type) const;
/**
* @brief Find the linked permission for the passed in parameters
* @param authorizer_account The account authorizing the message
* @param code_account The account which publishes the contract that handles the message
* @param type The type of message
* @return an optional<permission_name> for the linked permission if one exists; otherwise an invalid
* optional<permission_name>
*/
optional<permission_name> lookup_linked_permission( account_name authorizer_account,
scope_name code_account,
action_name type) const;
bool should_check_for_duplicate_transactions()const { return !(_skip_flags&skip_transaction_dupe_check); }
bool should_check_tapos()const { return !(_skip_flags&skip_tapos_check); }
......@@ -412,6 +424,7 @@ namespace eosio { namespace chain {
transaction _get_on_block_transaction();
void _apply_on_block_transaction();
void store_deferred_transaction(const deferred_transaction& dtrx);
// producer_schedule_type calculate_next_round( const signed_block& next_block );
......
......@@ -177,6 +177,12 @@ namespace impl {
mvo(name, std::move(array));
}
template<typename Resolver, typename... Args>
static void add( mutable_variant_object &mvo, const char* name, const fc::static_variant<Args...>& v, Resolver resolver )
{
//TODO: implement deserialization for static_variant
}
/**
* overload of to_variant_object for actions
* @tparam Resolver
......@@ -401,7 +407,6 @@ namespace impl {
Resolver _resolver;
};
template<typename M, typename Resolver, require_abi_t<M>>
void abi_to_variant::add( mutable_variant_object &mvo, const char* name, const M& v, Resolver resolver ) {
mutable_variant_object member_mvo;
......
......@@ -29,6 +29,9 @@ namespace eosio { namespace chain { namespace contracts {
void apply_eosio_setabi(apply_context&);
void apply_eosio_onerror(apply_context&);
void apply_eosio_canceldelay(apply_context&);
void apply_eosio_mindelay(apply_context&);
///@} end action handlers
} } } /// namespace eosio::contracts
......@@ -29,7 +29,8 @@ struct genesis_state_type {
.max_authority_depth = config::default_max_auth_depth,
.max_inline_depth = config::default_max_inline_depth,
.max_inline_action_size = config::default_max_inline_action_size,
.max_generated_transaction_size = config::default_max_gen_trx_size
.max_generated_transaction_size = config::default_max_gen_trx_size,
.max_generated_transaction_count = config::default_max_gen_trx_count
};
time_point initial_timestamp;
......
......@@ -150,6 +150,7 @@ struct updateauth {
permission_name permission;
permission_name parent;
authority data;
uint32 delay;
static account_name get_account() {
return config::system_account_name;
......@@ -268,6 +269,29 @@ struct vetorecovery {
}
};
struct canceldelay {
uint32 sender_id;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(canceldelay);
}
};
struct mindelay {
uint32 delay;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(mindelay);
}
};
} } } /// namespace eosio::chain::contracts
......@@ -281,10 +305,12 @@ FC_REFLECT( eosio::chain::contracts::abi_def , (types)(
FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery) )
FC_REFLECT( eosio::chain::contracts::setcode , (account)(vmtype)(vmversion)(code) ) //abi
FC_REFLECT( eosio::chain::contracts::setabi , (account)(abi) )
FC_REFLECT( eosio::chain::contracts::updateauth , (account)(permission)(parent)(data) )
FC_REFLECT( eosio::chain::contracts::updateauth , (account)(permission)(parent)(data)(delay) )
FC_REFLECT( eosio::chain::contracts::deleteauth , (account)(permission) )
FC_REFLECT( eosio::chain::contracts::linkauth , (account)(code)(type)(requirement) )
FC_REFLECT( eosio::chain::contracts::unlinkauth , (account)(code)(type) )
FC_REFLECT( eosio::chain::contracts::postrecovery , (account)(data)(memo) )
FC_REFLECT( eosio::chain::contracts::passrecovery , (account) )
FC_REFLECT( eosio::chain::contracts::vetorecovery , (account) )
FC_REFLECT( eosio::chain::contracts::canceldelay , (sender_id) )
FC_REFLECT( eosio::chain::contracts::mindelay , (delay) )
......@@ -29,7 +29,7 @@ namespace eosio { namespace chain {
id_type id;
transaction_id_type trx_id;
account_name sender;
uint32_t sender_id = 0; /// ID given this transaction by the sender
uint64_t sender_id = 0; /// ID given this transaction by the sender
time_point delay_until; /// this generated transaction will not be applied until the specified time
time_point expiration; /// this generated transaction will not be applied after this time
time_point published;
......@@ -62,8 +62,7 @@ namespace eosio { namespace chain {
ordered_unique< tag<by_sender_id>,
composite_key< generated_transaction_object,
BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, account_name, sender),
BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, uint32_t, sender_id),
BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, generated_transaction_object::id_type, id)
BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, uint64_t, sender_id)
>
>
>
......
......@@ -17,36 +17,45 @@ namespace eosio { namespace chain {
permission_name name; ///< human-readable name for the permission
shared_authority auth; ///< authority required to execute this permission
time_point last_updated; ///< the last time this authority was updated
time_point delay; ///< delay associated with this permission
/**
* @brief Checks if this permission is equivalent or greater than other
* @tparam Index The permission_index
* @return True if this permission matches, or is a parent of, other; false otherwise
* @return a time_point set to the maximum delay encountered between this and the permission that is other;
* empty optional otherwise
*
* Permissions are organized hierarchically such that a parent permission is strictly more powerful than its
* children/grandchildren. This method checks whether this permission is of greater or equal power (capable of
* satisfying) permission @ref other. This would be the case if this permission matches, or is some parent of,
* other.
* satisfying) permission @ref other. The returned value is an optional<time_point> that will indicate the
* maximum delay encountered walking the hierarchy between this permission and other, if other satisfies this,
* otherwise an empty optional is returned.
*/
template <typename Index>
bool satisfies(const permission_object& other, const Index& permission_index) const {
optional<time_point> satisfies(const permission_object& other, const Index& permission_index) const {
// If the owners are not the same, this permission cannot satisfy other
if (owner != other.owner)
return false;
return optional<time_point>();
// if other satisfies this permission, then other's delay and this delay will have to contribute
auto max_delay = other.delay > delay ? other.delay : delay;
// If this permission matches other, or is the immediate parent of other, then this permission satisfies other
if (id == other.id || id == other.parent)
return true;
return optional<time_point>(max_delay);
// Walk up other's parent tree, seeing if we find this permission. If so, this permission satisfies other
const permission_object* parent = &*permission_index.template get<by_id>().find(other.parent);
while (parent) {
if (max_delay < parent->delay)
max_delay = parent->delay;
if (id == parent->parent)
return true;
return optional<time_point>(max_delay);
if (parent->parent._id == 0)
return false;
return optional<time_point>();
parent = &*permission_index.template get<by_id>().find(parent->parent);
}
// This permission is not a parent of other, and so does not satisfy other
return false;
return optional<time_point>();
}
};
......@@ -108,7 +117,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::permission_object, eosio::chain::permissi
CHAINBASE_SET_INDEX_TYPE(eosio::chain::permission_usage_object, eosio::chain::permission_usage_index)
FC_REFLECT(chainbase::oid<eosio::chain::permission_object>, (_id))
FC_REFLECT(eosio::chain::permission_object, (id)(owner)(parent)(name)(auth))
FC_REFLECT(eosio::chain::permission_object, (id)(owner)(parent)(name)(auth)(last_updated)(delay))
FC_REFLECT(chainbase::oid<eosio::chain::permission_usage_object>, (_id))
FC_REFLECT(eosio::chain::permission_usage_object, (id)(account)(permission)(last_used))
......@@ -82,7 +82,8 @@ namespace eosio { namespace chain {
enum status_enum {
executed = 0, ///< succeed, no error handler executed
soft_fail = 1, ///< objectively failed (not executed), error handler executed
hard_fail = 2 ///< objectively failed and error handler objectively failed thus no state change
hard_fail = 2, ///< objectively failed and error handler objectively failed thus no state change
delayed = 3 ///< transaction delayed
};
transaction_receipt() : status(hard_fail) {}
......@@ -138,8 +139,8 @@ namespace eosio { namespace chain {
vector<action> actions;
transaction_id_type id()const;
digest_type sig_digest( const chain_id_type& chain_id )const;
flat_set<public_key_type> get_signature_keys( const vector<signature_type>& signatures, const chain_id_type& chain_id )const;
digest_type sig_digest( const chain_id_type& chain_id, const vector<bytes>& cfd = vector<bytes>() )const;
flat_set<public_key_type> get_signature_keys( const vector<signature_type>& signatures, const chain_id_type& chain_id, const vector<bytes>& cfd = vector<bytes>() )const;
};
......@@ -216,6 +217,15 @@ namespace eosio { namespace chain {
uint64_t sender_id; /// ID assigned by sender of generated, accessible via WASM api when executing normal or error
account_name sender; /// receives error handler callback
time_point_sec execute_after; /// delayed exeuction
deferred_transaction() = default;
deferred_transaction(uint32_t sender_id, account_name sender, time_point_sec execute_after, const transaction& txn)
: transaction(txn),
sender_id(sender_id),
sender(sender),
execute_after(execute_after)
{}
};
struct deferred_reference {
......@@ -253,8 +263,7 @@ namespace eosio { namespace chain {
using transaction_receipt::transaction_receipt;
vector<action_trace> action_traces;
vector<deferred_transaction> deferred_transactions;
vector<deferred_reference> canceled_deferred;
vector<fc::static_variant<deferred_transaction, deferred_reference>> deferred_transaction_requests;
};
} } // eosio::chain
......@@ -266,12 +275,13 @@ FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction
FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib))
FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(data) )
FC_REFLECT_DERIVED( eosio::chain::deferred_transaction, (eosio::chain::transaction), (sender_id)(sender)(execute_after) )
FC_REFLECT( eosio::chain::deferred_reference, (sender_id)(sender) )
FC_REFLECT_ENUM( eosio::chain::data_access_info::access_type, (read)(write))
FC_REFLECT( eosio::chain::data_access_info, (type)(code)(scope)(sequence))
FC_REFLECT( eosio::chain::action_trace, (receiver)(act)(console)(region_id)(cycle_index)(data_access) )
FC_REFLECT( eosio::chain::transaction_receipt, (status)(id))
FC_REFLECT_ENUM( eosio::chain::transaction_receipt::status_enum, (executed)(soft_fail)(hard_fail))
FC_REFLECT_DERIVED( eosio::chain::transaction_trace, (eosio::chain::transaction_receipt), (action_traces)(deferred_transactions) )
FC_REFLECT_ENUM( eosio::chain::transaction_receipt::status_enum, (executed)(soft_fail)(hard_fail)(delayed) )
FC_REFLECT_DERIVED( eosio::chain::transaction_trace, (eosio::chain::transaction_receipt), (action_traces)(deferred_transaction_requests) )
......@@ -64,20 +64,22 @@ transaction_id_type transaction::id() const {
}
digest_type transaction::sig_digest( const chain_id_type& chain_id )const {
digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector<bytes>& cfd )const {
digest_type::encoder enc;
fc::raw::pack( enc, chain_id );
fc::raw::pack( enc, *this );
if( cfd.size() )
fc::raw::pack( enc, cfd );
return enc.result();
}
flat_set<public_key_type> transaction::get_signature_keys( const vector<signature_type>& signatures, const chain_id_type& chain_id )const
flat_set<public_key_type> transaction::get_signature_keys( const vector<signature_type>& signatures, const chain_id_type& chain_id, const vector<bytes>& cfd )const
{ try {
using boost::adaptors::transformed;
constexpr size_t recovery_cache_size = 100000;
static recovery_cache_type recovery_cache;
const digest_type digest = sig_digest(chain_id);
const digest_type digest = sig_digest(chain_id, cfd);
flat_set<public_key_type> recovered_pub_keys;
for(const signature_type& sig : signatures) {
......@@ -100,17 +102,17 @@ flat_set<public_key_type> transaction::get_signature_keys( const vector<signatur
const signature_type& signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id) {
signatures.push_back(key.sign(sig_digest(chain_id)));
signatures.push_back(key.sign(sig_digest(chain_id, context_free_data)));
return signatures.back();
}
signature_type signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)const {
return key.sign(sig_digest(chain_id));
return key.sign(sig_digest(chain_id, context_free_data));
}
flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{
return transaction::get_signature_keys(signatures, chain_id);
return transaction::get_signature_keys(signatures, chain_id, context_free_data);
}
namespace bio = boost::iostreams;
......
......@@ -1033,7 +1033,8 @@ class transaction_api : public context_aware_api {
void send_deferred( uint64_t sender_id, const fc::time_point_sec& execute_after, array_ptr<char> data, size_t data_len ) {
try {
// TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size
FC_ASSERT(data_len < config::default_max_gen_trx_size, "generated transaction too big");
const auto& gpo = context.controller.get_global_properties();
FC_ASSERT(data_len < gpo.configuration.max_generated_transaction_size, "generated transaction too big");
deferred_transaction dtrx;
fc::raw::unpack<transaction>(data, data_len, dtrx);
......
......@@ -62,6 +62,7 @@ namespace fc {
time_point& operator += ( const microseconds& m) { elapsed+=m; return *this; }
time_point& operator -= ( const microseconds& m) { elapsed-=m; return *this; }
time_point operator + (const microseconds& m) const { return time_point(elapsed+m); }
time_point operator + (const time_point& m) const { return time_point(elapsed+m.elapsed); }
time_point operator - (const microseconds& m) const { return time_point(elapsed-m); }
microseconds operator - (const time_point& m) const { return microseconds(elapsed.count() - m.elapsed.count()); }
private:
......@@ -102,8 +103,10 @@ namespace fc {
friend bool operator != ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds != b.utc_seconds; }
time_point_sec& operator += ( uint32_t m ) { utc_seconds+=m; return *this; }
time_point_sec& operator += ( microseconds m ) { utc_seconds+=m.to_seconds(); return *this; }
time_point_sec& operator += ( time_point_sec m ) { utc_seconds+=m.utc_seconds; return *this; }
time_point_sec& operator -= ( uint32_t m ) { utc_seconds-=m; return *this; }
time_point_sec& operator -= ( microseconds m ) { utc_seconds-=m.to_seconds(); return *this; }
time_point_sec& operator -= ( time_point_sec m ) { utc_seconds-=m.utc_seconds; return *this; }
time_point_sec operator +( uint32_t offset )const { return time_point_sec(utc_seconds + offset); }
time_point_sec operator -( uint32_t offset )const { return time_point_sec(utc_seconds - offset); }
......
......@@ -64,6 +64,8 @@ namespace eosio { namespace testing {
public:
typedef string action_result;
static const uint32_t DEFAULT_EXPIRATION_DELTA = 6;
base_tester(chain_controller::runtime_limits limits = chain_controller::runtime_limits());
explicit base_tester(chain_controller::controller_config config);
......@@ -78,10 +80,10 @@ namespace eosio { namespace testing {
transaction_trace push_transaction( signed_transaction& trx, uint32_t skip_flag = skip_nothing );
action_result push_action(action&& cert_act, uint64_t authorizer);
transaction_trace push_action( const account_name& code, const action_name& act, const account_name& signer, const variant_object &data );
transaction_trace push_action( const account_name& code, const action_name& acttype, const account_name& actor, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA );
transaction_trace push_action( const account_name& code, const action_name& acttype, const vector<account_name>& actors, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA );
void set_tapos( signed_transaction& trx ) const;
void set_tapos( signed_transaction& trx, uint32_t expiration = DEFAULT_EXPIRATION_DELTA ) const;
void create_accounts( vector<account_name> names, bool multisig = false ) {
for( auto n : names ) create_account(n, config::system_account_name, multisig );
......@@ -96,7 +98,7 @@ namespace eosio { namespace testing {
void delete_authority( account_name account, permission_name perm, const vector<permission_level>& auths, const vector<private_key_type>& keys );
void delete_authority( account_name account, permission_name perm );
void create_account( account_name name, account_name creator = config::system_account_name, bool multisig = false );
void create_account( account_name name, account_name creator = config::system_account_name, bool multisig = false );
transaction_trace push_reqauth( account_name from, const vector<permission_level>& auths, const vector<private_key_type>& keys );
transaction_trace push_reqauth(account_name from, string role, bool multi_sig = false);
......
......@@ -106,8 +106,8 @@ namespace eosio { namespace testing {
}
}
void base_tester::set_tapos( signed_transaction& trx ) const {
trx.expiration = control->head_block_time() + fc::seconds(6);
void base_tester::set_tapos( signed_transaction& trx, uint32_t expiration ) const {
trx.expiration = control->head_block_time() + fc::seconds(expiration);
trx.set_reference_block( control->head_block_id() );
}
......@@ -169,7 +169,18 @@ namespace eosio { namespace testing {
transaction_trace base_tester::push_action( const account_name& code,
const action_name& acttype,
const account_name& actor,
const variant_object& data )
const variant_object& data,
uint32_t expiration)
{ try {
return push_action(code, acttype, vector<account_name>{ actor }, data, expiration);
} FC_CAPTURE_AND_RETHROW( (code)(acttype)(actor)(data)(expiration) ) }
transaction_trace base_tester::push_action( const account_name& code,
const action_name& acttype,
const vector<account_name>& actors,
const variant_object& data,
uint32_t expiration)
{ try {
const auto& acnt = control->get_database().get<account_object,by_name>(code);
......@@ -184,16 +195,20 @@ namespace eosio { namespace testing {
action act;
act.account = code;
act.name = acttype;
act.authorization = vector<permission_level>{{actor, config::active_name}};
for (const auto& actor : actors) {
act.authorization.push_back(permission_level{actor, config::active_name});
}
act.data = abis.variant_to_binary(action_type_name, data);
signed_transaction trx;
trx.actions.emplace_back(std::move(act));
set_tapos(trx);
trx.sign(get_private_key(actor, "active"), chain_id_type());
set_tapos(trx, expiration);
for (const auto& actor : actors) {
trx.sign(get_private_key(actor, "active"), chain_id_type());
}
return push_transaction(trx);
} FC_CAPTURE_AND_RETHROW( (code)(acttype)(actor)(data) ) }
} FC_CAPTURE_AND_RETHROW( (code)(acttype)(actors)(data)(expiration) ) }
transaction_trace base_tester::push_reqauth( account_name from, const vector<permission_level>& auths, const vector<private_key_type>& keys ) {
variant pretty_trx = fc::mutable_variant_object()
......@@ -397,7 +412,7 @@ namespace eosio { namespace testing {
void base_tester::set_code( account_name account, const char* wast ) try {
set_code(account, wast_to_wasm(wast));
} FC_CAPTURE_AND_RETHROW( (account)(wast) )
} FC_CAPTURE_AND_RETHROW( (account) )
void base_tester::set_code( account_name account, const vector<uint8_t> wasm ) try {
signed_transaction trx;
......
......@@ -19,30 +19,30 @@ if(BUILD_MONGO_DB_PLUGIN)
# link step for all executables using this archive must include the
# mongo-cxx-driver libraries libmongocxx and libbsoncxx.
find_package(libbsoncxx REQUIRED)
message(STATUS "Found bsoncxx headers: ${LIBBSONCXX_INCLUDE_DIRS}")
find_package(libbsoncxx-static REQUIRED)
message(STATUS "Found bsoncxx headers: ${LIBBSONCXX_STATIC_INCLUDE_DIRS}")
# mongo-cxx-driver 3.2 release altered LIBBSONCXX_LIBRARIES semantics. Instead of library names,
# it now hold library paths.
if((LIBBSONCXX_VERSION_MAJOR LESS 3) OR ((LIBBSONCXX_VERSION_MAJOR EQUAL 3) AND (LIBBSONCXX_VERSION_MINOR LESS 2)))
find_library(EOS_LIBBSONCXX ${LIBBSONCXX_LIBRARIES}
PATHS ${LIBBSONCXX_LIBRARY_DIRS} NO_DEFAULT_PATH)
if((LIBBSONCXX_STATIC_VERSION_MAJOR LESS 3) OR ((LIBBSONCXX_STATIC_VERSION_MAJOR EQUAL 3) AND (LIBBSONCXX_STATIC_VERSION_MINOR LESS 2)))
find_library(EOS_LIBBSONCXX ${LIBBSONCXX_STATIC_LIBRARIES}
PATHS ${LIBBSONCXX_STATIC_LIBRARY_DIRS} NO_DEFAULT_PATH)
else()
set(EOS_LIBBSONCXX ${LIBBSONCXX_LIBRARIES})
set(EOS_LIBBSONCXX ${LIBBSONCXX_STATIC_LIBRARIES})
endif()
message(STATUS "Found bsoncxx library: ${EOS_LIBBSONCXX}")
find_package(libmongocxx REQUIRED)
message(STATUS "Found mongocxx headers: ${LIBMONGOCXX_INCLUDE_DIRS}")
find_package(libmongocxx-static REQUIRED)
message(STATUS "Found mongocxx headers: ${LIBMONGOCXX_STATIC_INCLUDE_DIRS}")
# mongo-cxx-driver 3.2 release altered LIBBSONCXX_LIBRARIES semantics. Instead of library names,
# it now hold library paths.
if((LIBMONGOCXX_VERSION_MAJOR LESS 3) OR ((LIBMONGOCXX_VERSION_MAJOR EQUAL 3) AND (LIBMONGOCXX_VERSION_MINOR LESS 2)))
find_library(EOS_LIBMONGOCXX ${LIBMONGOCXX_LIBRARIES}
PATHS ${LIBMONGOCXX_LIBRARY_DIRS} NO_DEFAULT_PATH)
if((LIBMONGOCXX_STATIC_VERSION_MAJOR LESS 3) OR ((LIBMONGOCXX_STATIC_VERSION_MAJOR EQUAL 3) AND (LIBMONGOCXX_STATIC_VERSION_MINOR LESS 2)))
find_library(EOS_LIBMONGOCXX ${LIBMONGOCXX_STATIC_LIBRARIES}
PATHS ${LIBMONGOCXX_STATIC_LIBRARY_DIRS} NO_DEFAULT_PATH)
else()
set(EOS_LIBMONGOCXX ${LIBMONGOCXX_LIBRARIES})
set(EOS_LIBMONGOCXX ${LIBMONGOCXX_STATIC_LIBRARIES})
endif()
message(STATUS "Found mongocxx library: ${EOS_LIBMONGOCXX}")
......@@ -58,7 +58,7 @@ if(BUILD_MONGO_DB_PLUGIN)
#
# git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
# cd mongo-cxx-driver/build
# cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
# cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_SHARED_LIBS=OFF ..
# sudo make EP_mnmlstc_core
# make
# sudo make install
......@@ -67,20 +67,18 @@ if(BUILD_MONGO_DB_PLUGIN)
endif()
target_include_directories(mongo_db_plugin
PRIVATE ${LIBMONGOCXX_INCLUDE_DIRS} ${LIBBSONCXX_INCLUDE_DIRS}
PRIVATE ${LIBMONGOCXX_STATIC_INCLUDE_DIRS} ${LIBBSONCXX_STATIC_INCLUDE_DIRS}
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
)
target_compile_definitions(mongo_db_plugin
PRIVATE ${LIBMONGOCXX_DEFINITIONS} ${LIBBSONCXX_DEFINITIONS}
PRIVATE ${LIBMONGOCXX_STATIC_DEFINITIONS} ${LIBBSONCXX_STATIC_DEFINITIONS}
)
target_link_libraries(mongo_db_plugin
PUBLIC chain_plugin eosio_chain appbase
${EOS_LIBMONGOCXX} ${EOS_LIBBSONCXX}
)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libmongoc-1.0-0 (>= 1.3)" PARENT_SCOPE)
else()
message("mongo_db_plugin not selected and will be omitted.")
endif()
......@@ -475,16 +475,26 @@ void mongo_db_plugin_impl::_process_block(const block_trace& bt, const signed_bl
"unknown";
trx_status_map[trx_trace.id] = trx_status;
for (const auto& trx : trx_trace.deferred_transactions) {
auto doc = process_trx(trx);
doc.append(kvp("type", "deferred"),
kvp("sender_id", b_int64{static_cast<int64_t>(trx.sender_id)}),
kvp("sender", trx.sender.to_string()),
kvp("execute_after", b_date{std::chrono::milliseconds{
std::chrono::seconds{trx.execute_after.sec_since_epoch()}}}));
mongocxx::model::insert_one insert_op{doc.view()};
bulk_trans.append(insert_op);
++trx_num;
for (const auto& req : trx_trace.deferred_transaction_requests) {
if ( req.contains<chain::deferred_transaction>() ) {
auto trx = req.get<chain::deferred_transaction>();
auto doc = process_trx(trx);
doc.append(kvp("type", "deferred"),
kvp("sender_id", b_int64{static_cast<int64_t>(trx.sender_id)}),
kvp("sender", trx.sender.to_string()),
kvp("execute_after", b_date{std::chrono::milliseconds{
std::chrono::seconds{trx.execute_after.sec_since_epoch()}}}));
mongocxx::model::insert_one insert_op{doc.view()};
bulk_trans.append(insert_op);
++trx_num;
} else {
auto cancel = req.get<chain::deferred_reference>();
auto doc = bsoncxx::builder::basic::document{};
doc.append(kvp("type", "cancel_deferred"),
kvp("sender_id", b_int64{static_cast<int64_t>(cancel.sender_id)}),
kvp("sender", cancel.sender.to_string())
);
}
}
if (!trx_trace.action_traces.empty()) {
actions_to_write = true;
......
......@@ -2253,7 +2253,11 @@ namespace eosio {
}
}
break;
}}
}
case transaction_receipt::delayed:
#warning TODO: Not sure what should happen here
break;
}
}
}
}
......
......@@ -176,7 +176,7 @@ mongodconf
fi
printf "\n\tChecking MongoDB C++ driver installation.\n"
if [ ! -e /usr/local/lib/libmongocxx.so ]; then
if [ ! -e /usr/local/lib/libmongocxx-static.a ]; then
cd ${TEMP_DIR}
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
if [ $? -ne 0 ]; then
......@@ -188,7 +188,7 @@ mongodconf
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f ${TEMP_DIR}/mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --with-libbson=bundled --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
if [ $? -ne 0 ]; then
printf "\tConfiguring MondgDB C driver has encountered the errors above.\n"
printf "\tExiting now.\n\n"
......@@ -209,6 +209,7 @@ mongodconf
cd ..
rm -rf ${TEMP_DIR}/mongo-c-driver-1.9.3
cd ${TEMP_DIR}
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
if [ $? -ne 0 ]; then
printf "\tUnable to clone MondgDB C++ driver at this time.\n"
......@@ -216,7 +217,7 @@ mongodconf
exit;
fi
cd mongo-cxx-driver/build
${CMAKE} -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
${CMAKE} -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
if [ $? -ne 0 ]; then
printf "\tCmake has encountered the above errors building the MongoDB C++ driver.\n"
printf "\tExiting now.\n\n"
......@@ -237,7 +238,7 @@ mongodconf
cd ..
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
else
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx.so.\n"
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\n"
fi
printf "\n\tChecking secp256k1-zkp installation.\n"
......
......@@ -249,7 +249,7 @@ mongodconf
fi
printf "\n\tChecking for MongoDB C++ driver.\n"
if [ ! -e /usr/local/lib/libmongocxx.so ]; then
if [ ! -e /usr/local/lib/libmongocxx-static.a ]; then
printf "\n\tInstalling MongoDB C & C++ drivers.\n"
cd ${TEMP_DIR}
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
......@@ -262,7 +262,7 @@ mongodconf
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f ${TEMP_DIR}/mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --with-libbson=bundled --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
if [ $? -ne 0 ]; then
printf "\tConfiguring MondgDB C driver has encountered the errors above.\n"
printf "\tExiting now.\n\n"
......@@ -283,6 +283,7 @@ mongodconf
cd ..
rm -rf ${TEMP_DIR}/mongo-c-driver-1.9.3
cd ${TEMP_DIR}
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
if [ $? -ne 0 ]; then
printf "\tUnable to clone MondgDB C++ driver at this time.\n"
......@@ -290,7 +291,7 @@ mongodconf
exit;
fi
cd mongo-cxx-driver/build
${CMAKE} -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
${CMAKE} -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
if [ $? -ne 0 ]; then
printf "\tCmake has encountered the above errors building the MongoDB C++ driver.\n"
printf "\tExiting now.\n\n"
......@@ -311,7 +312,7 @@ mongodconf
cd
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
else
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx.so.\n"
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\n"
fi
printf "\n\tChecking for secp256k1-zkp\n"
if [ ! -e /usr/local/lib/libsecp256k1.a ]; then
......
......@@ -155,7 +155,7 @@
printf "\n\tChecking for MongoDB C++ driver\n"
# install libmongocxx.dylib
if [ ! -e /usr/local/lib/libmongocxx.dylib ]; then
if [ ! -e /usr/local/lib/libmongocxx-static.a ]; then
cd ${TEMP_DIR}
brew install --force pkgconfig
brew unlink pkgconfig && brew link --force pkgconfig
......@@ -169,7 +169,7 @@
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f ${TEMP_DIR}/mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=darwin --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --with-libbson=bundled --enable-ssl=darwin --disable-automatic-init-and-cleanup --prefix=/usr/local
if [ $? -ne 0 ]; then
printf "\tConfiguring MondgDB C driver has encountered the errors above.\n"
printf "\tExiting now.\n\n"
......@@ -190,6 +190,7 @@
cd ..
rm -rf ${TEMP_DIR}/mongo-c-driver-1.9.3
cd ${TEMP_DIR}
rm -rf ${TEMP_DIR}/mongo-cxx-driver
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
if [ $? -ne 0 ]; then
printf "\tUnable to clone MondgDB C++ driver at this time.\n"
......@@ -197,7 +198,7 @@
exit;
fi
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
if [ $? -ne 0 ]; then
printf "\tCmake has encountered the above errors building the MongoDB C++ driver.\n"
printf "\tExiting now.\n\n"
......@@ -218,7 +219,7 @@
cd
rm -rf ${TEMP_DIR}/mongo-cxx-driver
else
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx.dylib.\n"
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\n"
fi
printf "\n\tChecking for secp256k1-zkp\n"
......
......@@ -124,8 +124,7 @@
fi
printf "\n\tChecking for MongoDB C++ driver.\n"
# install libmongocxx.dylib
if [ ! -e /usr/local/lib/libmongocxx.so ]; then
if [ ! -e /usr/local/lib/libmongocxx-static.a ]; then
printf "\n\tInstalling MongoDB C & C++ drivers.\n"
cd ${TEMP_DIR}
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
......@@ -138,7 +137,7 @@
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f ${TEMP_DIR}/mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --with-libbson=bundled --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
if [ $? -ne 0 ]; then
printf "\tConfiguring MondgDB C driver has encountered the errors above.\n"
printf "\tExiting now.\n\n"
......@@ -159,6 +158,7 @@
cd ..
rm -rf ${TEMP_DIR}/mongo-c-driver-1.9.3
cd ${TEMP_DIR}
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
if [ $? -ne 0 ]; then
printf "\tUnable to clone MondgDB C++ driver at this time.\n"
......@@ -166,7 +166,7 @@
exit;
fi
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
if [ $? -ne 0 ]; then
printf "\tCmake has encountered the above errors building the MongoDB C++ driver.\n"
printf "\tExiting now.\n\n"
......@@ -187,7 +187,7 @@
cd
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
else
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx.so.\n"
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\n"
fi
printf "\n\tChecking for secp256k1-zkp\n"
......
......@@ -117,8 +117,7 @@
fi
printf "\n\tChecking for MongoDB C++ driver.\n"
# install libmongocxx.dylib
if [ ! -e /usr/local/lib/libmongocxx.so ]; then
if [ ! -e /usr/local/lib/libmongocxx-static.a ]; then
printf "\n\tInstalling MongoDB C & C++ drivers.\n"
cd ${TEMP_DIR}
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.3/mongo-c-driver-1.9.3.tar.gz
......@@ -131,7 +130,7 @@
tar xf mongo-c-driver-1.9.3.tar.gz
rm -f ${TEMP_DIR}/mongo-c-driver-1.9.3.tar.gz
cd mongo-c-driver-1.9.3
./configure --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
./configure --enable-static --with-libbson=bundled --enable-ssl=openssl --disable-automatic-init-and-cleanup --prefix=/usr/local
if [ $? -ne 0 ]; then
printf "\tConfiguring MondgDB C driver has encountered the errors above.\n"
printf "\tExiting now.\n\n"
......@@ -152,6 +151,7 @@
cd ..
rm -rf ${TEMP_DIR}/mongo-c-driver-1.9.3
cd ${TEMP_DIR}
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
git clone https://github.com/mongodb/mongo-cxx-driver.git --branch releases/stable --depth 1
if [ $? -ne 0 ]; then
printf "\tUnable to clone MondgDB C++ driver at this time.\n"
......@@ -159,7 +159,7 @@
exit;
fi
cd mongo-cxx-driver/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
if [ $? -ne 0 ]; then
printf "\tCmake has encountered the above errors building the MongoDB C++ driver.\n"
printf "\tExiting now.\n\n"
......@@ -180,7 +180,7 @@
cd
sudo rm -rf ${TEMP_DIR}/mongo-cxx-driver
else
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx.so.\n"
printf "\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\n"
fi
printf "\n\tChecking for secp256k1-zkp\n"
......
......@@ -15,14 +15,14 @@ set( CMAKE_CXX_STANDARD 14 )
#include_directories("${CMAKE_BINARY_DIR}/tests/api_tests")
include_directories("${CMAKE_BINARY_DIR}/contracts")
include_directories("${CMAKE_SOURCE_DIR}/contracts")
include_directories("${CMAKE_SOURCE_DIR}/plugins/wallet_plugin/include")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/config.hpp ESCAPE_QUOTES)
file(GLOB UNIT_TESTS "chain_tests/*.cpp" "api_tests/*.cpp" "tests/abi_tests.cpp" "tests/database_tests.cpp" "tests/misc_tests.cpp" "wasm_tests/*.cpp" "tests/message_buffer_tests.cpp")
file(GLOB UNIT_TESTS "chain_tests/*.cpp" "api_tests/*.cpp" "tests/abi_tests.cpp" "tests/database_tests.cpp" "tests/misc_tests.cpp" "wasm_tests/*.cpp" "tests/message_buffer_tests.cpp" "tests/wallet_tests.cpp")
add_executable( chain_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} common/main.cpp)
target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilities chain_plugin abi_generator fc ${PLATFORM_SPECIFIC_LIBS} )
target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilities chain_plugin wallet_plugin abi_generator fc ${PLATFORM_SPECIFIC_LIBS} )
target_include_directories( chain_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts )
target_include_directories( chain_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/wasm_tests )
......
......@@ -666,6 +666,46 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, tester) { try {
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, tester) { try {
produce_blocks(2);
create_account( N(testapi) );
produce_blocks(100);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
//schedule
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", fc::raw::pack(uint64_t(1)) );
//check that it doesn't get executed immediately
auto traces = control->push_deferred_transactions( true );
BOOST_CHECK_EQUAL( 0, traces.size() );
produce_blocks(24);
//check that it gets executed afterwards
traces = control->push_deferred_transactions( true );
BOOST_CHECK_EQUAL( 1, traces.size() );
//schedule twice (second deferred transaction should replace first one)
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
produce_blocks( 24 );
//check that only one deferred transaction executed
traces = control->push_deferred_transactions( true );
BOOST_CHECK_EQUAL( 1, traces.size() );
//schedule and cancel
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction", {});
produce_blocks( 24 );
traces = control->push_deferred_transactions( true );
BOOST_CHECK_EQUAL( 0, traces.size() );
//cancel_deferred() before scheduling transaction should not prevent the transaction from being scheduled (check that previous bug is fixed)
CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction", {});
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
produce_blocks( 24 );
traces = control->push_deferred_transactions( true );
BOOST_CHECK_EQUAL( 1, traces.size() );
} FC_LOG_AND_RETHROW() }
template <uint64_t NAME>
struct setprod_act {
static account_name get_account() {
......
......@@ -105,6 +105,55 @@ BOOST_AUTO_TEST_CASE(trx_variant ) {
}
}
BOOST_AUTO_TEST_CASE(trx_uniqueness) {
tester chain;
signed_transaction trx;
name new_account_name = name("alice");
authority owner_auth = authority(chain.get_public_key( new_account_name, "owner"));
trx.actions.emplace_back(vector<permission_level>{{config::system_account_name, config::active_name}},
contracts::newaccount{
.creator = config::system_account_name,
.name = new_account_name,
.owner = owner_auth,
.active = authority(chain.get_public_key(new_account_name, "active")),
.recovery = authority(chain.get_public_key(new_account_name, "recovery)),"))
});
trx.expiration = time_point_sec(chain.control->head_block_time()) + 90;
trx.ref_block_num = static_cast<uint16_t>(chain.control->head_block_num());
trx.ref_block_prefix = static_cast<uint32_t>(chain.control->head_block_id()._hash[1]);
trx.sign(chain.get_private_key(config::system_account_name, "active"), chain_id_type());
chain.push_transaction(trx);
BOOST_CHECK_THROW(chain.push_transaction(trx), tx_duplicate);
}
BOOST_AUTO_TEST_CASE(invalid_expiration) {
tester chain;
signed_transaction trx;
name new_account_name = name("alice");
authority owner_auth = authority(chain.get_public_key( new_account_name, "owner"));
trx.actions.emplace_back(vector<permission_level>{{config::system_account_name, config::active_name}},
contracts::newaccount{
.creator = config::system_account_name,
.name = new_account_name,
.owner = owner_auth,
.active = authority(chain.get_public_key(new_account_name, "active")),
.recovery = authority(chain.get_public_key(new_account_name, "recovery)),"))
});
trx.ref_block_num = static_cast<uint16_t>(chain.control->head_block_num());
trx.ref_block_prefix = static_cast<uint32_t>(chain.control->head_block_id()._hash[1]);
trx.sign(chain.get_private_key(config::system_account_name, "active"), chain_id_type());
// Unset expiration should throw
BOOST_CHECK_THROW(chain.push_transaction(trx), transaction_exception);
memset(&trx.expiration, 0, sizeof(trx.expiration)); // currently redundant, as default is all zeros, but may not always be.
trx.sign(chain.get_private_key(config::system_account_name, "active"), chain_id_type());
// Expired transaction (January 1970) should throw
BOOST_CHECK_THROW(chain.push_transaction(trx), transaction_exception);
}
BOOST_AUTO_TEST_CASE(irrelevant_auth) {
try {
tester chain;
......@@ -177,12 +226,14 @@ BOOST_AUTO_TEST_CASE(order_dependent_transactions)
("account", "tester")
("permission", "first")
("parent", "active")
("data", authority(chain.get_public_key(name("tester"), "first"))));
("data", authority(chain.get_public_key(name("tester"), "first")))
("delay", 0));
chain.push_action(name("eosio"), name("updateauth"), name("tester"), fc::mutable_variant_object()
("account", "tester")
("permission", "second")
("parent", "first")
("data", authority(chain.get_public_key(name("tester"), "second"))));
("data", authority(chain.get_public_key(name("tester"), "second")))
("delay", 0));
// Ensure the related auths are created
const auto* first_auth = chain.find<permission_object, by_owner>(boost::make_tuple(name("tester"), name("first")));
......
此差异已折叠。
......@@ -52,8 +52,8 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_multisig_owner, tester ) try {
{
signed_transaction trx = make_postrecovery(*this, N(alice), "owner.recov");
auto trace = push_transaction(trx);
BOOST_REQUIRE_EQUAL(trace.deferred_transactions.size(), 1);
recovery_txid = trace.deferred_transactions.front().id();
BOOST_REQUIRE_EQUAL(trace.deferred_transaction_requests.size(), 1);
recovery_txid = trace.deferred_transaction_requests.front().get<deferred_transaction>().id();
produce_block();
BOOST_REQUIRE_EQUAL(chain_has_transaction(trx.id()), true);
}
......@@ -84,8 +84,8 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner, tester ) try {
{
signed_transaction trx = make_postrecovery(*this, N(alice), "owner.recov");
auto trace = push_transaction(trx);
BOOST_REQUIRE_EQUAL(trace.deferred_transactions.size(), 1);
recovery_txid = trace.deferred_transactions.front().id();
BOOST_REQUIRE_EQUAL(trace.deferred_transaction_requests.size(), 1);
recovery_txid = trace.deferred_transaction_requests.front().get<deferred_transaction>().id();
produce_block();
BOOST_REQUIRE_EQUAL(chain_has_transaction(trx.id()), true);
}
......@@ -117,8 +117,8 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_owner_veto, tester ) try {
{
signed_transaction trx = make_postrecovery(*this, N(alice), "owner.recov");
auto trace = push_transaction(trx);
BOOST_REQUIRE_EQUAL(trace.deferred_transactions.size(), 1);
recovery_txid = trace.deferred_transactions.front().id();
BOOST_REQUIRE_EQUAL(trace.deferred_transaction_requests.size(), 1);
recovery_txid = trace.deferred_transaction_requests.front().get<deferred_transaction>().id();
produce_block();
BOOST_REQUIRE_EQUAL(chain_has_transaction(trx.id()), true);
}
......@@ -159,8 +159,8 @@ BOOST_FIXTURE_TEST_CASE( test_recovery_bad_creator, tester ) try {
{
signed_transaction trx = make_postrecovery(*this, N(alice), "owner");
auto trace = push_transaction(trx);
BOOST_REQUIRE_EQUAL(trace.deferred_transactions.size(), 1);
recovery_txid = trace.deferred_transactions.front().id();
BOOST_REQUIRE_EQUAL(trace.deferred_transaction_requests.size(), 1);
recovery_txid = trace.deferred_transaction_requests.front().get<deferred_transaction>().id();
produce_block();
BOOST_REQUIRE_EQUAL(chain_has_transaction(trx.id()), true);
}
......
......@@ -1937,7 +1937,8 @@ BOOST_AUTO_TEST_CASE(updateauth)
{"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ],
"accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 },
{"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 }]
}
},
"delay" : 0
}
)=====";
......
......@@ -110,6 +110,13 @@ BOOST_AUTO_TEST_CASE(deterministic_distributions)
BOOST_TEST(std::equal(nums.begin(), nums.end(), c.begin()));
} FC_LOG_AND_RETHROW() }
struct permission_visitor {
std::vector<permission_level> permissions;
void operator()(const permission_level& permission) {
permissions.push_back(permission);
}
};
BOOST_AUTO_TEST_CASE(authority_checker)
{ try {
testing::tester test;
......@@ -119,23 +126,24 @@ BOOST_AUTO_TEST_CASE(authority_checker)
auto GetNullAuthority = [](auto){abort(); return authority();};
permission_visitor pv;
auto A = authority(2, {key_weight{a, 1}, key_weight{b, 1}});
{
auto checker = make_auth_checker(GetNullAuthority, 2, {a, b});
auto checker = make_auth_checker(GetNullAuthority, pv, 2, {a, b});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 2);
BOOST_TEST(checker.unused_keys().size() == 0);
}
{
auto checker = make_auth_checker(GetNullAuthority, 2, {a, c});
auto checker = make_auth_checker(GetNullAuthority, pv, 2, {a, c});
BOOST_TEST(!checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 0);
BOOST_TEST(checker.unused_keys().size() == 2);
}
{
auto checker = make_auth_checker(GetNullAuthority, 2, {a, b, c});
auto checker = make_auth_checker(GetNullAuthority, pv, 2, {a, b, c});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 2);
......@@ -145,27 +153,27 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST(checker.unused_keys().count(c) == 1);
}
{
auto checker = make_auth_checker(GetNullAuthority, 2, {b, c});
auto checker = make_auth_checker(GetNullAuthority, pv, 2, {b, c});
BOOST_TEST(!checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 0);
}
A = authority(3, {key_weight{a, 1}, key_weight{b, 1}, key_weight{c, 1}});
BOOST_TEST(make_auth_checker(GetNullAuthority, 2, {c, b, a}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, 2, {a, b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, 2, {a, c}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, 2, {b, c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, pv, 2, {c, b, a}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, pv, 2, {a, b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, pv, 2, {a, c}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, pv, 2, {b, c}).satisfied(A));
A = authority(1, {key_weight{a, 1}, key_weight{b, 1}});
BOOST_TEST(make_auth_checker(GetNullAuthority, 2, {a}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, 2, {b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, 2, {c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, pv, 2, {a}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, pv, 2, {b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, pv, 2, {c}).satisfied(A));
A = authority(1, {key_weight{a, 2}, key_weight{b, 1}});
BOOST_TEST(make_auth_checker(GetNullAuthority, 2, {a}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, 2, {b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, 2, {c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, pv, 2, {a}).satisfied(A));
BOOST_TEST(make_auth_checker(GetNullAuthority, pv, 2, {b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetNullAuthority, pv, 2, {c}).satisfied(A));
auto GetCAuthority = [c](auto){
return authority(1, {key_weight{c, 1}});
......@@ -173,26 +181,26 @@ BOOST_AUTO_TEST_CASE(authority_checker)
A = authority(2, {key_weight{a, 2}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 1}});
{
auto checker = make_auth_checker(GetCAuthority, 2, {a});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {a});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(checker.all_keys_used());
}
{
auto checker = make_auth_checker(GetCAuthority, 2, {b});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {b});
BOOST_TEST(!checker.satisfied(A));
BOOST_TEST(checker.used_keys().size() == 0);
BOOST_TEST(checker.unused_keys().size() == 1);
BOOST_TEST(checker.unused_keys().count(b) == 1);
}
{
auto checker = make_auth_checker(GetCAuthority, 2, {c});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {c});
BOOST_TEST(!checker.satisfied(A));
BOOST_TEST(checker.used_keys().size() == 0);
BOOST_TEST(checker.unused_keys().size() == 1);
BOOST_TEST(checker.unused_keys().count(c) == 1);
}
{
auto checker = make_auth_checker(GetCAuthority, 2, {b, c});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {b, c});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 2);
......@@ -201,7 +209,7 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST(checker.used_keys().count(c) == 1);
}
{
auto checker = make_auth_checker(GetCAuthority, 2, {b, c, a});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {b, c, a});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 1);
......@@ -212,14 +220,14 @@ BOOST_AUTO_TEST_CASE(authority_checker)
}
A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 1}});
BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {a}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, 2, {a, b}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, 2, {b, c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, 2, {a, c}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, pv, 2, {a}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, pv, 2, {b}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, pv, 2, {c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, pv, 2, {a, b}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, pv, 2, {b, c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, pv, 2, {a, c}).satisfied(A));
{
auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {a, b, c});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 2);
......@@ -228,12 +236,12 @@ BOOST_AUTO_TEST_CASE(authority_checker)
}
A = authority(2, {key_weight{a, 1}, key_weight{b, 1}}, {permission_level_weight{{"hello", "world"}, 2}});
BOOST_TEST(make_auth_checker(GetCAuthority, 2, {a, b}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, 2, {c}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {a}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, 2, {b}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, pv, 2, {a, b}).satisfied(A));
BOOST_TEST(make_auth_checker(GetCAuthority, pv, 2, {c}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, pv, 2, {a}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetCAuthority, pv, 2, {b}).satisfied(A));
{
auto checker = make_auth_checker(GetCAuthority, 2, {a, b, c});
auto checker = make_auth_checker(GetCAuthority, pv, 2, {a, b, c});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 1);
......@@ -252,12 +260,12 @@ BOOST_AUTO_TEST_CASE(authority_checker)
A = authority(5, {key_weight{a, 2}, key_weight{b, 2}, key_weight{c, 2}}, {permission_level_weight{{"top", "top"}, 5}});
{
auto checker = make_auth_checker(GetAuthority, 2, {d, e});
auto checker = make_auth_checker(GetAuthority, pv, 2, {d, e});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(checker.all_keys_used());
}
{
auto checker = make_auth_checker(GetAuthority, 2, {a, b, c, d, e});
auto checker = make_auth_checker(GetAuthority, pv, 2, {a, b, c, d, e});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 2);
......@@ -266,7 +274,7 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST(checker.used_keys().count(e) == 1);
}
{
auto checker = make_auth_checker(GetAuthority, 2, {a, b, c, e});
auto checker = make_auth_checker(GetAuthority, pv, 2, {a, b, c, e});
BOOST_TEST(checker.satisfied(A));
BOOST_TEST(!checker.all_keys_used());
BOOST_TEST(checker.used_keys().size() == 3);
......@@ -275,14 +283,14 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST(checker.used_keys().count(b) == 1);
BOOST_TEST(checker.used_keys().count(c) == 1);
}
BOOST_TEST(make_auth_checker(GetAuthority, 1, {a, b, c}).satisfied(A));
BOOST_TEST(make_auth_checker(GetAuthority, pv, 1, {a, b, c}).satisfied(A));
// Fails due to short recursion depth limit
BOOST_TEST(!make_auth_checker(GetAuthority, 1, {d, e}).satisfied(A));
BOOST_TEST(!make_auth_checker(GetAuthority, pv, 1, {d, e}).satisfied(A));
A = authority(2, {key_weight{c, 1}, key_weight{b, 1}, key_weight{a, 1}});
auto B = authority(1, {key_weight{c, 1}, key_weight{b, 1}});
{
auto checker = make_auth_checker(GetNullAuthority, 2, {a, b, c});
auto checker = make_auth_checker(GetNullAuthority, pv, 2, {a, b, c});
BOOST_TEST(validate(A));
BOOST_TEST(validate(B));
BOOST_TEST(checker.satisfied(A));
......
......@@ -2,12 +2,13 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eos/utilities/key_conversion.hpp>
#include <eos/utilities/rand.hpp>
#include <eos/wallet_plugin/wallet.hpp>
#include <eos/wallet_plugin/wallet_manager.hpp>
#include <eosio/utilities/key_conversion.hpp>
#include <eosio/utilities/rand.hpp>
#include <eosio/wallet_plugin/wallet.hpp>
#include <eosio/wallet_plugin/wallet_manager.hpp>
#include <boost/test/unit_test.hpp>
#include <eosio/chain/authority.hpp>
namespace eosio {
......@@ -35,14 +36,14 @@ BOOST_AUTO_TEST_CASE(wallet_test)
BOOST_CHECK_EQUAL(0, wallet.list_keys().size());
auto priv = fc::ecc::private_key::generate();
auto pub = public_key_type( priv.get_public_key() );
auto wif = key_to_wif(priv.get_secret());
auto priv = fc::crypto::private_key::generate();
auto pub = priv.get_public_key();
auto wif = (std::string)priv;
wallet.import_key(wif);
BOOST_CHECK_EQUAL(1, wallet.list_keys().size());
auto privCopy = wallet.get_private_key(pub);
BOOST_CHECK_EQUAL(wif, privCopy);
BOOST_CHECK_EQUAL(wif, (std::string)privCopy);
wallet.lock();
BOOST_CHECK(wallet.is_locked());
......@@ -61,7 +62,7 @@ BOOST_AUTO_TEST_CASE(wallet_test)
BOOST_CHECK_EQUAL(1, wallet2.list_keys().size());
auto privCopy2 = wallet2.get_private_key(pub);
BOOST_CHECK_EQUAL(wif, privCopy2);
BOOST_CHECK_EQUAL(wif, (std::string)privCopy2);
} FC_LOG_AND_RETHROW() }
/// Test wallet manager
......@@ -98,12 +99,18 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test)
wm.import_key("test", key1);
BOOST_CHECK_EQUAL(1, wm.list_keys().size());
auto keys = wm.list_keys();
#warning TODO: fix check commented out when keys was converted to map<public_key_type,string>
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key1) != keys.cend());
auto pub_pri_pair = [](const char *key) -> auto {
private_key_type prikey = private_key_type(std::string(key));
return std::pair<const public_key_type, private_key_type>(prikey.get_public_key(), prikey);
};
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) != keys.cend());
wm.import_key("test", key2);
keys = wm.list_keys();
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key1) != keys.cend());
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key2) != keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) != keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key2)) != keys.cend());
wm.lock("test");
BOOST_CHECK_EQUAL(0, wm.list_keys().size());
wm.unlock("test", pw);
......@@ -117,34 +124,30 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test)
BOOST_CHECK_EQUAL(0, wm.list_keys().size());
wm.import_key("test2", key3);
keys = wm.list_keys();
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key1) == keys.cend());
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key2) == keys.cend());
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key3) != keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) == keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key2)) == keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key3)) != keys.cend());
wm.unlock("test", pw);
keys = wm.list_keys();
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key1) != keys.cend());
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key2) != keys.cend());
//BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), key3) != keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) != keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key2)) != keys.cend());
BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key3)) != keys.cend());
fc::optional<fc::ecc::private_key> optional_private_key1 = utilities::wif_to_key(key1);
fc::optional<fc::ecc::private_key> optional_private_key2 = utilities::wif_to_key(key2);
fc::optional<fc::ecc::private_key> optional_private_key3 = utilities::wif_to_key(key3);
private_key_type pkey1{std::string(key1)};
private_key_type pkey2{std::string(key2)};
private_key_type pkey3{std::string(key3)};
chain::signed_transaction trx;
name sender("billgates");
name recipient("kevinheifner");
uint64_t amount = 100000000;
trx.scope = {sender,recipient};
transaction_emplace_message(trx,config::eos_contract_name, vector<types::account_permission>{{sender,"active"}}, "transfer",
types::transfer{sender, recipient, amount, "deposit"});
trx = wm.sign_transaction(trx,
{ optional_private_key1->get_public_key(), optional_private_key2->get_public_key(), optional_private_key3->get_public_key()},
chain_id_type{});
flat_set<public_key_type> pubkeys;
pubkeys.emplace(pkey1.get_public_key());
pubkeys.emplace(pkey2.get_public_key());
pubkeys.emplace(pkey3.get_public_key());
trx = wm.sign_transaction(trx, pubkeys, chain_id_type{});
const auto& pks = trx.get_signature_keys(chain_id_type{});
BOOST_CHECK_EQUAL(3, pks.size());
BOOST_CHECK(find(pks.cbegin(), pks.cend(), optional_private_key1->get_public_key()) != pks.cend());
BOOST_CHECK(find(pks.cbegin(), pks.cend(), optional_private_key2->get_public_key()) != pks.cend());
BOOST_CHECK(find(pks.cbegin(), pks.cend(), optional_private_key3->get_public_key()) != pks.cend());
BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey1.get_public_key()) != pks.cend());
BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey2.get_public_key()) != pks.cend());
BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey3.get_public_key()) != pks.cend());
BOOST_CHECK_EQUAL(3, wm.list_keys().size());
wm.set_timeout(chrono::seconds(0));
......
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#include <boost/test/unit_test.hpp>
#pragma GCC diagnostic pop
#include <boost/algorithm/string/predicate.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
......@@ -100,6 +103,29 @@ BOOST_FIXTURE_TEST_CASE( test_transfer, currency_tester ) try {
}
} FC_LOG_AND_RETHROW() /// test_transfer
BOOST_FIXTURE_TEST_CASE( test_duplicate_transfer, currency_tester ) {
create_accounts( {N(alice)} );
auto trace = push_action(N(currency), N(transfer), mutable_variant_object()
("from", "currency")
("to", "alice")
("quantity", "100.0000 CUR")
("memo", "fund Alice")
);
BOOST_CHECK_THROW(push_action(N(currency), N(transfer), mutable_variant_object()
("from", "currency")
("to", "alice")
("quantity", "100.0000 CUR")
("memo", "fund Alice")),
tx_duplicate);
produce_block();
BOOST_CHECK_EQUAL(true, chain_has_transaction(trace.id));
BOOST_CHECK_EQUAL(get_balance(N(alice)), asset::from_string( "100.0000 CUR" ) );
}
BOOST_FIXTURE_TEST_CASE( test_addtransfer, currency_tester ) try {
create_accounts( {N(alice)} );
......@@ -429,8 +455,8 @@ BOOST_FIXTURE_TEST_CASE( test_deferred_failure, currency_tester ) try {
("memo", "fund Proxy")
);
BOOST_REQUIRE_EQUAL(trace.deferred_transactions.size(), 1);
auto deferred_id = trace.deferred_transactions.back().id();
BOOST_REQUIRE_EQUAL(trace.deferred_transaction_requests.size(), 1);
auto deferred_id = trace.deferred_transaction_requests.back().get<deferred_transaction>().id();
while(control->head_block_time() < expected_delivery) {
control->push_deferred_transactions(true);
......
......@@ -99,6 +99,7 @@ public:
("max_inline_depth", 4 + n)
("max_inline_action_size", 4096 + n)
("max_generated_transaction_size", 64*1024 + n)
("max_generated_transaction_count", 10 + n)
("percent_of_max_inflation_rate", 50 + n)
("storage_reserve_ratio", 100 + n);
}
......@@ -1374,7 +1375,8 @@ fc::mutable_variant_object config_to_variant( const eosio::chain::chain_config&
( "max_authority_depth", config.max_authority_depth )
( "max_inline_depth", config.max_inline_depth )
( "max_inline_action_size", config.max_inline_action_size )
( "max_generated_transaction_size", config.max_generated_transaction_size );
( "max_generated_transaction_size", config.max_generated_transaction_size )
( "max_generated_transaction_count", config.max_generated_transaction_count );
}
BOOST_FIXTURE_TEST_CASE( elect_producers_and_parameters, eosio_system_tester ) try {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册