提交 ca9468b4 编写于 作者: A Anton Perkov

Merge branch 'master' into deferred-transactions-3

......@@ -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 ..
......
......@@ -35,15 +35,22 @@
"name": "account",
"base": "",
"fields": [
{"name":"currency", "type":"uint64"},
{"name":"balance", "type":"uint64"}
{"name":"balance", "type":"asset"},
{"name":"frozen", "type":"uint8"},
{"name":"whitelist", "type":"uint8"}
]
},{
"name": "currency_stats",
"base": "",
"fields": [
{"name":"currency", "type":"uint64"},
{"name":"supply", "type":"uint64"}
{"name":"supply", "type":"asset"},
{"name":"max_supply", "type":"asset"},
{"name":"issuer", "type":"account_name"},
{"name":"can_freeze", "type":"uint8"},
{"name":"can_recall", "type":"uint8"},
{"name":"can_whitelist", "type":"uint8"},
{"name":"is_frozen", "type":"uint8"},
{"name":"enforce_whitelist", "type":"uint8"}
]
}
],
......@@ -60,7 +67,7 @@
],
"tables": [{
"name": "account",
"name": "accounts",
"type": "account",
"index_type": "i64",
"key_names" : ["currency"],
......
......@@ -8,11 +8,6 @@
#include "test_multi_index.cpp"
extern "C" {
void init() {
}
void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
WASM_TEST_HANDLER_EX(test_multi_index, idx64_general);
......
......@@ -30,20 +30,22 @@
# https://github.com/EOSIO/eos/blob/master/LICENSE.txt
##########################################################################
VERSION=1.1
VERSION=1.2
ULIMIT=$( ulimit -u )
WORK_DIR=$PWD
BUILD_DIR=${WORK_DIR}/build
TEMP_DIR=/tmp
ARCH=$( uname )
DISK_MIN=20
PYTHON_MIN=3
TIME_BEGIN=$( date -u +%s )
txtbld=$(tput bold)
bldred=${txtbld}$(tput setaf 1)
txtrst=$(tput sgr0)
printf "\n\t$( date -u )\n"
DISK_MIN=20
PYTHON_MIN=3
printf "\n\tBeginning build version: ${VERSION}\n"
printf "\t$( date -u )\n"
printf "\tgit head id: $( cat .git/refs/heads/master )\n"
printf "\tCurrent branch: $( git branch | grep \* )\n"
printf "\n\tARCHITECTURE: ${ARCH}\n"
......@@ -174,7 +176,7 @@
TIME_END=$(( `date -u +%s` - $TIME_BEGIN ))
printf "\t _______ _______ _______ _________ _______\n"
printf "\t _______ _______ _______ _________ _______\n"
printf "\t( ____ \( ___ )( ____ \\__ __/( ___ )\n"
printf "\t| ( \/| ( ) || ( \/ ) ( | ( ) |\n"
printf "\t| (__ | | | || (_____ | | | | | |\n"
......
......@@ -198,7 +198,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) );
......@@ -232,8 +235,12 @@ 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"
......@@ -355,10 +362,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" );
......
......@@ -6,6 +6,7 @@
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <fc/reflect/variant.hpp>
#include <eosio/chain/exceptions.hpp>
namespace eosio { namespace chain {
typedef boost::multiprecision::int128_t int128_t;
......@@ -34,37 +35,46 @@ string asset::to_string()const {
asset asset::from_string(const string& from)
{
try {
try {
asset result;
string s = fc::trim(from);
auto dot_pos = s.find(".");
FC_ASSERT(dot_pos != string::npos, "dot missing in asset from string");
auto space_pos = s.find(" ", dot_pos);
FC_ASSERT(space_pos != string::npos, "space missing in asset from string");
asset result;
auto intpart = s.substr(0, dot_pos);
result.amount = fc::to_int64(intpart);
string symbol_part;
if (dot_pos != string::npos && space_pos != string::npos) {
symbol_part = eosio::chain::to_string(space_pos - dot_pos - 1);
symbol_part += ',';
symbol_part += s.substr(space_pos + 1);
// Find space in order to split amount and symbol
auto space_pos = s.find(' ');
EOS_ASSERT((space_pos != string::npos), asset_type_exception, "Asset's amount and symbol should be separated with space");
auto symbol_str = fc::trim(s.substr(space_pos + 1));
auto amount_str = s.substr(0, space_pos);
// Ensure that if decimal point is used (.), decimal fraction is specified
auto dot_pos = amount_str.find('.');
if (dot_pos != string::npos) {
EOS_ASSERT((dot_pos != amount_str.size() - 1), asset_type_exception, "Missing decimal fraction after decimal point");
}
// Parse symbol
string precision_digit_str;
if (dot_pos != string::npos) {
precision_digit_str = eosio::chain::to_string(amount_str.size() - dot_pos - 1);
} else {
precision_digit_str = "0";
}
string symbol_part = precision_digit_str + ',' + symbol_str;
result.sym = symbol::from_string(symbol_part);
// Parse amount
int64_t int_part, fract_part = 0;
if (dot_pos != string::npos) {
auto fractpart = "1" + s.substr(dot_pos + 1, space_pos - dot_pos - 1);
result.amount *= int64_t(result.precision());
if ( intpart[0] == '-' ) {
result.amount -= int64_t(fc::to_int64(fractpart));
result.amount += int64_t(result.precision());
} else {
result.amount += int64_t(fc::to_int64(fractpart));
result.amount -= int64_t(result.precision());
}
int_part = fc::to_int64(amount_str.substr(0, dot_pos));
fract_part = fc::to_int64(amount_str.substr(dot_pos + 1));
if (amount_str[0] == '-') fract_part *= -1;
} else {
int_part = fc::to_int64(amount_str);
}
result.amount = int_part;
result.amount *= int64_t(result.precision());
result.amount += fract_part;
return result;
}
FC_CAPTURE_LOG_AND_RETHROW( (from) )
......
......@@ -18,6 +18,7 @@
#include <eosio/chain/scope_sequence_object.hpp>
#include <eosio/chain/merkle.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wasm_interface.hpp>
#include <eosio/utilities/rand.hpp>
......@@ -260,20 +261,57 @@ transaction_trace chain_controller::push_transaction(const packed_transaction& t
return _push_transaction(trx);
});
});
} FC_CAPTURE_AND_RETHROW() }
} EOS_CAPTURE_AND_RETHROW( transaction_exception ) }
transaction_trace chain_controller::_push_transaction(const packed_transaction& trx)
transaction_trace chain_controller::_push_transaction(const packed_transaction& packed_trx)
{ try {
transaction_metadata mtrx( trx, get_chain_id(), head_block_time());
transaction_metadata mtrx( packed_trx, get_chain_id(), head_block_time());
const auto delay = check_transaction_authorization(mtrx.trx(), packed_trx.signatures, packed_trx.context_free_data);
transaction_trace result(mtrx.id);
if (!delay.sec_since_epoch()) {
result = _push_transaction(std::move(mtrx));
// notify anyone listening to pending transactions
on_pending_transaction(_pending_transaction_metas.back(), packed_trx);
_pending_block->input_transactions.emplace_back(packed_trx);
} else {
result.status = transaction_trace::delayed;
const auto trx = mtrx.trx();
FC_ASSERT( !trx.actions.empty(), "transaction must have at least one action");
FC_ASSERT( trx.expiration > (head_block_time() + fc::milliseconds(2*config::block_interval_ms)),
"transaction is expired when created" );
// add in the system account authorization
action for_deferred = trx.actions[0];
bool found = false;
for (const auto& auth : for_deferred.authorization) {
if (auth.actor == config::system_account_name &&
auth.permission == config::active_name) {
found = true;
break;
}
}
if (!found)
for_deferred.authorization.push_back(permission_level{config::system_account_name, config::active_name});
check_transaction_authorization(mtrx.trx(), trx.signatures);
auto result = _push_transaction(std::move(mtrx));
apply_context context(*this, _db, for_deferred, mtrx);
// notify anyone listening to pending transactions
on_pending_transaction(_pending_transaction_metas.back(), trx);
time_point_sec execute_after = head_block_time();
execute_after += time_point_sec(delay);
deferred_transaction dtrx(context.get_next_sender_id(), config::system_account_name, execute_after, trx);
FC_ASSERT( dtrx.execute_after < dtrx.expiration, "transaction expires before it can execute" );
_pending_block->input_transactions.emplace_back(trx);
result.deferred_transaction_requests.push_back(std::move(dtrx));
// notify anyone listening to pending transactions
on_pending_transaction(std::move(mtrx), packed_trx);
store_deferred_transaction(result.deferred_transaction_requests[0].get<deferred_transaction>());
}
return result;
} FC_CAPTURE_AND_RETHROW() }
......@@ -426,6 +464,21 @@ void chain_controller::_finalize_pending_cycle()
_pending_cycle_trace.reset();
}
void chain_controller::store_deferred_transaction(const deferred_transaction& dtrx)
{
_db.create<generated_transaction_object>([&](generated_transaction_object &obj) {
obj.trx_id = dtrx.id();
obj.sender = dtrx.sender;
obj.sender_id = dtrx.sender_id;
obj.expiration = dtrx.expiration;
obj.delay_until = dtrx.execute_after;
obj.published = head_block_time();
obj.packed_trx.resize(fc::raw::pack_size(dtrx));
fc::datastream<char *> ds(obj.packed_trx.data(), obj.packed_trx.size());
fc::raw::pack(ds, dtrx);
});
}
void chain_controller::_apply_cycle_trace( const cycle_trace& res )
{
auto &generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
......@@ -447,17 +500,7 @@ void chain_controller::_apply_cycle_trace( const cycle_trace& res )
fc::raw::pack(ds, dt);
});
} else {
_db.create<generated_transaction_object>([&](generated_transaction_object &obj) {
obj.trx_id = dt.id();
obj.sender = dt.sender;
obj.sender_id = dt.sender_id;
obj.expiration = dt.expiration;
obj.delay_until = dt.execute_after;
obj.published = head_block_time();
obj.packed_trx.resize(fc::raw::pack_size(dt));
fc::datastream<char *> ds(obj.packed_trx.data(), obj.packed_trx.size());
fc::raw::pack(ds, dt);
});
store_deferred_transaction(dt);
}
} else if ( req.contains<deferred_reference>() ) {
const auto& dr = req.get<deferred_reference>();
......@@ -797,6 +840,7 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction&
const flat_set<public_key_type>& candidate_keys)const
{
auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
[](const permission_level& ) {},
get_global_properties().configuration.max_authority_depth,
candidate_keys);
......@@ -813,63 +857,154 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction&
return checker.used_keys();
}
void chain_controller::check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures,
flat_set<account_name> provided_accounts )const
class permission_visitor {
public:
permission_visitor(const chain_controller& controller) : _chain_controller(controller) {}
void operator()(const permission_level& perm_level) {
const auto obj = _chain_controller.get_permission(perm_level);
if (_max_delay < obj.delay)
_max_delay = obj.delay;
}
const time_point& get_max_delay() const { return _max_delay; }
private:
const chain_controller& _chain_controller;
time_point _max_delay;
};
time_point chain_controller::check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures,
flat_set<account_name> provided_accounts )const
{
auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
permission_visitor(*this),
get_global_properties().configuration.max_authority_depth,
provided_keys, provided_accounts );
time_point max_delay;
for( const auto& act : actions ) {
for( const auto& declared_auth : act.authorization ) {
// check a minimum permission if one is set, otherwise assume the contract code will validate
auto min_permission_name = lookup_minimum_permission(declared_auth.actor, act.account, act.name);
bool min_permission_required = true;
if (!min_permission_name) {
// for updateauth actions, need to determine the permission that is changing
if (act.account == config::system_account_name && act.name == contracts::updateauth::get_name()) {
auto update = act.data_as<contracts::updateauth>();
const auto permission_to_change = _db.find<permission_object, by_owner>(boost::make_tuple(update.account, update.permission));
if (permission_to_change != nullptr) {
// only determining delay
min_permission_required = false;
min_permission_name = update.permission;
}
}
}
if (min_permission_name) {
const auto& min_permission = _db.get<permission_object, by_owner>(boost::make_tuple(declared_auth.actor, *min_permission_name));
if ((_skip_flags & skip_authority_check) == false) {
const auto &index = _db.get_index<permission_index>().indices();
EOS_ASSERT(get_permission(declared_auth).satisfies(min_permission, index),
const auto& index = _db.get_index<permission_index>().indices();
const optional<time_point> delay = get_permission(declared_auth).satisfies(min_permission, index);
EOS_ASSERT(!min_permission_required || delay.valid(),
tx_irrelevant_auth,
"action declares irrelevant authority '${auth}'; minimum authority is ${min}",
("auth", declared_auth)("min", min_permission.name));
if (max_delay < *delay)
max_delay = *delay;
}
}
if (act.account == config::system_account_name) {
// for link changes, we need to also determine the delay associated with an existing link that is being
// moved or removed
if (act.name == contracts::linkauth::get_name()) {
auto link = act.data_as<contracts::linkauth>();
if (declared_auth.actor == link.account) {
const auto linked_permission_name = lookup_linked_permission(link.account, link.code, link.type);
if (linked_permission_name.valid()) {
const auto& linked_permission = _db.get<permission_object, by_owner>(boost::make_tuple(link.account, *linked_permission_name));
const auto& index = _db.get_index<permission_index>().indices();
const optional<time_point> delay = get_permission(declared_auth).satisfies(linked_permission, index);
if (delay.valid() && max_delay < *delay)
max_delay = *delay;
} // else it is only a new link, so don't need to delay
}
} else if (act.name == contracts::unlinkauth::get_name()) {
auto unlink = act.data_as<contracts::unlinkauth>();
if (declared_auth.actor == unlink.account) {
const auto unlinked_permission_name = lookup_linked_permission(unlink.account, unlink.code, unlink.type);
if (unlinked_permission_name.valid()) {
const auto& unlinked_permission = _db.get<permission_object, by_owner>(boost::make_tuple(unlink.account, *unlinked_permission_name));
const auto& index = _db.get_index<permission_index>().indices();
const optional<time_point> delay = get_permission(declared_auth).satisfies(unlinked_permission, index);
if (delay.valid() && max_delay < *delay)
max_delay = *delay;
}
}
}
}
if ((_skip_flags & skip_transaction_signatures) == false) {
EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
"transaction declares authority '${auth}', but does not have signatures for it.",
("auth", declared_auth));
}
}
if (act.account == config::system_account_name && act.name == contracts::mindelay::get_name()) {
const auto mindelay = act.data_as<contracts::mindelay>();
const time_point delay = time_point_sec{mindelay.delay.convert_to<uint32_t>()};
if (max_delay < delay)
max_delay = delay;
}
}
if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
"transaction bears irrelevant signatures from these keys: ${keys}",
("keys", checker.unused_keys()));
const auto checker_max_delay = checker.get_permission_visitor().get_max_delay();
if (max_delay < checker_max_delay)
max_delay = checker_max_delay;
return max_delay;
}
void chain_controller::check_transaction_authorization(const transaction& trx,
const vector<signature_type>& signatures,
bool allow_unused_signatures)const
time_point chain_controller::check_transaction_authorization(const transaction& trx,
const vector<signature_type>& signatures,
const vector<bytes>& cfd,
bool allow_unused_signatures)const
{
check_authorization( trx.actions, trx.get_signature_keys( signatures, chain_id_type{} ), allow_unused_signatures );
return check_authorization( trx.actions, trx.get_signature_keys( signatures, chain_id_type{}, cfd ), allow_unused_signatures );
}
optional<permission_name> chain_controller::lookup_minimum_permission(account_name authorizer_account,
account_name scope,
action_name act_name) const {
#warning TODO: this comment sounds like it is expecting a check ("may") somewhere else, but I have not found anything else
// updateauth is a special case where any permission _may_ be suitable depending
// on the contents of the action
if (scope == config::system_account_name && act_name == N(updateauth)) {
if (scope == config::system_account_name && act_name == contracts::updateauth::get_name()) {
return optional<permission_name>();
}
try {
optional<permission_name> linked_permission = lookup_linked_permission(authorizer_account, scope, act_name);
if (!linked_permission)
return config::active_name;
return linked_permission;
} FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
}
optional<permission_name> chain_controller::lookup_linked_permission(account_name authorizer_account,
account_name scope,
action_name act_name) const {
try {
// First look up a specific link for this message act_name
auto key = boost::make_tuple(authorizer_account, scope, act_name);
......@@ -883,8 +1018,8 @@ optional<permission_name> chain_controller::lookup_minimum_permission(account_na
// If no specific or default link found, use active permission
if (link != nullptr)
return link->required_permission;
else
return N(active);
return optional<permission_name>();
} FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
}
......@@ -892,7 +1027,7 @@ void chain_controller::validate_uniqueness( const transaction& trx )const {
if( !should_check_for_duplicate_transactions() ) return;
auto transaction = _db.find<transaction_object, by_trx_id>(trx.id());
EOS_ASSERT(transaction == nullptr, tx_duplicate, "transaction is not unique");
EOS_ASSERT(transaction == nullptr, tx_duplicate, "Transaction is not unique");
}
void chain_controller::record_transaction(const transaction& trx)
......@@ -916,8 +1051,8 @@ void chain_controller::validate_tapos(const transaction& trx)const {
const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), transaction_exception,
"transaction's reference block did not match. Is this transaction from a different fork?",
EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
"Transaction's reference block did not match. Is this transaction from a different fork?",
("tapos_summary", tapos_block_summary));
}
......@@ -936,10 +1071,10 @@ void chain_controller::validate_expiration( const transaction& trx ) const
const auto& chain_configuration = get_global_properties().configuration;
EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
transaction_exception, "transaction expiration is too far in the future",
tx_exp_too_far_exception, "Transaction expiration is too far in the future, expiration is ${trx.expiration} but max expiration is ${max_til_exp}",
("trx.expiration",trx.expiration)("now",now)
("max_til_exp",chain_configuration.max_transaction_lifetime));
EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
EOS_ASSERT( now <= time_point(trx.expiration), expired_tx_exception, "Transaction is expired, now is ${now}, expiration is ${trx.exp}",
("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
......@@ -1113,7 +1248,7 @@ const producer_object& chain_controller::get_producer(const account_name& owner_
const permission_object& chain_controller::get_permission( const permission_level& level )const
{ try {
return _db.get<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
} FC_CAPTURE_AND_RETHROW( (level) ) }
} EOS_RETHROW_EXCEPTIONS( chain::permission_query_exception, "Fail to retrieve permission: ${level}", ("level", level) ) }
uint32_t chain_controller::last_irreversible_block_num() const {
return get_dynamic_global_properties().last_irreversible_block_num;
......@@ -1643,7 +1778,7 @@ vector<transaction_trace> chain_controller::_push_deferred_transactions( bool fl
auto& generated_index = generated_transaction_idx.indices().get<by_delay>();
vector<const generated_transaction_object*> candidates;
for( auto itr = generated_index.rbegin(); itr != generated_index.rend() && (head_block_time() >= itr->delay_until); ++itr) {
for( auto itr = generated_index.begin(); itr != generated_index.end() && (head_block_time() >= itr->delay_until); ++itr) {
const auto &gtrx = *itr;
candidates.emplace_back(&gtrx);
}
......
......@@ -59,6 +59,7 @@ namespace eosio { namespace chain { namespace contracts {
//symbol.hpp
built_in_types.emplace("symbol", pack_unpack<symbol>());
built_in_types.emplace("symbol_code", pack_unpack<symbol_code>());
//asset.hpp
built_in_types.emplace("asset", pack_unpack<asset>());
......@@ -102,7 +103,7 @@ namespace eosio { namespace chain { namespace contracts {
for( const auto& st : abi.structs )
structs[st.name] = st;
for( const auto& td : abi.types ) {
FC_ASSERT(is_type(td.type), "invalid type", ("type",td.type));
typedefs[td.new_type_name] = td.type;
......@@ -140,9 +141,9 @@ namespace eosio { namespace chain { namespace contracts {
return boost::lexical_cast<int>(stype.substr(4));
} else {
return boost::lexical_cast<int>(stype.substr(3));
}
}
}
bool abi_serializer::is_struct(const type_name& type)const {
return structs.find(resolve_type(type)) != structs.end();
}
......@@ -256,7 +257,7 @@ namespace eosio { namespace chain { namespace contracts {
fc::raw::unpack(stream, flag);
return flag ? binary_to_variant(ftype, stream) : fc::variant();
}
fc::mutable_variant_object mvo;
binary_to_variant(rtype, stream, mvo);
return fc::variant( std::move(mvo) );
......@@ -293,7 +294,7 @@ namespace eosio { namespace chain { namespace contracts {
}
else {
/// TODO: default construct field and write it out
FC_ASSERT( !"missing field in variant object", "Missing '${f}' in variant object", ("f",field.name) );
FC_THROW( "Missing '${f}' in variant object", ("f",field.name) );
}
}
}
......@@ -322,4 +323,4 @@ namespace eosio { namespace chain { namespace contracts {
return type_name();
}
} } }
} } }
......@@ -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>
......@@ -199,6 +200,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
......@@ -209,6 +211,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>());
});
}
}
......@@ -246,9 +249,15 @@ void apply_eosio_linkauth(apply_context& context) {
context.require_authorization(requirement.account);
auto& db = context.mutable_db;
db.get<account_object, by_name>(requirement.account);
db.get<account_object, by_name>(requirement.code);
db.get<permission_object, by_name>(requirement.requirement);
const auto *account = db.find<account_object, by_name>(requirement.account);
EOS_ASSERT(account != nullptr, account_query_exception,
"Fail to retrieve account: ${account}", ("account", requirement.account));
const auto *code = db.find<account_object, by_name>(requirement.code);
EOS_ASSERT(code != nullptr, account_query_exception,
"Fail to retrieve code for account: ${account}", ("account", requirement.code));
const auto *permission = db.find<permission_object, by_name>(requirement.requirement);
EOS_ASSERT(permission != nullptr, permission_query_exception,
"Fail to retrieve permission: ${permission}", ("permission", requirement.requirement));
auto link_key = boost::make_tuple(requirement.account, requirement.code, requirement.type);
auto link = db.find<permission_link_object, by_action_name>(link_key);
......@@ -313,24 +322,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;
......@@ -393,7 +384,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)
......@@ -473,5 +464,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
......@@ -504,6 +504,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
......@@ -585,6 +587,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
......
......@@ -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
......@@ -283,13 +283,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 );
......
......@@ -6,7 +6,7 @@
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/transaction.hpp>
#include <eosio/chain/block.hpp>
#include <eosio/chain/exceptions.hpp>
#include <fc/variant_object.hpp>
namespace eosio { namespace chain { namespace contracts {
......@@ -309,8 +309,8 @@ namespace impl {
static void extract( const variant& v, action& act, Resolver resolver )
{
const variant_object& vo = v.get_object();
FC_ASSERT(vo.contains("account"));
FC_ASSERT(vo.contains("name"));
EOS_ASSERT(vo.contains("account"), packed_transaction_type_exception, "Missing account");
EOS_ASSERT(vo.contains("name"), packed_transaction_type_exception, "Missing name");
from_variant(vo["account"], act.account);
from_variant(vo["name"], act.name);
......@@ -340,14 +340,15 @@ namespace impl {
}
}
FC_ASSERT(!act.data.empty(), "Failed to deserialize data for ${account}:${name}", ("account", act.account)("name", act.name));
EOS_ASSERT(!act.data.empty(), packed_transaction_type_exception,
"Failed to deserialize data for ${account}:${name}", ("account", act.account)("name", act.name));
}
template<typename Resolver>
static void extract( const variant& v, packed_transaction& ptrx, Resolver resolver ) {
const variant_object& vo = v.get_object();
FC_ASSERT(vo.contains("signatures"));
FC_ASSERT(vo.contains("compression"));
EOS_ASSERT(vo.contains("signatures"), packed_transaction_type_exception, "Missing signatures");
EOS_ASSERT(vo.contains("compression"), packed_transaction_type_exception, "Missing compression");
from_variant(vo["signatures"], ptrx.signatures);
if ( vo.contains("context_free_data")) {
from_variant(vo["context_free_data"], ptrx.context_free_data);
......@@ -357,7 +358,7 @@ namespace impl {
if (vo.contains("hex_data") && vo["hex_data"].is_string() && !vo["hex_data"].as_string().empty()) {
from_variant(vo["hex_data"], ptrx.data);
} else {
FC_ASSERT(vo.contains("data"));
EOS_ASSERT(vo.contains("data"), packed_transaction_type_exception, "Missing data");
if (vo["data"].is_string()) {
from_variant(vo["data"], ptrx.data);
} else {
......
......@@ -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
......@@ -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) )
......@@ -22,8 +22,12 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( unknown_block_exception, eosio::chain::chain_exception, 3110000, "unknown block" )
FC_DECLARE_DERIVED_EXCEPTION( chain_type_exception, eosio::chain::chain_exception, 3120000, "chain type exception" )
FC_DECLARE_DERIVED_EXCEPTION( missing_plugin_exception, eosio::chain::chain_exception, 3130000, "missing plugin exception" )
FC_DECLARE_DERIVED_EXCEPTION( wallet_exception, eosio::chain::chain_exception, 3140000, "wallet exception" )
FC_DECLARE_DERIVED_EXCEPTION( permission_query_exception, eosio::chain::database_query_exception, 3010001, "permission query exception" )
FC_DECLARE_DERIVED_EXCEPTION( permission_query_exception, eosio::chain::database_query_exception, 3010001, "Permission Query Exception" )
FC_DECLARE_DERIVED_EXCEPTION( account_query_exception, eosio::chain::database_query_exception, 3010002, "Account Query Exception" )
FC_DECLARE_DERIVED_EXCEPTION( contract_table_query_exception, eosio::chain::database_query_exception, 3010003, "Contract Table Query Exception" )
FC_DECLARE_DERIVED_EXCEPTION( contract_query_exception, eosio::chain::database_query_exception, 3010004, "Contract Query Exception" )
FC_DECLARE_DERIVED_EXCEPTION( block_tx_output_exception, eosio::chain::block_validate_exception, 3020001, "transaction outputs in block do not match transaction outputs from applying block" )
FC_DECLARE_DERIVED_EXCEPTION( block_concurrency_exception, eosio::chain::block_validate_exception, 3020002, "block does not guarantee concurrent exection without conflicts" )
......@@ -48,9 +52,14 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( tx_msgs_auth_exceeded, eosio::chain::transaction_exception, 3030018, "Number of transaction messages per authorized account has been exceeded" )
FC_DECLARE_DERIVED_EXCEPTION( tx_msgs_code_exceeded, eosio::chain::transaction_exception, 3030019, "Number of transaction messages per code account has been exceeded" )
FC_DECLARE_DERIVED_EXCEPTION( wasm_execution_error, eosio::chain::transaction_exception, 3030020, "Runtime Error Processing WASM" )
FC_DECLARE_DERIVED_EXCEPTION( tx_decompression_error, eosio::chain::transaction_exception, 3030020, "Error decompressing transaction" )
FC_DECLARE_DERIVED_EXCEPTION( tx_decompression_error, eosio::chain::transaction_exception, 3030021, "Error decompressing transaction" )
FC_DECLARE_DERIVED_EXCEPTION( expired_tx_exception, eosio::chain::transaction_exception, 3030022, "Expired Transaction" )
FC_DECLARE_DERIVED_EXCEPTION( tx_exp_too_far_exception, eosio::chain::transaction_exception, 3030023, "Transaction Expiration Too Far" )
FC_DECLARE_DERIVED_EXCEPTION( invalid_ref_block_exception, eosio::chain::transaction_exception, 3030024, "Invalid Reference Block" )
FC_DECLARE_DERIVED_EXCEPTION( tx_apply_exception, eosio::chain::transaction_exception, 3030025, "Transaction Apply Exception" )
FC_DECLARE_DERIVED_EXCEPTION( account_name_exists_exception, eosio::chain::action_validate_exception, 3040001, "account name already exists" )
FC_DECLARE_DERIVED_EXCEPTION( invalid_action_args_exception, eosio::chain::action_validate_exception, 3040002, "Invalid Action Arguments" )
FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, eosio::chain::utility_exception, 3060001, "invalid pts address" )
FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, eosio::chain::chain_exception, 37006, "insufficient feeds" )
......@@ -58,15 +67,26 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( name_type_exception, eosio::chain::chain_type_exception, 3120001, "Invalid name" )
FC_DECLARE_DERIVED_EXCEPTION( public_key_type_exception, eosio::chain::chain_type_exception, 3120002, "Invalid public key" )
FC_DECLARE_DERIVED_EXCEPTION( authority_type_exception, eosio::chain::chain_type_exception, 3120003, "Invalid authority" )
FC_DECLARE_DERIVED_EXCEPTION( action_type_exception, eosio::chain::chain_type_exception, 3120004, "Invalid action" )
FC_DECLARE_DERIVED_EXCEPTION( transaction_type_exception, eosio::chain::chain_type_exception, 3120005, "Invalid transaction" )
FC_DECLARE_DERIVED_EXCEPTION( abi_type_exception, eosio::chain::chain_type_exception, 3120006, "Invalid ABI" )
FC_DECLARE_DERIVED_EXCEPTION( private_key_type_exception, eosio::chain::chain_type_exception, 3120003, "Invalid private key" )
FC_DECLARE_DERIVED_EXCEPTION( authority_type_exception, eosio::chain::chain_type_exception, 3120004, "Invalid authority" )
FC_DECLARE_DERIVED_EXCEPTION( action_type_exception, eosio::chain::chain_type_exception, 3120005, "Invalid action" )
FC_DECLARE_DERIVED_EXCEPTION( transaction_type_exception, eosio::chain::chain_type_exception, 3120006, "Invalid transaction" )
FC_DECLARE_DERIVED_EXCEPTION( abi_type_exception, eosio::chain::chain_type_exception, 3120007, "Invalid ABI" )
FC_DECLARE_DERIVED_EXCEPTION( block_id_type_exception, eosio::chain::chain_type_exception, 3120008, "Invalid block ID" )
FC_DECLARE_DERIVED_EXCEPTION( transaction_id_type_exception, eosio::chain::chain_type_exception, 3120009, "Invalid transaction ID" )
FC_DECLARE_DERIVED_EXCEPTION( packed_transaction_type_exception, eosio::chain::chain_type_exception, 3120010, "Invalid packed transaction" )
FC_DECLARE_DERIVED_EXCEPTION( asset_type_exception, eosio::chain::chain_type_exception, 3120011, "Invalid asset" )
FC_DECLARE_DERIVED_EXCEPTION( missing_chain_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130001, "Missing Chain API Plugin" )
FC_DECLARE_DERIVED_EXCEPTION( missing_wallet_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130002, "Missing Wallet API Plugin" )
FC_DECLARE_DERIVED_EXCEPTION( missing_account_history_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130003, "Missing Account History API Plugin" )
FC_DECLARE_DERIVED_EXCEPTION( missing_net_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130003, "Missing Net API Plugin" )
FC_DECLARE_DERIVED_EXCEPTION( missing_net_api_plugin_exception, eosio::chain::missing_plugin_exception, 3130004, "Missing Net API Plugin" )
FC_DECLARE_DERIVED_EXCEPTION( wallet_exist_exception, eosio::chain::wallet_exception, 3140001, "Wallet already exists" )
FC_DECLARE_DERIVED_EXCEPTION( wallet_nonexistent_exception, eosio::chain::wallet_exception, 3140002, "Nonexistent wallet" )
FC_DECLARE_DERIVED_EXCEPTION( wallet_locked_exception, eosio::chain::wallet_exception, 3140003, "Locked wallet" )
FC_DECLARE_DERIVED_EXCEPTION( wallet_missing_pub_key_exception, eosio::chain::wallet_exception, 3140004, "Missing public key" )
FC_DECLARE_DERIVED_EXCEPTION( wallet_invalid_password_exception, eosio::chain::wallet_exception, 3140005, "Invalid wallet password" )
#define EOS_RECODE_EXC( cause_type, effect_type ) \
......
......@@ -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))
......@@ -19,11 +19,11 @@ namespace eosio {
from_string constructs a symbol from an input a string of the form "4,EOS"
where the integer represents number of decimals. Number of decimals must be larger than zero.
*/
static constexpr uint64_t string_to_symbol_c(uint8_t precision, const char* str) {
uint32_t len = 0;
while (str[len]) ++len;
uint64_t result = 0;
// No validation is done at compile time
for (uint32_t i = 0; i < len; ++i) {
......@@ -33,7 +33,7 @@ namespace eosio {
result |= uint64_t(precision);
return result;
}
#define SY(P,X) ::eosio::chain::string_to_symbol_c(P,#X)
static uint64_t string_to_symbol(uint8_t precision, const char* str) {
......@@ -42,7 +42,7 @@ namespace eosio {
while(str[len]) ++len;
uint64_t result = 0;
for (uint32_t i = 0; i < len; ++i) {
// All characters must be upper case alaphabets
// All characters must be upper case alphabets
FC_ASSERT (str[i] >= 'A' && str[i] <= 'Z', "invalid character in symbol name");
result |= (uint64_t(str[i]) << (8*(i+1)));
}
......@@ -51,6 +51,10 @@ namespace eosio {
} FC_CAPTURE_LOG_AND_RETHROW((str))
}
struct symbol_code {
uint64_t value;
};
class symbol {
public:
explicit symbol(uint8_t p, const char* s): m_value(string_to_symbol(p, s)) { }
......@@ -64,7 +68,6 @@ namespace eosio {
FC_ASSERT(comma_pos != string::npos, "missing comma in symbol");
auto prec_part = s.substr(0, comma_pos);
uint8_t p = fc::to_int64(prec_part);
FC_ASSERT(p > 0, "zero decimals in symbol");
string name_part = s.substr(comma_pos + 1);
return symbol(string_to_symbol(p, name_part.c_str()));
} FC_CAPTURE_LOG_AND_RETHROW((from))
......@@ -72,7 +75,6 @@ namespace eosio {
uint64_t value() const { return m_value; }
bool valid() const
{
if (decimals() == 0) return false;
const auto& s = name();
return valid_name(s);
}
......@@ -105,7 +107,9 @@ namespace eosio {
}
return result;
}
symbol_code to_symbol_code()const { return {m_value >> 8}; }
explicit operator string() const
{
uint64_t v = m_value;
......@@ -122,7 +126,7 @@ namespace eosio {
{
return ds << s.to_string();
}
private:
uint64_t m_value;
friend struct fc::reflector<symbol>;
......@@ -150,7 +154,7 @@ namespace eosio {
return lhs.value() > rhs.value();
}
} // namespace chain
} // namespace chain
} // namespace eosio
namespace fc {
......@@ -160,5 +164,15 @@ namespace fc {
}
}
namespace fc {
inline void to_variant(const eosio::chain::symbol_code& var, fc::variant& vo) {
vo = eosio::chain::symbol(var.value << 8).name();
}
inline void from_variant(const fc::variant& var, eosio::chain::symbol_code& vo) {
vo = eosio::chain::symbol(0, var.get_string().c_str()).to_symbol_code();
}
}
FC_REFLECT(eosio::chain::symbol_code, (value))
FC_REFLECT(eosio::chain::symbol, (m_value))
FC_REFLECT(eosio::chain::extended_symbol, (sym)(contract))
......@@ -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 {
uint128_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 {
......@@ -270,7 +280,7 @@ 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_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;
......
......@@ -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);
......@@ -191,7 +193,7 @@ namespace eosio { namespace testing {
:expected(expected)
{}
bool operator()( const fc::assert_exception& ex ) {
bool operator()( const fc::exception& ex ) {
auto message = ex.get_log().at(0).get_message();
return boost::algorithm::ends_with(message, expected);
}
......
......@@ -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;
......
......@@ -8,15 +8,54 @@
FC_THROW_EXCEPTION( exc_type, FORMAT, __VA_ARGS__ ); \
FC_MULTILINE_MACRO_END
#define EOS_CAPTURE_AND_RETHROW(exc_type, FORMAT, ... ) \
catch (fc::exception& e) { \
exc_type new_exception(FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ )); \
#define EOS_THROW( exc_type, FORMAT, ... ) \
throw exc_type( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) );
/**
* Macro inspired from FC_RETHROW_EXCEPTIONS
* The main difference here is that if the exception caught isn't of type "eosio::chain::chain_exception"
* This macro will rethrow the exception as the specified "exception_type"
*/
#define EOS_RETHROW_EXCEPTIONS(exception_type, FORMAT, ... ) \
catch (eosio::chain::chain_exception& e) { \
FC_RETHROW_EXCEPTION( e, warn, FORMAT, __VA_ARGS__ ); \
} catch (fc::exception& e) { \
exception_type new_exception(FC_LOG_MESSAGE( warn, FORMAT, __VA_ARGS__ )); \
for (const auto& log: e.get_log()) { \
new_exception.append_log(log); \
} \
throw new_exception; \
}
} catch( const std::exception& e ) { \
exception_type fce(FC_LOG_MESSAGE( warn, FORMAT" (${what})" ,__VA_ARGS__("what",e.what()))); \
throw fce;\
} catch( ... ) { \
throw fc::unhandled_exception( \
FC_LOG_MESSAGE( warn, FORMAT,__VA_ARGS__), \
std::current_exception() ); \
}
/**
* Macro inspired from FC_CAPTURE_AND_RETHROW
* The main difference here is that if the exception caught isn't of type "eosio::chain::chain_exception"
* This macro will rethrow the exception as the specified "exception_type"
*/
#define EOS_CAPTURE_AND_RETHROW( exception_type, ... ) \
catch (eosio::chain::chain_exception& e) { \
FC_RETHROW_EXCEPTION( e, warn, "", FC_FORMAT_ARG_PARAMS(__VA_ARGS__) ); \
} catch (fc::exception& e) { \
exception_type new_exception(e.get_log()); \
throw new_exception; \
} catch( const std::exception& e ) { \
exception_type fce( \
FC_LOG_MESSAGE( warn, "${what}: ",FC_FORMAT_ARG_PARAMS(__VA_ARGS__)("what",e.what())), \
fc::std_exception_code,\
BOOST_CORE_TYPEID(decltype(e)).name(), \
e.what() ) ; throw fce;\
} catch( ... ) { \
throw fc::unhandled_exception( \
FC_LOG_MESSAGE( warn, "",FC_FORMAT_ARG_PARAMS(__VA_ARGS__)), \
std::current_exception() ); \
}
#define EOS_DECLARE_OP_BASE_EXCEPTIONS( op_name ) \
FC_DECLARE_DERIVED_EXCEPTION( \
......
......@@ -287,11 +287,11 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params
}
abi_def get_abi( const chain_controller& db, const name& account ) {
const auto& d = db.get_database();
const auto& code_accnt = d.get<account_object,by_name>( account );
const auto &d = db.get_database();
const account_object *code_accnt = d.find<account_object, by_name>(account);
EOS_ASSERT(code_accnt != nullptr, chain::account_query_exception, "Fail to retrieve account for ${account}", ("account", account) );
abi_def abi;
abi_serializer::to_abi(code_accnt.abi, abi);
abi_serializer::to_abi(code_accnt->abi, abi);
return abi;
}
......@@ -301,7 +301,7 @@ string get_table_type( const abi_def& abi, const name& table_name ) {
return t.index_type;
}
}
FC_ASSERT( !"ABI does not define table", "Table ${table} not specified in ABI", ("table",table_name) );
EOS_ASSERT( false, chain::contract_table_query_exception, "Table ${table} is not specified in the ABI", ("table",table_name) );
}
read_only::get_table_rows_result read_only::get_table_rows( const read_only::get_table_rows_params& p )const {
......@@ -311,7 +311,8 @@ read_only::get_table_rows_result read_only::get_table_rows( const read_only::get
if( table_type == KEYi64 ) {
return get_table_rows_ex<contracts::key_value_index, contracts::by_scope_primary>(p,abi);
}
FC_ASSERT( false, "invalid table type/key ${type}/${key}", ("type",table_type)("abi",abi));
EOS_ASSERT( false, chain::contract_table_query_exception, "Invalid table type ${type}", ("type",table_type)("abi",abi));
}
vector<asset> read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const {
......@@ -380,7 +381,7 @@ fc::variant read_only::get_block(const read_only::get_block_params& params) cons
block = db.fetch_block_by_number(fc::to_uint64(params.block_num_or_id));
}
} catch (fc::bad_cast_exception) {/* do nothing */}
} EOS_RETHROW_EXCEPTIONS(chain::block_id_type_exception, "Invalid block ID: ${block_num_or_id}", ("block_num_or_id", params.block_num_or_id))
if (!block)
FC_THROW_EXCEPTION(unknown_block_exception,
......@@ -405,7 +406,10 @@ read_write::push_block_results read_write::push_block(const read_write::push_blo
read_write::push_transaction_results read_write::push_transaction(const read_write::push_transaction_params& params) {
packed_transaction pretty_input;
auto resolver = make_resolver(this);
abi_serializer::from_variant(params, pretty_input, resolver);
try {
abi_serializer::from_variant(params, pretty_input, resolver);
} EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")
auto result = db.push_transaction(pretty_input, skip_flags);
#warning TODO: get transaction results asynchronously
fc::variant pretty_output;
......@@ -481,11 +485,17 @@ read_only::get_account_results read_only::get_account( const get_account_params&
read_only::abi_json_to_bin_result read_only::abi_json_to_bin( const read_only::abi_json_to_bin_params& params )const try {
abi_json_to_bin_result result;
const auto& code_account = db.get_database().get<account_object,by_name>( params.code );
const auto code_account = db.get_database().find<account_object,by_name>( params.code );
EOS_ASSERT(code_account != nullptr, contract_query_exception, "Contract can't be found ${contract}", ("contract", params.code));
abi_def abi;
if( abi_serializer::to_abi(code_account.abi, abi) ) {
if( abi_serializer::to_abi(code_account->abi, abi) ) {
abi_serializer abis( abi );
result.binargs = abis.variant_to_binary( abis.get_action_type( params.action ), params.args );
try {
result.binargs = abis.variant_to_binary(abis.get_action_type(params.action), params.args);
} EOS_RETHROW_EXCEPTIONS(chain::invalid_action_args_exception,
"'${args}' is invalid args for action '${action}' code '${code}'",
("args", params.args)("action", params.action)("code", params.code))
}
return result;
} FC_CAPTURE_AND_RETHROW( (params.code)(params.action)(params.args) )
......
......@@ -14,6 +14,8 @@
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <boost/container/flat_set.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
namespace fc { class variant; }
......@@ -145,7 +147,7 @@ public:
struct get_table_rows_params {
bool json = false;
name code;
name scope;
string scope;
name table;
// string table_type;
string table_key;
......@@ -180,12 +182,6 @@ public:
fc::variant get_currency_stats( const get_currency_stats_params& params )const;
static void copy_row(const chain::contracts::key_value_object& obj, vector<char>& data) {
data.resize( sizeof(uint64_t) + obj.value.size() );
memcpy( data.data(), &obj.primary_key, sizeof(uint64_t) );
memcpy( data.data()+sizeof(uint64_t), obj.value.data(), obj.value.size() );
}
static void copy_inline_row(const chain::contracts::key_value_object& obj, vector<char>& data) {
data.resize( obj.value.size() );
memcpy( data.data(), obj.value.data(), obj.value.size() );
......@@ -215,9 +211,32 @@ public:
read_only::get_table_rows_result result;
const auto& d = db.get_database();
uint64_t scope = 0;
try {
name s(p.scope);
scope = s.value;
} catch( ... ) {
try {
auto trimmed_scope_str = p.scope;
boost::trim(trimmed_scope_str);
scope = boost::lexical_cast<uint64_t>(trimmed_scope_str.c_str(), trimmed_scope_str.size());
} catch( ... ) {
try {
auto symb = eosio::chain::symbol::from_string(p.scope);
scope = symb.value();
} catch( ... ) {
try {
scope = ( eosio::chain::string_to_symbol( 0, p.scope.c_str() ) >> 8 );
} catch( ... ) {
FC_ASSERT( false, "could not convert scope string to any of the following: uint64_t, valid name, or valid symbol (with or without the precision)" );
}
}
}
}
abi_serializer abis;
abis.set_abi(abi);
const auto* t_id = d.find<chain::contracts::table_id_object, chain::contracts::by_code_scope_table>(boost::make_tuple(p.code, p.scope, p.table));
const auto* t_id = d.find<chain::contracts::table_id_object, chain::contracts::by_code_scope_table>(boost::make_tuple(p.code, scope, p.table));
if (t_id != nullptr) {
const auto &idx = d.get_index<IndexType, Scope>();
decltype(t_id->id) next_tid(t_id->id._id + 1);
......@@ -240,7 +259,7 @@ public:
unsigned int count = 0;
auto itr = lower;
for (itr = lower; itr != upper; ++itr) {
copy_row(*itr, data);
copy_inline_row(*itr, data);
if (p.json) {
result.rows.emplace_back(abis.binary_to_variant(abis.get_table_type(p.table), data));
......
......@@ -81,36 +81,48 @@ namespace eosio {
* @brief Structure used to create JSON error responses
*/
struct error_results {
struct error_detail {
uint16_t code;
string message;
struct error_info {
int64_t code;
string name;
string message;
string details;
vector<fc::log_context> stack_trace;
string what;
struct error_detail {
string message;
string file;
uint64_t line_number;
string method;
};
static const uint8_t stack_trace_limit = 10;
vector<error_detail> details;
error_detail() {};
static const uint8_t details_limit = 10;
error_detail(const fc::exception& exc) {
error_info() {};
error_info(const fc::exception& exc) {
code = exc.code();
name = exc.name();
message = exc.what();
details = exc.top_message();
what = exc.what();
for (auto itr = exc.get_log().begin(); itr != exc.get_log().end(); ++itr) {
// Prevent sending trace that are too big
if (stack_trace.size() >= stack_trace_limit) break;
// Append context
stack_trace.emplace_back(itr->get_context());
if (details.size() >= details_limit) break;
// Append error
error_detail detail = {
itr->get_message(), itr->get_context().get_file(),
itr->get_context().get_line_number(), itr->get_context().get_method()
};
details.emplace_back(detail);
}
}
};
uint16_t code;
string message;
error_detail error;
error_info error;
};
}
FC_REFLECT(eosio::error_results::error_detail, (code)(name)(message)(details)(stack_trace))
FC_REFLECT(eosio::error_results::error_info::error_detail, (message)(file)(line_number)(method))
FC_REFLECT(eosio::error_results::error_info, (code)(name)(what)(details))
FC_REFLECT(eosio::error_results, (code)(message)(error))
......@@ -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()
......@@ -2253,7 +2253,11 @@ namespace eosio {
}
}
break;
}}
}
case transaction_receipt::delayed:
#warning TODO: Not sure what should happen here
break;
}
}
}
}
......
......@@ -24,6 +24,8 @@
#ifndef WIN32
# include <sys/types.h>
# include <sys/stat.h>
#include <eosio/chain/exceptions.hpp>
#endif
namespace eosio { namespace wallet {
......@@ -295,7 +297,8 @@ void wallet_api::unlock(string password)
FC_ASSERT(pk.checksum == pw);
my->_keys = std::move(pk.keys);
my->_checksum = pk.checksum;
} FC_CAPTURE_AND_RETHROW() }
} EOS_RETHROW_EXCEPTIONS(chain::wallet_invalid_password_exception,
"Invalid password for wallet: \"${wallet_name}\"", ("wallet_name", get_wallet_filename())) }
void wallet_api::set_password( string password )
{
......
......@@ -3,7 +3,7 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/wallet_plugin/wallet_manager.hpp>
#include <eosio/chain/exceptions.hpp>
namespace eosio {
namespace wallet {
......@@ -38,7 +38,7 @@ std::string wallet_manager::create(const std::string& name) {
auto wallet_filename = dir / (name + file_ext);
if (fc::exists(wallet_filename)) {
FC_THROW("Wallet with name: '${n}' already exists at ${path}", ("n", name)("path",fc::path(wallet_filename)));
EOS_THROW(chain::wallet_exist_exception, "Wallet with name: '${n}' already exists at ${path}", ("n", name)("path",fc::path(wallet_filename)));
}
wallet_data d;
......@@ -68,7 +68,7 @@ void wallet_manager::open(const std::string& name) {
auto wallet_filename = dir / (name + file_ext);
wallet->set_wallet_filename(wallet_filename.string());
if (!wallet->load_wallet_file()) {
FC_THROW("Unable to open file: ${f}", ("f", wallet_filename.string()));
EOS_THROW(chain::wallet_nonexistent_exception, "Unable to open file: ${f}", ("f", wallet_filename.string()));
}
// If we have name in our map then remove it since we want the emplace below to replace.
......@@ -134,7 +134,7 @@ void wallet_manager::lock_all() {
void wallet_manager::lock(const std::string& name) {
check_timeout();
if (wallets.count(name) == 0) {
FC_THROW("Wallet not found: ${w}", ("w", name));
EOS_THROW(chain::wallet_nonexistent_exception, "Wallet not found: ${w}", ("w", name));
}
auto& w = wallets.at(name);
if (w->is_locked()) {
......@@ -158,11 +158,11 @@ void wallet_manager::unlock(const std::string& name, const std::string& password
void wallet_manager::import_key(const std::string& name, const std::string& wif_key) {
check_timeout();
if (wallets.count(name) == 0) {
FC_THROW("Wallet not found: ${w}", ("w", name));
EOS_THROW(chain::wallet_nonexistent_exception, "Wallet not found: ${w}", ("w", name));
}
auto& w = wallets.at(name);
if (w->is_locked()) {
FC_THROW("Wallet is locked: ${w}", ("w", name));
EOS_THROW(chain::wallet_locked_exception, "Wallet is locked: ${w}", ("w", name));
}
w->import_key(wif_key);
}
......@@ -185,7 +185,7 @@ wallet_manager::sign_transaction(const chain::signed_transaction& txn, const fla
}
}
if (!found) {
FC_THROW("Public key not found in unlocked wallets ${k}", ("k", pk));
EOS_THROW(chain::wallet_missing_pub_key_exception, "Public key not found in unlocked wallets ${k}", ("k", pk));
}
}
......
......@@ -97,11 +97,29 @@ auto smatch_to_variant(const std::smatch& smatch) {
return result;
};
const char* error_advice_3120001 = R"=====(Name should be less than 13 characters and only contains the following symbol .12345abcdefghijklmnopqrstuvwxyz)=====";
const char* error_advice_3010001 = "Most likely, the given account/ permission doesn't exist in the blockchain.";
const char* error_advice_3010002 = "Most likely, the given account doesn't exist in the blockchain.";
const char* error_advice_3010003 = "Most likely, the given table doesnt' exist in the blockchain.";
const char* error_advice_3010004 = "Most likely, the given contract doesnt' exist in the blockchain.";
const char* error_advice_3030000 = "Ensure that your transaction satisfy the contract's constraint!";
const char* error_advice_3030001 = R"=====(Ensure that you have the related authority inside your transaction!;
If you are currently using 'cleos push action' command, try to add the relevant authority using -p option.)=====";
const char* error_advice_3030002 = "Ensure that you have the related private keys inside your wallet and you wallet is unlocked.";
const char* error_advice_3030003 = "Please remove the unnecessary authority from your action!";
const char* error_advice_3030004 = "Please remove the unnecessary signature from your transaction!";
const char* error_advice_3030011 = "You can try embedding eosio nonce action inside your transaction to ensure uniqueness.";
const char* error_advice_3030022 = "Please increase the expiration time of your transaction!";
const char* error_advice_3030023 = "Please decrease the expiration time of your transaction!";
const char* error_advice_3030024 = "Ensure that the reference block exist in the blockchain!";
const char* error_advice_3040002 = R"=====(Ensure that your arguments follow the contract abi!
You can check the contract's abi by using 'cleos get code' command.)=====";
const char* error_advice_3120001 = R"=====(Name should be less than 13 characters and only contains the following symbol .12345abcdefghijklmnopqrstuvwxyz)=====";
const char* error_advice_3120002 = R"=====(Public key should be encoded in base58 and starts with EOS prefix)=====";
const char* error_advice_3120003 = R"=====(Ensure that your authority JSON follows the following format!
const char* error_advice_3120003 = R"=====(Private key should be encoded in base58 WIF)=====";
const char* error_advice_3120004 = R"=====(Ensure that your authority JSON follows the following format!
{
"threshold":"uint32_t",
"keys":[{ "key":"public_key", "weight":"uint16_t" }],
......@@ -119,10 +137,8 @@ e.g.
"weight":"1
}]
})=====";
const char* error_advice_3120004 = R"=====(Ensure that your action JSON follows the contract's abi!)=====";
const char* error_advice_3120005 = R"=====(Ensure that your transaction JSON follows the following format!\n"
const char* error_advice_3120005 = R"=====(Ensure that your action JSON follows the contract's abi!)=====";
const char* error_advice_3120006 = R"=====(Ensure that your transaction JSON follows the following format!\n"
{
"ref_block_num":"uint16_t",
"ref_block_prefix":"uint32_t",
......@@ -152,8 +168,7 @@ e.g.
"data":"000000008093dd74000000000094dd74e80300000000000000"
}]
})=====";
const char* error_advice_3120006 = R"=====(Ensure that your abi JSON follows the following format!
const char* error_advice_3120007 = R"=====(Ensure that your abi JSON follows the following format!
{
"types" : [{ "new_type_name":"type_name", "type":"type_name" }],
"structs" : [{ "name":"type_name", "base":"type_name", "fields": [{ "name":"field_name", "type": "type_name" }] }],
......@@ -182,27 +197,74 @@ e.g.
"type":"foobar" "
}]
})=====";
const char* error_advice_3120008 = "Ensure that the block ID is a SHA-256 hexadecimal string!";
const char* error_advice_3120009 = "Ensure that the transaction ID is a SHA-256 hexadecimal string!";
const char* error_advice_3120010 = R"=====(Ensure that your packed transaction JSON follows the following format!
{
"signatures" : [ "signature" ],
"compression" : enum("none", "zlib"),
"data" : "bytes"
}
e.g.
{
"signatures" : [ "EOSJze4m1ZHQ4UjuHpBcX6uHPN4Xyggv52raQMTBZJghzDLepaPcSGCNYTxaP2NiaF4yRF5RaYwqsQYAwBwFtfuTJr34Z5GJX" ],
"compression" : "none",
"data" : "6c36a25a00002602626c5e7f0000000000010000001e4d75af460000000000a53176010000000000ea305500000000a8ed3232180000001e4d75af4680969800000000000443555200000000"
})=====";
const char* error_advice_3130001 = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration!";
const char* error_advice_3130002 = "Ensure that you have \033[2meosio::wallet_api_plugin\033[0m\033[32m added to your node's configuration!\n"\
"Otherwise specify your wallet location with \033[2m--wallet-host\033[0m\033[32m and \033[2m--wallet_port\033[0m\033[32m arguments!";
const char* error_advice_3130003 = "Ensure that you have \033[2meosio::account_history_api_plugin\033[0m\033[32m added to your node's configuration!";
const char* error_advice_3130004 = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration!";
const char* error_advice_3030002 = "Ensure that you have the related private keys inside your wallet.";
const char* error_advice_3140001 = "Try to use different wallet name.";
const char* error_advice_3140002 = "Are you sure you typed the name correctly?";
const char* error_advice_3140003 = "Ensure that your wallet is unlocked before using it!";
const char* error_advice_3140004 = "Ensure that you have the relevant private key imported!";
const char* error_advice_3140005 = "Are you sure you are using the right password?";
const char* error_advice_3130001 = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration.";
const char* error_advice_3130002 = "Ensure that you have \033[2meosio::wallet_api_plugin\033[0m\033[32m added to your node's configuration.\n"\
"Otherwise specify your wallet location with \033[2m--wallet-host\033[0m\033[32m and \033[2m--wallet_port\033[0m\033[32m arguments.";
const char* error_advice_3130003 = "Ensure that you have \033[2meosio::account_history_api_plugin\033[0m\033[32m added to your node's configuration.";
const char* error_advice_3130004 = "Ensure that you have \033[2meosio::net_api_plugin\033[0m\033[32m added to your node's configuration";
const std::map<int64_t, std::string> error_advice = {
{ 3010001, error_advice_3010001 },
{ 3010002, error_advice_3010002 },
{ 3010003, error_advice_3010003 },
{ 3010004, error_advice_3010004 },
{ 3030000, error_advice_3030000 },
{ 3030001, error_advice_3030001 },
{ 3030002, error_advice_3030002 },
{ 3030003, error_advice_3030003 },
{ 3030004, error_advice_3030004 },
{ 3030011, error_advice_3030011 },
{ 3030022, error_advice_3030022 },
{ 3030023, error_advice_3030023 },
{ 3030024, error_advice_3030024 },
{ 3040002, error_advice_3040002 },
{ 3120001, error_advice_3120001 },
{ 3120002, error_advice_3120002 },
{ 3120003, error_advice_3120003 },
{ 3120004, error_advice_3120004 },
{ 3120005, error_advice_3120005 },
{ 3120006, error_advice_3120006 },
{ 3120007, error_advice_3120007 },
{ 3120008, error_advice_3120008 },
{ 3120009, error_advice_3120009 },
{ 3120010, error_advice_3120010 },
{ 3130001, error_advice_3130001 },
{ 3130002, error_advice_3130002 },
{ 3130003, error_advice_3130003 },
{ 3130004, error_advice_3130004 },
{ 3030002, error_advice_3030002 }
{ 3140001, error_advice_3140001 },
{ 3140002, error_advice_3140002 },
{ 3140003, error_advice_3140003 },
{ 3140004, error_advice_3140004 },
{ 3140005, error_advice_3140005 }
};
......@@ -222,14 +284,14 @@ bool print_recognized_errors(const fc::exception& e, const bool verbose_errors)
// Check if there's a log to display
if (!log.get_format().empty()) {
// Localize the message as needed
explanation += "\n " + localized_with_variant(log.get_format().data(), log.get_data());
explanation += "\n" + localized_with_variant(log.get_format().data(), log.get_data());
} else if (log.get_data().size() > 0 && verbose_errors) {
// Show data-only log only if verbose_errors option is enabled
explanation += "\n " + fc::json::to_string(log.get_data());
explanation += "\n" + fc::json::to_string(log.get_data());
}
// Check if there's stack trace to be added
if (!log.get_context().get_method().empty() && verbose_errors) {
stack_trace += "\n " +
stack_trace += "\n" +
log.get_context().get_file() + ":" +
fc::to_string(log.get_context().get_line_number()) + " " +
log.get_context().get_method();
......
......@@ -124,26 +124,24 @@ namespace eosio { namespace client { namespace http {
throw chain::missing_net_api_plugin_exception(FC_LOG_MESSAGE(error, "Net API plugin is not enabled"));
}
} else {
auto &&error = response_result.as<eosio::error_results>().error;
auto &&error_info = response_result.as<eosio::error_results>().error;
// Construct fc exception from error
const auto &stack_trace = error.stack_trace;
fc::exception new_exception(error.code, error.name, error.message);
if (stack_trace.empty()) {
new_exception.append_log(FC_LOG_MESSAGE(error, error.details));
} else {
for (auto itr = stack_trace.begin(); itr != stack_trace.end(); itr++) {
const auto &error_message = itr == stack_trace.begin() ? error.details : std::string();
new_exception.append_log(fc::log_message(*itr, error_message));
}
const auto &error_details = error_info.details;
fc::log_messages logs;
for (auto itr = error_details.begin(); itr != error_details.end(); itr++) {
const auto& context = fc::log_context(fc::log_level::error, itr->file.data(), itr->line_number, itr->method.data());
logs.emplace_back(fc::log_message(context, itr->message));
}
throw new_exception;
throw fc::exception(logs, error_info.code, error_info.name, error_info.what);
}
FC_ASSERT( status_code == 200, "Error code ${c}\n: ${msg}\n", ("c", status_code)("msg", re.str()) );
}
FC_ASSERT( !"unable to connect" );
} FC_RETHROW_EXCEPTIONS( error, "Request Path: ${server}:${port}${path}, Request Post Data: ${postdata}" ,
} FC_RETHROW_EXCEPTIONS( error, "Request Path: ${server}:${port}${path}\nRequest Post Data: ${postdata}" ,
("server", server)("port", port)("path", path)("postdata", postdata) )
}
}}}
\ No newline at end of file
......@@ -141,7 +141,7 @@ void add_standard_transaction_options(CLI::App* cmd, string default_permission =
if (res.size() == 0 || !CLI::detail::lexical_cast(res[0], value_s)) {
return false;
}
tx_expiration = fc::seconds(static_cast<uint64_t>(value_s));
return true;
};
......@@ -245,9 +245,9 @@ chain::action create_newaccount(const name& creator, const name& newaccount, pub
return action {
tx_permission.empty() ? vector<chain::permission_level>{{creator,config::active_name}} : get_account_permissions(tx_permission),
contracts::newaccount{
.creator = creator,
.name = newaccount,
.owner = eosio::chain::authority{1, {{owner, 1}}, {}},
.creator = creator,
.name = newaccount,
.owner = eosio::chain::authority{1, {{owner, 1}}, {}},
.active = eosio::chain::authority{1, {{active, 1}}, {}},
.recovery = eosio::chain::authority{1, {}, {{{creator, config::active_name}, 1}}}
}
......@@ -261,7 +261,7 @@ chain::action create_transfer(const name& sender, const name& recipient, uint64_
("to", recipient)
("quantity", asset(amount))
("memo", memo);
auto args = fc::mutable_variant_object
("code", name(config::system_account_name))
("action", "transfer")
......@@ -276,7 +276,7 @@ chain::action create_transfer(const name& sender, const name& recipient, uint64_
}
chain::action create_setabi(const name& account, const contracts::abi_def& abi) {
return action {
return action {
tx_permission.empty() ? vector<chain::permission_level>{{account,config::active_name}} : get_account_permissions(tx_permission),
contracts::setabi{
.account = account,
......@@ -286,13 +286,13 @@ chain::action create_setabi(const name& account, const contracts::abi_def& abi)
}
chain::action create_setcode(const name& account, const bytes& code) {
return action {
return action {
tx_permission.empty() ? vector<chain::permission_level>{{account,config::active_name}} : get_account_permissions(tx_permission),
contracts::setcode{
.account = account,
.vmtype = 0,
.vmversion = 0,
.code = code
.code = code
}
};
}
......@@ -336,7 +336,7 @@ struct set_account_permission_subcommand {
name account = name(accountStr);
name permission = name(permissionStr);
bool is_delete = boost::iequals(authorityJsonOrFile, "null");
if (is_delete) {
send_actions({create_deleteauth(account, permission)});
} else {
......@@ -344,7 +344,7 @@ struct set_account_permission_subcommand {
if (boost::istarts_with(authorityJsonOrFile, "EOS")) {
try {
auth = authority(public_key_type(authorityJsonOrFile));
} EOS_CAPTURE_AND_RETHROW(public_key_type_exception, "")
} EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid public key: ${public_key}", ("public_key", authorityJsonOrFile))
} else {
fc::variant parsedAuthority;
try {
......@@ -354,7 +354,7 @@ struct set_account_permission_subcommand {
parsedAuthority = fc::json::from_file(authorityJsonOrFile);
}
auth = parsedAuthority.as<authority>();
} EOS_CAPTURE_AND_RETHROW(authority_type_exception, "Fail to parse Authority JSON")
} EOS_RETHROW_EXCEPTIONS(authority_type_exception, "Fail to parse Authority JSON")
}
......@@ -363,10 +363,10 @@ struct set_account_permission_subcommand {
// see if we can auto-determine the proper parent
const auto account_result = call(get_account_func, fc::mutable_variant_object("account_name", accountStr));
const auto& existing_permissions = account_result.get_object()["permissions"].get_array();
auto permissionPredicate = [this](const auto& perm) {
return perm.is_object() &&
auto permissionPredicate = [this](const auto& perm) {
return perm.is_object() &&
perm.get_object().contains("permission") &&
boost::equals(perm.get_object()["permission"].get_string(), permissionStr);
boost::equals(perm.get_object()["permission"].get_string(), permissionStr);
};
auto itr = boost::find_if(existing_permissions, permissionPredicate);
......@@ -382,10 +382,10 @@ struct set_account_permission_subcommand {
}
send_actions({create_updateauth(account, permission, parent, auth)});
}
}
});
}
};
struct set_action_permission_subcommand {
......@@ -408,13 +408,13 @@ struct set_action_permission_subcommand {
name code = name(codeStr);
name type = name(typeStr);
bool is_delete = boost::iequals(requirementStr, "null");
if (is_delete) {
send_actions({create_unlinkauth(account, code, type)});
} else {
name requirement = name(requirementStr);
send_actions({create_linkauth(account, code, type, requirement)});
}
}
});
}
};
......@@ -422,7 +422,7 @@ struct set_action_permission_subcommand {
int main( int argc, char** argv ) {
fc::path binPath = argv[0];
if (binPath.is_relative()) {
binPath = relative(binPath, current_path());
binPath = relative(binPath, current_path());
}
setlocale(LC_ALL, "");
......@@ -475,8 +475,10 @@ int main( int argc, char** argv ) {
public_key_type owner_key, active_key;
try {
owner_key = public_key_type(owner_key_str);
} EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid owner public key: ${public_key}", ("public_key", owner_key_str))
try {
active_key = public_key_type(active_key_str);
} EOS_CAPTURE_AND_RETHROW(public_key_type_exception, "Invalid Public Key")
} EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str))
send_actions({create_newaccount(creator, account_name, owner_key, active_key)});
});
......@@ -534,7 +536,7 @@ int main( int argc, char** argv ) {
}
});
// get table
// get table
string scope;
string code;
string table;
......@@ -544,8 +546,8 @@ int main( int argc, char** argv ) {
bool binary = false;
uint32_t limit = 10;
auto getTable = get->add_subcommand( "table", localized("Retrieve the contents of a database table"), false);
getTable->add_option( "scope", scope, localized("The account scope where the table is found") )->required();
getTable->add_option( "contract", code, localized("The contract within scope who owns the table") )->required();
getTable->add_option( "contract", code, localized("The contract who owns the table") )->required();
getTable->add_option( "scope", scope, localized("The scope within the contract in which the table is found") )->required();
getTable->add_option( "table", table, localized("The name of the table as specified by the contract abi") )->required();
getTable->add_option( "-b,--binary", binary, localized("Return the value as BINARY rather than using abi to interpret as JSON") );
getTable->add_option( "-l,--limit", limit, localized("The maximum number of rows to return") );
......@@ -555,8 +557,8 @@ int main( int argc, char** argv ) {
getTable->set_callback([&] {
auto result = call(get_table_func, fc::mutable_variant_object("json", !binary)
("scope",scope)
("code",code)
("scope",scope)
("table",table)
("table_key",table_key)
("lower_bound",lower)
......@@ -572,6 +574,7 @@ int main( int argc, char** argv ) {
// get currency balance
string symbol;
auto get_currency = get->add_subcommand( "currency", localized("Retrieve information related to standard currencies"), true);
get_currency->require_subcommand();
auto get_balance = get_currency->add_subcommand( "balance", localized("Retrieve the balance of an account for a given currency"), false);
get_balance->add_option( "contract", code, localized("The contract that operates the currency") )->required();
get_balance->add_option( "account", accountName, localized("The account to query balances for") )->required();
......@@ -613,11 +616,15 @@ int main( int argc, char** argv ) {
});
// get accounts
string publicKey;
string public_key_str;
auto getAccounts = get->add_subcommand("accounts", localized("Retrieve accounts associated with a public key"), false);
getAccounts->add_option("public_key", publicKey, localized("The public key to retrieve accounts for"))->required();
getAccounts->add_option("public_key", public_key_str, localized("The public key to retrieve accounts for"))->required();
getAccounts->set_callback([&] {
auto arg = fc::mutable_variant_object( "public_key", publicKey);
public_key_type public_key;
try {
public_key = public_key_type(public_key_str);
} EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid public key: ${public_key}", ("public_key", public_key_str))
auto arg = fc::mutable_variant_object( "public_key", public_key);
std::cout << fc::json::to_pretty_string(call(get_key_accounts_func, arg)) << std::endl;
});
......@@ -632,27 +639,44 @@ int main( int argc, char** argv ) {
});
// get transaction
string transactionId;
string transaction_id_str;
auto getTransaction = get->add_subcommand("transaction", localized("Retrieve a transaction from the blockchain"), false);
getTransaction->add_option("id", transactionId, localized("ID of the transaction to retrieve"))->required();
getTransaction->add_option("id", transaction_id_str, localized("ID of the transaction to retrieve"))->required();
getTransaction->set_callback([&] {
auto arg= fc::mutable_variant_object( "transaction_id", transactionId);
transaction_id_type transaction_id;
try {
transaction_id = transaction_id_type(transaction_id_str);
} EOS_RETHROW_EXCEPTIONS(transaction_id_type_exception, "Invalid transaction ID: ${transaction_id}", ("transaction_id", transaction_id_str))
auto arg= fc::mutable_variant_object( "transaction_id", transaction_id);
std::cout << fc::json::to_pretty_string(call(get_transaction_func, arg)) << std::endl;
});
// get transactions
string skip_seq;
string num_seq;
string skip_seq_str;
string num_seq_str;
auto getTransactions = get->add_subcommand("transactions", localized("Retrieve all transactions with specific account name referenced in their scope"), false);
getTransactions->add_option("account_name", account_name, localized("name of account to query on"))->required();
getTransactions->add_option("skip_seq", skip_seq, localized("Number of most recent transactions to skip (0 would start at most recent transaction)"));
getTransactions->add_option("num_seq", num_seq, localized("Number of transactions to return"));
getTransactions->add_option("skip_seq", skip_seq_str, localized("Number of most recent transactions to skip (0 would start at most recent transaction)"));
getTransactions->add_option("num_seq", num_seq_str, localized("Number of transactions to return"));
getTransactions->set_callback([&] {
auto arg = (skip_seq.empty())
? fc::mutable_variant_object( "account_name", account_name)
: (num_seq.empty())
? fc::mutable_variant_object( "account_name", account_name)("skip_seq", skip_seq)
: fc::mutable_variant_object( "account_name", account_name)("skip_seq", skip_seq)("num_seq", num_seq);
fc::mutable_variant_object arg;
if (skip_seq_str.empty()) {
arg = fc::mutable_variant_object( "account_name", account_name);
} else {
uint64_t skip_seq;
try {
skip_seq = boost::lexical_cast<uint64_t>(skip_seq_str);
} EOS_RETHROW_EXCEPTIONS(chain_type_exception, "Invalid Skip Seq: ${skip_seq}", ("skip_seq", skip_seq_str))
if (num_seq_str.empty()) {
arg = fc::mutable_variant_object( "account_name", account_name)("skip_seq", skip_seq);
} else {
uint64_t num_seq;
try {
num_seq = boost::lexical_cast<uint64_t>(num_seq_str);
} EOS_RETHROW_EXCEPTIONS(chain_type_exception, "Invalid Num Seq: ${num_seq}", ("num_seq", num_seq_str))
arg = fc::mutable_variant_object( "account_name", account_name)("skip_seq", skip_seq_str)("num_seq", num_seq);
}
}
auto result = call(get_transactions_func, arg);
std::cout << fc::json::to_pretty_string(call(get_transactions_func, arg)) << std::endl;
......@@ -685,7 +709,7 @@ int main( int argc, char** argv ) {
->check(CLI::ExistingFile);
auto abi = contractSubcommand->add_option("abi-file,-a,--abi", abiPath, localized("The ABI for the contract"))
->check(CLI::ExistingFile);
add_standard_transaction_options(contractSubcommand, "account@active");
contractSubcommand->set_callback([&] {
std::string wast;
......@@ -709,7 +733,7 @@ int main( int argc, char** argv ) {
if (abi->count()) {
try {
actions.emplace_back( create_setabi(account, fc::json::from_file(abiPath).as<contracts::abi_def>()) );
} EOS_CAPTURE_AND_RETHROW(abi_type_exception, "Fail to parse ABI JSON")
} EOS_RETHROW_EXCEPTIONS(abi_type_exception, "Fail to parse ABI JSON")
}
std::cout << localized("Publishing contract...") << std::endl;
......@@ -724,7 +748,7 @@ int main( int argc, char** argv ) {
// set action
auto setAction = setSubcommand->add_subcommand("action", localized("set or update blockchain action state"))->require_subcommand();
// set action permission
auto setActionPermission = set_action_permission_subcommand(setAction);
......@@ -747,11 +771,11 @@ int main( int argc, char** argv ) {
memo = generate_nonce_value();
tx_force_unique = false;
}
send_actions({create_transfer(sender, recipient, amount, memo)});
});
// Net subcommand
// Net subcommand
string new_host;
auto net = app.add_subcommand( "net", localized("Interact with local p2p network connections"), false );
net->require_subcommand();
......@@ -847,13 +871,18 @@ int main( int argc, char** argv ) {
});
// import keys into wallet
string wallet_key;
string wallet_key_str;
auto importWallet = wallet->add_subcommand("import", localized("Import private key into wallet"), false);
importWallet->add_option("-n,--name", wallet_name, localized("The name of the wallet to import key into"));
importWallet->add_option("key", wallet_key, localized("Private key in WIF format to import"))->required();
importWallet->set_callback([&wallet_name, &wallet_key] {
private_key_type key( wallet_key );
public_key_type pubkey = key.get_public_key();
importWallet->add_option("key", wallet_key_str, localized("Private key in WIF format to import"))->required();
importWallet->set_callback([&wallet_name, &wallet_key_str] {
private_key_type wallet_key;
try {
wallet_key = private_key_type( wallet_key_str );
} catch (...) {
EOS_THROW(private_key_type_exception, "Invalid private key: ${private_key}", ("private_key", wallet_key_str))
}
public_key_type pubkey = wallet_key.get_public_key();
fc::variants vs = {fc::variant(wallet_name), fc::variant(wallet_key)};
const auto& v = call(wallet_host, wallet_port, wallet_import_key, vs);
......@@ -936,7 +965,7 @@ int main( int argc, char** argv ) {
fc::variant action_args_var;
try {
action_args_var = fc::json::from_string(data);
} EOS_CAPTURE_AND_RETHROW(action_type_exception, "Fail to parse action JSON")
} EOS_RETHROW_EXCEPTIONS(action_type_exception, "Fail to parse action JSON")
auto arg= fc::mutable_variant_object
("code", contract)
......@@ -962,7 +991,8 @@ int main( int argc, char** argv ) {
} else {
trx_var = fc::json::from_string(trx_to_push);
}
} EOS_CAPTURE_AND_RETHROW(transaction_type_exception, "Fail to parse transaction JSON") signed_transaction trx = trx_var.as<signed_transaction>();
} EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON")
signed_transaction trx = trx_var.as<signed_transaction>();
auto trx_result = call(push_txn_func, packed_transaction(trx, packed_transaction::none));
std::cout << fc::json::to_pretty_string(trx_result) << std::endl;
});
......@@ -975,7 +1005,7 @@ int main( int argc, char** argv ) {
fc::variant trx_var;
try {
trx_var = fc::json::from_string(trxsJson);
} EOS_CAPTURE_AND_RETHROW(transaction_type_exception, "Fail to parse transaction JSON")
} EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse transaction JSON")
auto trxs_result = call(push_txns_func, trx_var);
std::cout << fc::json::to_pretty_string(trxs_result) << std::endl;
});
......
......@@ -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
......
......@@ -5,7 +5,7 @@
MEM_GIG=`bc <<< "($(sysctl -in hw.memsize) / 1024000000)"`
CPU_SPEED=`bc <<< "scale=2; ($(sysctl -in hw.cpufrequency) / 100000000) / 10"`
CPU_SPEED=`bc <<< "scale=2; ($(sysctl -in hw.cpufrequency) / 10^6) / 10"`
CPU_CORE=$( sysctl -in machdep.cpu.core_count )
blksize=`df . | head -1 | awk '{print $2}' | cut -d- -f1`
......@@ -22,7 +22,7 @@
printf "\tPhysical Memory: $MEM_GIG Gbytes\n"
printf "\tDisk space total: ${DISK_TOTAL}G\n"
printf "\tDisk space available: ${DISK_AVAIL}G\n\n"
if [ $MEM_GIG -lt 8 ]; then
echo "Your system must have 8 or more Gigabytes of physical memory installed."
echo "Exiting now."
......@@ -100,7 +100,7 @@
printf '\t\t %s found\n' "$name"
continue
fi
# resolve conflict with homebrew glibtool and apples install of libtool
# resolve conflict with homebrew glibtool and apple/gnu installs of libtool
if [ ${testee} == "/usr/local/bin/glibtool" ]; then
if [ ${tester} "/usr/local/bin/libtool" ]; then
printf '\t\t %s found\n' "$name"
......@@ -117,6 +117,16 @@
let COUNT++
done < scripts/eosio_build_dep
IFS=${var_ifs}
printf "\tChecking Python3 ... "
if [ `python --version | tr - ' ' | cut -d ' ' -f2 | cut -d'.' -f1` != ${PYTHON_MIN} ]; then
DEP=$DEP"python@${PYTHON_MIN} "
DISPLAY="${DISPLAY}${COUNT}. Python 3\n\t"
printf "\t\t python${PYTHON_MIN} ${bldred}NOT${txtrst} found.\n"
let DCOUNT++
else
printf "\t\t Python3 found\n"
fi
if [ $DCOUNT -ne 0 ]; then
printf "\n\tThe following dependencies are required to install EOSIO.\n"
......@@ -145,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
......@@ -159,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"
......@@ -180,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"
......@@ -187,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"
......@@ -208,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 )
......
......@@ -244,8 +244,8 @@ BOOST_FIXTURE_TEST_CASE(action_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_action", "assert_true", {});
//test assert_false
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "assert_false", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "assert_false", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "test_action::assert_false");
}
);
......@@ -352,8 +352,8 @@ BOOST_FIXTURE_TEST_CASE(action_tests, tester) { try {
// test now
produce_block();
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "now", fc::raw::pack(now)), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "now", fc::raw::pack(now)), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "assertion failed: tmp == now");
}
);
......@@ -370,8 +370,8 @@ BOOST_FIXTURE_TEST_CASE(action_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_action", "test_publication_time", fc::raw::pack(pub_time) );
// test test_abort
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "test_abort", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_action", "test_abort", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "abort() called");
}
);
......@@ -404,7 +404,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, tester) { try {
auto sigs = trx.sign(get_private_key(N(testapi), "active"), chain_id_type());
BOOST_CHECK_EXCEPTION(push_transaction(trx), tx_irrelevant_sig,
[](const fc::assert_exception& e) {
[](const fc::exception& e) {
edump((e.what()));
return expect_assert_message(e, "signatures");
}
......@@ -434,8 +434,8 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, tester) { try {
set_tapos(trx);
// run normal passing case
sigs = trx.sign(get_private_key(N(testapi), "active"), chain_id_type());
BOOST_CHECK_EXCEPTION(push_transaction(trx), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(push_transaction(trx), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "may only be called from context_free");
}
);
......@@ -456,8 +456,8 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, tester) { try {
trx.signatures.clear();
set_tapos(trx);
sigs = trx.sign(get_private_key(N(testapi), "active"), chain_id_type());
BOOST_CHECK_EXCEPTION(push_transaction(trx), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(push_transaction(trx), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "context_free: only context free api's can be used in this context");
}
);
......@@ -473,8 +473,8 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, tester) { try {
BOOST_CHECK_EQUAL(ttrace.action_traces[1].act.name == account_name("event1"), true);
BOOST_CHECK_EQUAL(ttrace.action_traces[1].act.authorization.size(), 0);
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action_fail", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action_fail", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "context free actions cannot have authorizations");
}
);
......@@ -500,7 +500,11 @@ BOOST_FIXTURE_TEST_CASE(checktime_pass_tests, tester) { try {
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try {
tester t( {fc::milliseconds(100), fc::milliseconds(100)} );
// TODO: This is an extremely fragile test. It needs improvements:
// 1) compilation of the smart contract should probably not count towards the CPU time of a transaction that first uses it;
// 2) checktime should eventually switch to a deterministic metric which should hopefully fix the inconsistencies
// of this test succeeding/failing on different machines (for example, succeeding on our local dev machines but failing on Jenkins).
tester t( {fc::milliseconds(5000), fc::milliseconds(5000)} );
t.produce_blocks(2);
t.create_account( N(testapi) );
......@@ -543,8 +547,8 @@ BOOST_FIXTURE_TEST_CASE(compiler_builtins_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_divti3", {});
// test test_divti3_by_0
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_divti3_by_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_divti3_by_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -553,8 +557,8 @@ BOOST_FIXTURE_TEST_CASE(compiler_builtins_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_udivti3", {});
// test test_udivti3_by_0
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_udivti3_by_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_udivti3_by_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -563,8 +567,8 @@ BOOST_FIXTURE_TEST_CASE(compiler_builtins_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_modti3", {});
// test test_modti3_by_0
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_modti3_by_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_compiler_builtins", "test_modti3_by_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -600,15 +604,15 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, tester) { try {
CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_empty", {});
// test send_action_large
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "data_len < config::default_max_inline_action_size: inline action too big");
}
);
// test send_action_inline_fail
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_inline_fail", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_inline_fail", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "test_action::assert_false");
}
);
......@@ -619,8 +623,8 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, tester) { try {
control->push_deferred_transactions( true );
// test send_transaction_empty
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_empty", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_empty", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "transaction must have at least one action");
}
);
......@@ -825,33 +829,33 @@ BOOST_FIXTURE_TEST_CASE(multi_index_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_multi_index", "idx256_general", {});
CALL_TEST_FUNCTION( *this, "test_multi_index", "idx_double_general", {});
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pk_iterator_exceed_end", {},
fc::assert_exception, "cannot increment end iterator");
transaction_exception, "cannot increment end iterator");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_sk_iterator_exceed_end", {},
fc::assert_exception, "cannot increment end iterator");
transaction_exception, "cannot increment end iterator");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pk_iterator_exceed_begin", {},
fc::assert_exception, "cannot decrement iterator at beginning of table");
transaction_exception, "cannot decrement iterator at beginning of table");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_sk_iterator_exceed_begin", {},
fc::assert_exception, "cannot decrement iterator at beginning of index");
transaction_exception, "cannot decrement iterator at beginning of index");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_pk_ref_to_other_table", {},
fc::assert_exception, "object passed to iterator_to is not in multi_index");
transaction_exception, "object passed to iterator_to is not in multi_index");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_sk_ref_to_other_table", {},
fc::assert_exception, "object passed to iterator_to is not in multi_index");
transaction_exception, "object passed to iterator_to is not in multi_index");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_pk_end_itr_to_iterator_to", {},
fc::assert_exception, "object passed to iterator_to is not in multi_index");
transaction_exception, "object passed to iterator_to is not in multi_index");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_pk_end_itr_to_modify", {},
fc::assert_exception, "cannot pass end iterator to modify");
transaction_exception, "cannot pass end iterator to modify");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_pk_end_itr_to_erase", {},
fc::assert_exception, "cannot pass end iterator to erase");
transaction_exception, "cannot pass end iterator to erase");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_sk_end_itr_to_iterator_to", {},
fc::assert_exception, "object passed to iterator_to is not in multi_index");
transaction_exception, "object passed to iterator_to is not in multi_index");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_sk_end_itr_to_modify", {},
fc::assert_exception, "cannot pass end iterator to modify");
transaction_exception, "cannot pass end iterator to modify");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_pass_sk_end_itr_to_erase", {},
fc::assert_exception, "cannot pass end iterator to erase");
transaction_exception, "cannot pass end iterator to erase");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_modify_primary_key", {},
fc::assert_exception, "updater cannot change primary key when modifying an object");
transaction_exception, "updater cannot change primary key when modifying an object");
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_multi_index", "idx64_run_out_of_avl_pk", {},
fc::assert_exception, "next primary key in table is at autoincrement limit");
transaction_exception, "next primary key in table is at autoincrement limit");
CALL_TEST_FUNCTION( *this, "test_multi_index", "idx64_sk_cache_pk_lookup", {});
CALL_TEST_FUNCTION( *this, "test_multi_index", "idx64_pk_cache_sk_lookup", {});
......@@ -872,8 +876,8 @@ BOOST_FIXTURE_TEST_CASE(fixedpoint_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_subtraction", {});
CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_multiplication", {});
CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_division", {});
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_division_by_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_division_by_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -895,8 +899,8 @@ BOOST_FIXTURE_TEST_CASE(real_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_real", "test_addition", {} );
CALL_TEST_FUNCTION( *this, "test_real", "test_multiplication", {} );
CALL_TEST_FUNCTION( *this, "test_real", "test_division", {} );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_real", "test_division_by_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_real", "test_division_by_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -934,8 +938,8 @@ BOOST_FIXTURE_TEST_CASE(crypto_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key", payload );
CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_true", payload );
payload[payload.size()-1] = 0;
BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_false", payload ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_false", payload ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message( e, "check == p: Error expected key different than recovered key" );
}
);
......@@ -950,40 +954,40 @@ BOOST_FIXTURE_TEST_CASE(crypto_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_crypto", "sha512_no_data", {} );
CALL_TEST_FUNCTION( *this, "test_crypto", "ripemd160_no_data", {} );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha256_false", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha256_false", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "hash miss match");
}
);
CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha256_true", {} );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_false", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_false", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "hash miss match");
}
);
CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_true", {} );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_false", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_false", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "hash miss match");
}
);
CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha1_true", {} );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha512_false", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha512_false", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "hash miss match");
}
);
CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha512_true", {} );
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_ripemd160_false", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_crypto", "assert_ripemd160_false", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "hash miss match");
}
);
......@@ -1157,8 +1161,8 @@ BOOST_FIXTURE_TEST_CASE(math_tests, tester) { try {
CALL_TEST_FUNCTION( *this, "test_math", "test_diveq", fc::raw::pack(act));
}
// test diveq for divide by zero
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_math", "test_diveq_by_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_math", "test_diveq_by_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -1177,8 +1181,8 @@ BOOST_FIXTURE_TEST_CASE(math_tests, tester) { try {
std::copy(d_vals.whole, d_vals.whole+sizeof(d_vals), ds.begin());
CALL_TEST_FUNCTION( *this, "test_math", "test_double_to_i64", ds);
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_math", "test_double_api_div_0", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_math", "test_double_api_div_0", {}), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "divide by zero");
}
);
......@@ -1258,8 +1262,8 @@ BOOST_FIXTURE_TEST_CASE(privileged_tests, tester) { try {
}
CALL_TEST_FUNCTION( *this, "test_privileged", "test_is_privileged", {} );
BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_privileged", "test_is_privileged", {} ), fc::assert_exception,
[](const fc::assert_exception& e) {
BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_privileged", "test_is_privileged", {} ), transaction_exception,
[](const fc::exception& e) {
return expect_assert_message(e, "context.privileged: testapi does not have permission to call this API");
}
);
......
......@@ -104,6 +104,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;
......@@ -176,12 +225,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")));
......
此差异已折叠。
......@@ -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)} );
......@@ -161,7 +187,7 @@ BOOST_FIXTURE_TEST_CASE( test_overspend, currency_tester ) try {
("quantity", "101.0000 CUR")
("memo", "overspend! Alice");
BOOST_CHECK_EXCEPTION(push_action(N(alice), N(transfer), data), fc::assert_exception, assert_message_is("overdrawn balance"));
BOOST_CHECK_EXCEPTION(push_action(N(alice), N(transfer), data), transaction_exception, assert_message_is("overdrawn balance"));
produce_block();
BOOST_REQUIRE_EQUAL(get_balance(N(alice)), asset::from_string( "100.0000 CUR" ));
......@@ -245,18 +271,17 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, tester) try {
fc::assert_exception, assert_message_is("creating symbol from empty string"));
}
// precision part missing
{
BOOST_CHECK_EXCEPTION(symbol::from_string("RND"),
fc::assert_exception, assert_message_is("missing comma in symbol"));
}
// precision part missing
// 0 decimals part
{
BOOST_CHECK_EXCEPTION(symbol::from_string("0,EURO"),
fc::assert_exception, assert_message_is("zero decimals in symbol"));
symbol sym = symbol::from_string("0,EURO");
BOOST_REQUIRE_EQUAL(0, sym.decimals());
BOOST_REQUIRE_EQUAL("EURO", sym.name());
}
// invalid - contains lower case characters, no validation
......@@ -273,10 +298,63 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, tester) try {
fc::assert_exception, assert_message_is("invalid character in symbol name"));
}
// invalid - missing decimal point
// Missing decimal point, should create asset with 0 decimals
{
asset a = asset::from_string("10 CUR");
BOOST_REQUIRE_EQUAL(a.amount, 10);
BOOST_REQUIRE_EQUAL(a.precision(), 1);
BOOST_REQUIRE_EQUAL(a.decimals(), 0);
BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR");
}
// Missing space
{
BOOST_CHECK_EXCEPTION(asset::from_string("10CUR"),
asset_type_exception, assert_message_is("Asset's amount and symbol should be separated with space"));
}
// Precision is not specified when decimal separator is introduced
{
BOOST_CHECK_EXCEPTION(asset::from_string("10. CUR"),
asset_type_exception, assert_message_is("Missing decimal fraction after decimal point"));
}
// Missing symbol
{
BOOST_CHECK_EXCEPTION(asset::from_string("10"),
asset_type_exception, assert_message_is("Asset's amount and symbol should be separated with space"));
}
// Multiple spaces
{
asset a = asset::from_string("1000000000.00000 CUR");
BOOST_REQUIRE_EQUAL(a.amount, 100000000000000);
BOOST_REQUIRE_EQUAL(a.decimals(), 5);
BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR");
}
// Valid asset
{
asset a = asset::from_string("1000000000.00000 CUR");
BOOST_REQUIRE_EQUAL(a.amount, 100000000000000);
BOOST_REQUIRE_EQUAL(a.decimals(), 5);
BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR");
}
// Negative asset
{
asset a = asset::from_string("-001000000.00010 CUR");
BOOST_REQUIRE_EQUAL(a.amount, -100000000010);
BOOST_REQUIRE_EQUAL(a.decimals(), 5);
BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR");
}
// Negative asset below 1
{
BOOST_CHECK_EXCEPTION(asset::from_string("10 CUR"),
fc::assert_exception, assert_message_is("dot missing in asset from string"));
asset a = asset::from_string("-000000000.00100 CUR");
BOOST_REQUIRE_EQUAL(a.amount, -100);
BOOST_REQUIRE_EQUAL(a.decimals(), 5);
BOOST_REQUIRE_EQUAL(a.symbol_name(), "CUR");
}
} FC_LOG_AND_RETHROW() /// test_symbol
......
......@@ -110,7 +110,7 @@ BOOST_FIXTURE_TEST_CASE( basic_test, tester ) try {
trx.sign( get_private_key( N(asserter), "active" ), chain_id_type() );
yes_assert_id = trx.id();
BOOST_CHECK_THROW(push_transaction( trx ), fc::assert_exception);
BOOST_CHECK_THROW(push_transaction( trx ), transaction_exception);
}
produce_blocks(1);
......@@ -820,7 +820,7 @@ BOOST_FIXTURE_TEST_CASE( check_table_maximum, tester ) try {
trx.sign(get_private_key( N(tbl), "active" ), chain_id_type());
//should fail, a check to make sure assert() in wasm is being evaluated correctly
BOOST_CHECK_THROW(push_transaction(trx), fc::assert_exception);
BOOST_CHECK_THROW(push_transaction(trx), transaction_exception);
}
produce_blocks(1);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册