未验证 提交 dda3fa34 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #1678 from EOSIO/dawn-610-cfa-gh#1387

Dawn 610 context free actions
......@@ -15,10 +15,10 @@ extern "C" {
if( code == N(asserter) ) {
if( action == N(procassert) ) {
assertdef check;
read_action(&check, sizeof(assertdef));
read_action_data(&check, sizeof(assertdef));
unsigned char buffer[256];
size_t actsize = read_action(buffer, 256);
size_t actsize = read_action_data(buffer, 256);
assertdef *def = reinterpret_cast<assertdef *>(buffer);
// make sure to null term the string
......
......@@ -73,13 +73,13 @@ extern "C" {
*/
/**
* Copy up to @ref len bytes of current action to the specified location
* @brief Copy current action to the specified location
* @param msg - a pointer where up to @ref len bytes of the current action will be copied
* @param len - len of the current action to be copied
* Copy up to @ref len bytes of current action data to the specified location
* @brief Copy current action data to the specified location
* @param msg - a pointer where up to @ref len bytes of the current action data will be copied
* @param len - len of the current action data to be copied
* @return the number of bytes copied to msg
*/
uint32_t read_action( void* msg, uint32_t len );
uint32_t read_action_data( void* msg, uint32_t len );
/**
* Get the length of the current action's data field
......@@ -87,7 +87,7 @@ extern "C" {
* @brief Get the length of current action's data field
* @return the length of the current action's data field
*/
uint32_t action_size();
uint32_t action_data_size();
/**
* Add the specified account to set of accounts to be notified
......
......@@ -33,21 +33,21 @@ namespace eosio {
* unsigned long long b; //8
* int c; //4
* };
* dummy_action msg = current_action<dummy_action>();
* dummy_action msg = current_action_data<dummy_action>();
* @endcode
*/
template<typename T>
T current_action() {
T current_action_data() {
T value;
auto read = read_action( &value, sizeof(value) );
auto read = read_action_data( &value, sizeof(value) );
eosio_assert( read >= sizeof(value), "action shorter than expected" );
return value;
}
template<typename T>
T unpack_action() {
char buffer[action_size()];
read_action( buffer, sizeof(buffer) );
T unpack_action_data() {
char buffer[action_data_size()];
read_action_data( buffer, sizeof(buffer) );
return unpack<T>( buffer, sizeof(buffer) );
}
......@@ -109,7 +109,6 @@ namespace eosio {
data = pack(value);
}
/**
* @tparam Action - a type derived from action_meta<Scope,Name>
* @param value - will be serialized via pack into data
......@@ -140,6 +139,19 @@ namespace eosio {
auto serialize = pack(*this);
::send_inline(serialize.data(), serialize.size());
}
/**
* Retrieve the unpacked data as T
* @tparam T expected type of data
* @return the action data
*/
template<typename T>
T data_as() {
eosio_assert( name == T::get_name(), "Invalid name" );
eosio_assert( account == T::get_account(), "Invalid account" );
return unpack<T>( &data[0], data.size() );
}
};
template<uint64_t Account, uint64_t Name>
......
......@@ -78,12 +78,12 @@ void ripemd160( char* data, uint32_t length, checksum160* hash );
* returns the number of bytes read into pub
* `digest` should be checksum<256>
*/
int recover_key( checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen );
int recover_key( const checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen );
/**
* Tests a given public key with the generated key from digest and the signature
* `digest` should be checksum<256>
*/
void assert_recover_key( checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen );
void assert_recover_key( const checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen );
}
......@@ -110,15 +110,15 @@ namespace eosio {
switch( act ) {
case N(issue):
print( "issue\n");
on( unpack_action<issue>() );
on( unpack_action_data<issue>() );
return true;
case N(transfer):
print( "transfer\n");
on( unpack_action<transfer>() );
on( unpack_action_data<transfer>() );
return true;
case N(create):
print( "create\n");
on( unpack_action<create>() );
on( unpack_action_data<create>() );
return true;
}
return false;
......
......@@ -9,6 +9,7 @@
#include <boost/container/flat_map.hpp>
#include <eosiolib/varint.hpp>
#include <array>
#include <map>
#include <string>
......@@ -140,7 +141,7 @@ class datastream<size_t> {
* @param d value to serialize
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const key256 d) {
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const key256& d) {
ds.write( (const char*)d.data(), d.size() );
return ds;
}
......@@ -164,7 +165,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, key256& d) {
* @param d value to serialize
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const uint128_t d) {
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const uint128_t& d) {
ds.write( (const char*)&d, sizeof(d) );
return ds;
}
......@@ -187,7 +188,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, uint128_t& d) {
* @param d value to serialize
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const int128_t d) {
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const int128_t& d) {
ds.write( (const char*)&d, sizeof(d) );
return ds;
}
......@@ -413,6 +414,29 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, uint8_t& d) {
return ds;
}
/**
* Serialize a checksum256 into a stream
* @brief Serialize a checksum256
* @param ds stream to write
* @param d value to serialize
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum256& d) {
ds.write( (const char*)&d, sizeof(d) );
return ds;
}
/**
* Deserialize a checksum256 from a stream
* @brief Deserialize a checksum256
* @param ds stream to read
* @param d destination for deserialized value
*/
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, checksum256& d) {
ds.read((char*)&d, sizeof(d) );
return ds;
}
template<typename DataStream>
DataStream& operator << ( DataStream& ds, const std::string& v ) {
ds << unsigned_int( v.size() );
......@@ -445,19 +469,39 @@ DataStream& operator >> ( DataStream& ds, std::array<T,N>& v ) {
return ds;
}
template<typename DataStream, typename T>
DataStream& operator << ( DataStream& ds, const vector<T>& v ) {
ds << unsigned_int( v.size() );
for( const auto& i : v )
ds << i;
return ds;
}
template<typename DataStream, typename T>
DataStream& operator >> ( DataStream& ds, vector<T>& v ) {
unsigned_int s;
ds >> s;
v.resize(s.value);
for( auto& i : v )
ds >> i;
return ds;
}
template<typename DataStream, typename K, typename V>
DataStream& operator<<( DataStream& ds, const boost::container::flat_map<K,V>& m ) {
DataStream& operator << ( DataStream& ds, const std::map<K,V>& m ) {
ds << unsigned_int( m.size() );
for( const auto& i : m )
for( const auto& i : m ) {
ds << i.first << i.second;
}
return ds;
}
template<typename DataStream, typename K, typename V>
DataStream& operator>>( DataStream& ds, boost::container::flat_map<K,V>& m ) {
DataStream& operator >> ( DataStream& ds, std::map<K,V>& m ) {
m.clear();
unsigned_int s; ds >> s;
for( uint32_t i = 0; i < s.value; ++i ) {
for (uint32_t i = 0; i < s.value; ++i) {
K k; V v;
ds >> k >> v;
m.emplace( std::move(k), std::move(v) );
......@@ -465,23 +509,24 @@ DataStream& operator>>( DataStream& ds, boost::container::flat_map<K,V>& m ) {
return ds;
}
template<typename DataStream, typename T>
DataStream& operator << ( DataStream& ds, const vector<T>& v ) {
ds << unsigned_int( v.size() );
for( const auto& i : v )
ds << i;
template<typename DataStream, typename K, typename V>
DataStream& operator<<( DataStream& ds, const boost::container::flat_map<K,V>& m ) {
ds << unsigned_int( m.size() );
for( const auto& i : m )
ds << i.first << i.second;
return ds;
}
template<typename DataStream, typename T>
DataStream& operator >> ( DataStream& ds, vector<T>& v ) {
unsigned_int s;
ds >> s;
v.resize(s.value);
for( auto& i : v )
ds >> i;
template<typename DataStream, typename K, typename V>
DataStream& operator>>( DataStream& ds, boost::container::flat_map<K,V>& m ) {
m.clear();
unsigned_int s; ds >> s;
for( uint32_t i = 0; i < s.value; ++i ) {
K k; V v;
ds >> k >> v;
m.emplace( std::move(k), std::move(v) );
}
return ds;
}
......
......@@ -6,7 +6,7 @@ namespace eosio {
template<typename Contract, typename FirstAction>
bool dispatch( uint64_t code, uint64_t act ) {
if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
Contract().on( unpack_action<FirstAction>() );
Contract().on( unpack_action_data<FirstAction>() );
return true;
}
return false;
......@@ -26,7 +26,7 @@ namespace eosio {
template<typename Contract, typename FirstAction, typename SecondAction, typename... Actions>
bool dispatch( uint64_t code, uint64_t act ) {
if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
Contract().on( unpack_action<FirstAction>() );
Contract().on( unpack_action_data<FirstAction>() );
return true;
}
return eosio::dispatch<Contract,SecondAction,Actions...>( code, act );
......
......@@ -10,14 +10,14 @@ extern "C" {
/**
* @defgroup systemapi System API
* @ingroup contractdev
* @brief Define API for interating with system level intrinsics
* @brief Define API for interacting with system level intrinsics
*
*/
/**
* @defgroup systemcapi System C API
* @ingroup systemapi
* @brief Define API for interating with system level intrinsics
* @brief Define API for interacting with system level intrinsics
*
* @{
*/
......
......@@ -91,5 +91,24 @@ extern "C" {
*/
time expiration();
/**
* Retrieve the indicated action from the active transaction.
* @param type - 0 for context free action, 1 for action
* @param index - the index of the requested action
* @param buff - output packed buff of the action
* @param size - amount of buff read, pass 0 to have size returned
* @return the size of the action, -1 on failure
*/
int get_action( uint32_t type, uint32_t index, char* buff, size_t size );
/**
* Retrieve the signed_transaction.context_free_data[index].
* @param index - the index of the context_free_data entry to retrieve
* @param buff - output buff of the context_free_data entry
* @param size - amount of context_free_data[index] to retrieve into buff
* @return signed_transaction.context_free_data[index].size() or -1 if index not valid
*/
int get_context_free_data( uint32_t index, char* buff, size_t size );
///@ } transactioncapi
}
......@@ -8,6 +8,7 @@
#include <eosiolib/print.hpp>
#include <eosiolib/types.hpp>
#include <eosiolib/serialize.hpp>
#include <vector>
namespace eosio {
......@@ -18,10 +19,9 @@ namespace eosio {
*
* @note There are some methods from the @ref transactioncapi that can be used directly from C++
*
* @{
* @{
*/
class transaction {
public:
transaction(time exp = now() + 60, region_id r = 0)
......@@ -53,13 +53,27 @@ namespace eosio {
time delay_until;
static deferred_transaction from_current_action() {
return unpack_action<deferred_transaction>();
return unpack_action_data<deferred_transaction>();
}
EOSLIB_SERIALIZE_DERIVED( deferred_transaction, transaction, (sender_id)(sender)(delay_until) )
};
///@} transactioncpp api
/**
* Retrieve the indicated action from the active transaction.
* @param type - 0 for context free action, 1 for action
* @param index - the index of the requested action
* @return the indicated action
*/
action get_action( uint32_t type, uint32_t index ) {
auto size = ::get_action(type, index, nullptr, 0);
eosio_assert( size > 0, "get_action size failed" );
char buf[size];
auto size2 = ::get_action(type, index, &buf[0], static_cast<size_t>(size) );
eosio_assert( size == size2, "get_action failed" );
return eosio::unpack<eosio::action>(&buf[0], static_cast<size_t>(size));
}
} // namespace eos
///@} transactioncpp api
} // namespace eos
......@@ -4,8 +4,10 @@
*/
#pragma once
#include <eosiolib/types.h>
#include <functional>
#include <tuple>
namespace eosio {
namespace eosio {
/**
* @brief Converts a base32 symbol into its binary representation, used by string_to_name()
......@@ -89,4 +91,24 @@ namespace eosio {
};
/// @}
} // namespace eos
} // namespace eosio
namespace std {
/**
* @brief provide less for checksum256
*/
template<>
struct less<checksum256> : binary_function<checksum256, checksum256, bool> {
bool operator()( const checksum256& lhs, const checksum256& rhs ) const {
return memcmp(&lhs, &rhs, sizeof(lhs)) < 0;
}
};
} // namespace std
/**
* Provide == for checksum256 in global namespace
*/
bool operator==(const checksum256& lhs, const checksum256& rhs) {
return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
......@@ -201,7 +201,7 @@ namespace eosio {
bool exchange::apply( account_name contract, account_name act ) {
if( act == N(transfer) ) {
on( unpack_action<currency::transfer>(), contract );
on( unpack_action_data<currency::transfer>(), contract );
return true;
}
......@@ -210,28 +210,28 @@ namespace eosio {
switch( act ) {
case N(createx):
on( unpack_action<createx>() );
on( unpack_action_data<createx>() );
return true;
case N(trade):
on( unpack_action<trade>() );
on( unpack_action_data<trade>() );
return true;
case N(lend):
on( unpack_action<lend>() );
on( unpack_action_data<lend>() );
return true;
case N(unlend):
on( unpack_action<unlend>() );
on( unpack_action_data<unlend>() );
return true;
case N(deposit):
on( unpack_action<deposit>() );
on( unpack_action_data<deposit>() );
return true;
case N(withdraw):
on( unpack_action<withdraw>() );
on( unpack_action_data<withdraw>() );
return true;
case N(upmargin):
on( unpack_action<upmargin>() );
on( unpack_action_data<upmargin>() );
return true;
case N(covermargin):
on( unpack_action<covermargin>() );
on( unpack_action_data<covermargin>() );
return true;
default:
return _excurrencies.apply( contract, act );
......
......@@ -92,15 +92,15 @@ extern "C" {
if (action == N(onerror)) {
apply_onerror(deferred_transaction::from_current_action());
} if( action == N(transfer) ) {
apply_transfer(code, unpack_action<eosiosystem::contract<N(eosio.system)>::currency::transfer_memo>());
apply_transfer(code, unpack_action_data<eosiosystem::contract<N(eosio.system)>::currency::transfer_memo>());
}
} else if ( code == N(currency) ) {
if( action == N(transfer) ) {
apply_transfer(code, unpack_action<eosio::currency::transfer>());
apply_transfer(code, unpack_action_data<eosio::currency::transfer>());
}
} else if (code == current_receiver() ) {
if ( action == N(setowner)) {
apply_setowner(current_action<set_owner>());
apply_setowner(current_action_data<set_owner>());
}
}
}
......
......@@ -195,7 +195,7 @@ namespace simpledb {
struct dispatcher_impl<T> {
static bool dispatch(uint64_t action) {
if (action == T::action_name) {
unpack_action<T>().process();
unpack_action_data<T>().process();
return true;
}
......
......@@ -50,8 +50,8 @@ namespace testsystem {
struct set_producers : dispatchable<N(setprods)> {
static void process(const set_producers&) {
char buffer[action_size()];
read_action( buffer, sizeof(buffer) );
char buffer[action_data_size()];
read_action_data( buffer, sizeof(buffer) );
set_active_producers(buffer, sizeof(buffer));
}
};
......@@ -71,7 +71,7 @@ namespace testsystem {
struct dispatcher_impl<T> {
static bool dispatch(uint64_t action) {
if (action == T::action_name) {
T::process(current_action<T>());
T::process(current_action_data<T>());
return true;
}
......
......@@ -3,8 +3,13 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/action.hpp>
#include <eosiolib/transaction.hpp>
#include <eosiolib/chain.h>
#include <eosiolib/db.h>
#include <eosiolib/crypto.h>
#include <eosiolib/privileged.h>
#include <eosiolib/eosio.hpp>
#include <eosiolib/datastream.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/compiler_builtins.h>
......@@ -16,18 +21,18 @@ void test_action::read_action_normal() {
eosio_assert( current_receiver() == N(testapi), "current_receiver() == N(testapi)" );
eosio_assert(action_size() == sizeof(dummy_action), "action_size() == sizeof(dummy_action)");
eosio_assert(action_data_size() == sizeof(dummy_action), "action_size() == sizeof(dummy_action)");
total = read_action(buffer, 30);
total = read_action_data(buffer, 30);
eosio_assert(total == sizeof(dummy_action) , "read_action(30)" );
total = read_action(buffer, 100);
total = read_action_data(buffer, 100);
eosio_assert(total == sizeof(dummy_action) , "read_action(100)" );
total = read_action(buffer, 5);
total = read_action_data(buffer, 5);
eosio_assert(total == 5 , "read_action(5)" );
total = read_action(buffer, sizeof(dummy_action) );
total = read_action_data(buffer, sizeof(dummy_action) );
eosio_assert(total == sizeof(dummy_action), "read_action(sizeof(dummy_action))" );
dummy_action *dummy13 = reinterpret_cast<dummy_action *>(buffer);
......@@ -37,12 +42,93 @@ void test_action::read_action_normal() {
eosio_assert(dummy13->c == DUMMY_ACTION_DEFAULT_C, "dummy13->c == DUMMY_ACTION_DEFAULT_C");
}
void test_action::test_dummy_action() {
char buffer[100];
int total = 0;
// get_action
total = get_action( 1, 0, buffer, 0 );
total = get_action( 1, 0, buffer, static_cast<size_t>(total) );
eosio_assert( total > 0, "get_action failed" );
eosio::action act = eosio::get_action( 1, 0 );
eosio_assert( eosio::pack_size(act) == static_cast<size_t>(total), "pack_size does not match get_action size" );
eosio_assert( act.account == N(testapi), "expected testapi account" );
dummy_action dum13 = act.data_as<dummy_action>();
if ( dum13.b == 200 ) {
// attempt to access context free only api
get_context_free_data( 0, nullptr, 0 );
eosio_assert(false, "get_context_free_data() not allowed in non-context free action");
} else {
eosio_assert(dum13.a == DUMMY_ACTION_DEFAULT_A, "dum13.a == DUMMY_ACTION_DEFAULT_A");
eosio_assert(dum13.b == DUMMY_ACTION_DEFAULT_B, "dum13.b == DUMMY_ACTION_DEFAULT_B");
eosio_assert(dum13.c == DUMMY_ACTION_DEFAULT_C, "dum13.c == DUMMY_ACTION_DEFAULT_C");
}
}
void test_action::read_action_to_0() {
read_action((void *)0, action_size());
read_action_data((void *)0, action_data_size());
}
void test_action::read_action_to_64k() {
read_action( (void *)((1<<16)-2), action_size());
read_action_data( (void *)((1<<16)-2), action_data_size());
}
void test_action::test_cf_action() {
eosio::action act = eosio::get_action( 0, 0 );
cf_action cfa = act.data_as<cf_action>();
if ( cfa.payload == 100 ) {
// verify read of get_context_free_data, also verifies system api access
int size = get_context_free_data( cfa.cfd_idx, nullptr, 0 );
eosio_assert( size > 0, "size determination failed" );
eosio::bytes cfd( static_cast<size_t>(size) );
size = get_context_free_data( cfa.cfd_idx, &cfd[0], static_cast<size_t>(size) );
eosio_assert(static_cast<size_t>(size) == cfd.size(), "get_context_free_data failed" );
uint32_t v = eosio::unpack<uint32_t>( &cfd[0], cfd.size() );
eosio_assert( v == cfa.payload, "invalid value" );
// verify crypto api access
checksum256 hash;
char test[] = "test";
sha256( test, sizeof(test), &hash );
assert_sha256( test, sizeof(test), &hash );
// verify action api access
action_data_size();
// verify console api access
eosio::print("test\n");
// verify memory api access
uint32_t i = 42;
memccpy(&v, &i, sizeof(i), sizeof(i));
// verify transaction api access
eosio_assert(transaction_size() > 0, "transaction_size failed");
} else if ( cfa.payload == 200 ) {
// attempt to access non context free api, privileged_api
is_privileged(act.name);
eosio_assert( false, "privileged_api should not be allowed" );
} else if ( cfa.payload == 201 ) {
// attempt to access non context free api, producer_api
get_active_producers( nullptr, 0 );
eosio_assert( false, "producer_api should not be allowed" );
} else if ( cfa.payload == 202 ) {
// attempt to access non context free api, db_api
db_store_i64( N(testapi), N(testapi), N(testapi), 0, "test", 4 );
eosio_assert( false, "db_api should not be allowed" );
} else if ( cfa.payload == 203 ) {
// attempt to access non context free api, db_api
uint64_t i = 0;
db_idx64_store( N(testapi), N(testapi), N(testapi), 0, &i );
eosio_assert( false, "db_api should not be allowed" );
} else if ( cfa.payload == 204 ) {
// attempt to access non context free api, send action
eosio::action dum_act;
dum_act.send();
eosio_assert( false, "action send should not be allowed" );
}
}
void test_action::require_notice() {
......@@ -78,26 +164,26 @@ void test_action::test_abort() {
void test_action::test_publication_time() {
uint32_t pub_time = 0;
read_action(&pub_time, sizeof(uint32_t));
read_action_data(&pub_time, sizeof(uint32_t));
eosio_assert( pub_time == publication_time(), "pub_time == publication_time()" );
}
void test_action::test_current_receiver() {
account_name cur_rec;
read_action(&cur_rec, sizeof(account_name));
read_action_data(&cur_rec, sizeof(account_name));
eosio_assert( current_receiver() == cur_rec, "the current receiver does not match" );
}
void test_action::test_current_sender() {
account_name cur_send;
read_action(&cur_send, sizeof(account_name));
read_action_data(&cur_send, sizeof(account_name));
eosio_assert( current_sender() == cur_send, "the current sender does not match" );
}
void test_action::now() {
uint32_t tmp = 0;
uint32_t total = read_action(&tmp, sizeof(uint32_t));
uint32_t total = read_action_data(&tmp, sizeof(uint32_t));
eosio_assert( total == sizeof(uint32_t), "total == sizeof(uint32_t)");
eosio_assert( tmp == ::now(), "tmp == now()" );
}
......@@ -60,6 +60,16 @@ extern "C" {
WASM_TEST_HANDLER(test_action, test_current_sender);
WASM_TEST_HANDLER(test_action, test_publication_time);
// test named actions
// We enforce action name matches action data type name, so name mangling will not work for these tests.
if ( action == N(dummy_action) ) {
test_action::test_dummy_action();
return;
} else if ( action == N(cf_action) ) {
test_action::test_cf_action();
return;
}
//test_print
WASM_TEST_HANDLER(test_print, test_prints);
WASM_TEST_HANDLER(test_print, test_prints_l);
......
......@@ -3,6 +3,8 @@
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/serialize.hpp>
#include <string>
typedef unsigned long long u64;
typedef unsigned int u32;
......@@ -27,14 +29,37 @@ static constexpr u64 WASM_TEST_ACTION(const char* cls, const char* method)
#pragma pack(push, 1)
struct dummy_action {
static uint64_t get_name() {
return N(dummy_action);
}
static uint64_t get_account() {
return N(testapi);
}
char a; //1
unsigned long long b; //8
int c; //4
uint64_t b; //8
int32_t c; //4
EOSLIB_SERIALIZE( dummy_action, (a)(b)(c) )
};
struct u128_action {
unsigned __int128 values[3]; //16*3
};
struct cf_action {
static uint64_t get_name() {
return N(cf_action);
}
static uint64_t get_account() {
return N(testapi);
}
uint32_t payload = 100;
uint32_t cfd_idx = 0; // context free data index
EOSLIB_SERIALIZE( cf_action, (payload)(cfd_idx) )
};
#pragma pack(pop)
static_assert( sizeof(dummy_action) == 13 , "unexpected packing" );
......@@ -65,6 +90,8 @@ struct test_action {
static void read_action_normal();
static void read_action_to_0();
static void read_action_to_64k();
static void test_dummy_action();
static void test_cf_action();
static void require_notice();
static void require_auth();
static void assert_false();
......
......@@ -16,7 +16,7 @@ struct producers {
void test_chain::test_activeprods() {
producers act_prods;
read_action(&act_prods, sizeof(producers));
read_action_data(&act_prods, sizeof(producers));
eosio_assert(act_prods.len == 21, "producers.len != 21");
......
......@@ -193,20 +193,20 @@ struct sig_hash_key {
void test_crypto::test_recover_key_assert_true() {
sig_hash_key sh;
read_action( (char*)&sh, sizeof(sh) );
read_action_data( (char*)&sh, sizeof(sh) );
assert_recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), (const char*)&sh.pk, sizeof(sh.pk) );
}
void test_crypto::test_recover_key_assert_false() {
sig_hash_key sh;
read_action( (char*)&sh, sizeof(sh) );
read_action_data( (char*)&sh, sizeof(sh) );
assert_recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), (const char*)&sh.pk, sizeof(sh.pk) );
eosio_assert( false, "should have thrown an error" );
}
void test_crypto::test_recover_key() {
sig_hash_key sh;
read_action( (char*)&sh, sizeof(sh) );
read_action_data( (char*)&sh, sizeof(sh) );
public_key pk;
recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), pk.data, sizeof(pk) );
for ( uint32_t i=0; i < sizeof(pk); i++ )
......
......@@ -6,7 +6,7 @@
void test_math::test_multeq() {
u128_action act;
auto n = read_action(&act, sizeof(u128_action));
auto n = read_action_data(&act, sizeof(u128_action));
eosio_assert( n == sizeof(u128_action), "test_multeq n == sizeof(u128_action)" );
uint128_t self = *(act.values);
......@@ -17,7 +17,7 @@ void test_math::test_multeq() {
void test_math::test_diveq() {
u128_action act;
auto n = read_action(&act, sizeof(u128_action));
auto n = read_action_data(&act, sizeof(u128_action));
eosio_assert( n == sizeof(u128_action), "test_diveq n == sizeof(u128_action)" );
uint128_t self = *(act.values);
......@@ -37,7 +37,7 @@ void test_math::test_diveq_by_0() {
void test_math::test_i64_to_double()
{
uint64_t i[4];
read_action(&i, sizeof(i));
read_action_data(&i, sizeof(i));
uint64_t d = i64_to_double(2);
eosio_assert(i[0] == d, "test_i64_to_double i[0] == d");
......@@ -58,7 +58,7 @@ void test_math::test_i64_to_double()
void test_math::test_double_to_i64()
{
uint64_t d[4];
read_action(&d, sizeof(d));
read_action_data(&d, sizeof(d));
int64_t i = (int64_t)double_to_i64(d[0]);
eosio_assert(2 == i, "test_double_to_i64 2 == i");
......
......@@ -103,7 +103,7 @@ void test_transaction::send_action_large() {
*/
void test_transaction::send_action_recurse() {
char buffer[1024];
read_action(buffer, 1024);
read_action_data(buffer, 1024);
test_action_action<N(testapi), WASM_TEST_ACTION("test_transaction", "send_action_recurse")> test_action;
copy_data(buffer, 1024, test_action.data);
......@@ -125,13 +125,13 @@ void test_transaction::send_action_inline_fail() {
void test_transaction::test_tapos_block_prefix() {
int tbp;
read_action( (char*)&tbp, sizeof(int) );
read_action_data( (char*)&tbp, sizeof(int) );
eosio_assert( tbp == tapos_block_prefix(), "tapos_block_prefix does not match" );
}
void test_transaction::test_tapos_block_num() {
int tbn;
read_action( (char*)&tbn, sizeof(int) );
read_action_data( (char*)&tbn, sizeof(int) );
eosio_assert( tbn == tapos_block_num(), "tapos_block_num does not match" );
}
......@@ -147,7 +147,7 @@ void test_transaction::test_read_transaction() {
void test_transaction::test_transaction_size() {
uint32_t trans_size = 0;
read_action( (char*)&trans_size, sizeof(uint32_t) );
read_action_data( (char*)&trans_size, sizeof(uint32_t) );
eosio_assert( trans_size == transaction_size(), "transaction size does not match" );
}
......@@ -164,7 +164,7 @@ void test_transaction::send_transaction() {
void test_transaction::send_action_sender() {
account_name cur_send;
read_action( &cur_send, sizeof(account_name) );
read_action_data( &cur_send, sizeof(account_name) );
test_action_action<N(testapi), WASM_TEST_ACTION("test_action", "test_current_sender")> test_action;
copy_data((char*)&cur_send, sizeof(account_name), test_action.data);
......
......@@ -353,9 +353,9 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b
if( buffer_size == 0 ) return s;
if( buffer_size < s )
memcpy( buffer, trx_meta.context_free_data.data(), buffer_size );
memcpy( buffer, trx_meta.context_free_data[index].data(), buffer_size );
else
memcpy( buffer, trx_meta.context_free_data.data(), s );
memcpy( buffer, trx_meta.context_free_data[index].data(), s );
return s;
}
......
......@@ -737,9 +737,9 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction&
}
void chain_controller::check_authorization( const vector<action>& actions,
flat_set<public_key_type> provided_keys,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures,
flat_set<account_name> provided_accounts )const
flat_set<account_name> provided_accounts )const
{
auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
get_global_properties().configuration.max_authority_depth,
......
......@@ -25,32 +25,6 @@
namespace eosio { namespace chain { namespace contracts {
void intialize_eosio_tokens(chainbase::database& db, const account_name& system_account, share_type initial_tokens) {
const auto& t_id = db.create<contracts::table_id_object>([&](contracts::table_id_object &t_id){
t_id.scope = system_account;
t_id.code = config::system_account_name;
t_id.table = N(currency);
});
db.create<key_value_object>([&](key_value_object &o){
o.t_id = t_id.id;
o.primary_key = N(account);
o.value.insert(0, reinterpret_cast<const char *>(&initial_tokens), sizeof(share_type));
});
}
static void modify_eosio_balance( apply_context& context, const account_name& account, share_type amt) {
const auto& t_id = context.find_or_create_table(config::system_account_name, account, N(currency));
uint64_t key = N(account);
share_type balance = 0;
context.front_record<key_value_index, by_scope_primary>(t_id, &key, (char *)&balance, sizeof(balance));
balance += amt;
context.store_record<key_value_object>(t_id, config::system_account_name, &key, (const char *)&balance, sizeof(balance));
}
void validate_authority_precondition( const apply_context& context, const authority& auth ) {
for(const auto& a : auth.accounts) {
context.db.get<account_object, by_name>(a.permission.actor);
......@@ -62,7 +36,7 @@ void validate_authority_precondition( const apply_context& context, const author
* This method is called assuming precondition_system_newaccount succeeds a
*/
void apply_eosio_newaccount(apply_context& context) {
auto create = context.act.as<newaccount>();
auto create = context.act.data_as<newaccount>();
try {
context.require_authorization(create.creator);
context.require_write_lock( config::eosio_auth_scope );
......@@ -106,7 +80,7 @@ void apply_eosio_newaccount(apply_context& context) {
void apply_eosio_setcode(apply_context& context) {
auto& db = context.mutable_db;
auto act = context.act.as<setcode>();
auto act = context.act.data_as<setcode>();
context.require_authorization(act.account);
context.require_write_lock( config::eosio_auth_scope );
......@@ -138,7 +112,7 @@ void apply_eosio_setcode(apply_context& context) {
void apply_eosio_setabi(apply_context& context) {
auto& db = context.mutable_db;
auto act = context.act.as<setabi>();
auto act = context.act.data_as<setabi>();
context.require_authorization(act.account);
......@@ -161,7 +135,7 @@ void apply_eosio_setabi(apply_context& context) {
void apply_eosio_updateauth(apply_context& context) {
context.require_write_lock( config::eosio_auth_scope );
auto update = context.act.as<updateauth>();
auto update = context.act.data_as<updateauth>();
EOS_ASSERT(!update.permission.empty(), action_validate_exception, "Cannot create authority with empty name");
EOS_ASSERT(update.permission != update.parent, action_validate_exception,
"Cannot set an authority as its own parent");
......@@ -237,7 +211,7 @@ void apply_eosio_updateauth(apply_context& context) {
}
void apply_eosio_deleteauth(apply_context& context) {
auto remove = context.act.as<deleteauth>();
auto remove = context.act.data_as<deleteauth>();
EOS_ASSERT(remove.permission != "active", action_validate_exception, "Cannot delete active authority");
EOS_ASSERT(remove.permission != "owner", action_validate_exception, "Cannot delete owner authority");
......@@ -263,7 +237,7 @@ void apply_eosio_deleteauth(apply_context& context) {
}
void apply_eosio_linkauth(apply_context& context) {
auto requirement = context.act.as<linkauth>();
auto requirement = context.act.data_as<linkauth>();
EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty");
context.require_authorization(requirement.account);
......@@ -294,7 +268,7 @@ void apply_eosio_linkauth(apply_context& context) {
void apply_eosio_unlinkauth(apply_context& context) {
auto& db = context.mutable_db;
auto unlink = context.act.as<unlinkauth>();
auto unlink = context.act.data_as<unlinkauth>();
context.require_authorization(unlink.account);
......@@ -370,7 +344,7 @@ void apply_eosio_postrecovery(apply_context& context) {
FC_ASSERT(context.act.authorization.size() == 1, "Recovery Message must have exactly one authorization");
auto recover_act = context.act.as<postrecovery>();
auto recover_act = context.act.data_as<postrecovery>();
const auto &auth = context.act.authorization.front();
const auto& account = recover_act.account;
context.require_write_lock(account);
......@@ -447,7 +421,7 @@ static void remove_pending_recovery(apply_context& context, const account_name&
}
void apply_eosio_passrecovery(apply_context& context) {
auto pass_act = context.act.as<passrecovery>();
auto pass_act = context.act.data_as<passrecovery>();
const auto& account = pass_act.account;
// ensure this is only processed if it is a deferred transaction from the system account
......@@ -470,7 +444,7 @@ void apply_eosio_passrecovery(apply_context& context) {
void apply_eosio_vetorecovery(apply_context& context) {
context.require_write_lock( config::eosio_auth_scope );
auto pass_act = context.act.as<vetorecovery>();
auto pass_act = context.act.data_as<vetorecovery>();
const auto& account = pass_act.account;
context.require_authorization(account);
......
......@@ -277,15 +277,17 @@ namespace eosio { namespace chain {
/**
* @param actions - the actions to check authorization across
* @param provided_keys - the set of public keys which have authorized the transaction
* @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
*/
void check_authorization( const vector<action>& actions,
flat_set<public_key_type> provided_keys,
bool allow_unused_signatures = false,
flat_set<account_name> provided_accounts = flat_set<account_name>()
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures = false,
flat_set<account_name> provided_accounts = flat_set<account_name>()
)const;
......
......@@ -212,6 +212,7 @@ namespace impl {
static void add(mutable_variant_object &out, const char* name, const packed_transaction& ptrx, Resolver resolver) {
mutable_variant_object mvo;
mvo("signatures", ptrx.signatures);
mvo("context_free_data", ptrx.context_free_data);
mvo("compression", ptrx.compression);
mvo("hex_data", ptrx.data);
......@@ -341,6 +342,9 @@ namespace impl {
FC_ASSERT(vo.contains("signatures"));
FC_ASSERT(vo.contains("compression"));
from_variant(vo["signatures"], ptrx.signatures);
if ( vo.contains("context_free_data")) {
from_variant(vo["context_free_data"], ptrx.context_free_data);
}
from_variant(vo["compression"], ptrx.compression);
if (vo.contains("hex_data") && vo["hex_data"].is_string() && !vo["hex_data"].as_string().empty()) {
......
......@@ -62,7 +62,7 @@ namespace eosio { namespace chain {
}
template<typename T>
T as()const {
T data_as()const {
FC_ASSERT( account == T::get_account() );
FC_ASSERT( name == T::get_name() );
return fc::raw::unpack<T>(data);
......@@ -148,14 +148,15 @@ namespace eosio { namespace chain {
signed_transaction() = default;
// signed_transaction( const signed_transaction& ) = default;
// signed_transaction( signed_transaction&& ) = default;
signed_transaction( transaction&& trx, const vector<signature_type>& signatures)
signed_transaction( transaction&& trx, const vector<signature_type>& signatures, const vector<bytes>& context_free_data)
: transaction(std::forward<transaction>(trx))
, signatures(signatures)
, context_free_data(context_free_data)
{
}
vector<signature_type> signatures;
vector<vector<char>> context_free_data; ///< for each context-free action, there is an entry here
vector<bytes> context_free_data; ///< for each context-free action, there is an entry here
const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id);
signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const;
......@@ -177,17 +178,20 @@ namespace eosio { namespace chain {
explicit packed_transaction(const signed_transaction& t, compression_type _compression = none)
:signatures(t.signatures)
,context_free_data(t.context_free_data)
{
set_transaction(t, _compression);
}
explicit packed_transaction(signed_transaction&& t, compression_type _compression = none)
:signatures(std::move(t.signatures))
,context_free_data(std::move(t.context_free_data))
{
set_transaction(t, _compression);
}
vector<signature_type> signatures;
vector<bytes> context_free_data;
compression_type compression;
bytes data;
......
......@@ -27,7 +27,7 @@ class transaction_metadata {
// things for packed_transaction
optional<bytes> raw_trx;
optional<transaction> decompressed_trx;
vector<vector<char>> context_free_data;
vector<bytes> context_free_data;
// things for signed/packed transactions
optional<flat_set<public_key_type>> signing_keys;
......
......@@ -204,7 +204,7 @@ transaction packed_transaction::get_transaction()const
signed_transaction packed_transaction::get_signed_transaction() const
{
return signed_transaction(get_transaction(), signatures);
return signed_transaction(get_transaction(), signatures, context_free_data);
}
void packed_transaction::set_transaction(const transaction& t, packed_transaction::compression_type _compression)
......
......@@ -7,6 +7,7 @@ namespace eosio { namespace chain {
transaction_metadata::transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published )
:raw_trx(t.get_raw_transaction())
,decompressed_trx(fc::raw::unpack<transaction>(*raw_trx))
,context_free_data(t.context_free_data)
,id(decompressed_trx->id())
,bandwidth_usage( (uint32_t)fc::raw::pack_size(t) )
,published(published)
......
......@@ -378,6 +378,7 @@ class context_free_api : public context_aware_api {
return context.get_context_free_data( index, buffer, buffer_size );
}
};
class privileged_api : public context_aware_api {
public:
privileged_api( wasm_interface& wasm )
......@@ -470,7 +471,8 @@ class privileged_api : public context_aware_api {
class checktime_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
explicit checktime_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
void checktime(uint32_t instruction_count) {
context.checktime(instruction_count);
......@@ -492,13 +494,14 @@ class producer_api : public context_aware_api {
class crypto_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
explicit crypto_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
/**
* This method can be optimized out during replay as it has
* no possible side effects other than "passing".
*/
void assert_recover_key( fc::sha256& digest,
void assert_recover_key( const fc::sha256& digest,
array_ptr<char> sig, size_t siglen,
array_ptr<char> pub, size_t publen ) {
fc::crypto::signature s;
......@@ -513,7 +516,7 @@ class crypto_api : public context_aware_api {
FC_ASSERT( check == p, "Error expected key different than recovered key" );
}
int recover_key( fc::sha256& digest,
int recover_key( const fc::sha256& digest,
array_ptr<char> sig, size_t siglen,
array_ptr<char> pub, size_t publen ) {
fc::crypto::signature s;
......@@ -576,7 +579,8 @@ class string_api : public context_aware_api {
class system_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
explicit system_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
void abort() {
edump(("abort() called"));
......@@ -598,16 +602,17 @@ class system_api : public context_aware_api {
class action_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
action_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
int read_action(array_ptr<char> memory, size_t size) {
int read_action_data(array_ptr<char> memory, size_t size) {
FC_ASSERT(size > 0);
int minlen = std::min<size_t>(context.act.data.size(), size);
memcpy((void *)memory, context.act.data.data(), minlen);
return minlen;
}
int action_size() {
int action_data_size() {
return context.act.data.size();
}
......@@ -630,7 +635,8 @@ class action_api : public context_aware_api {
class console_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
console_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
void prints(null_terminated_ptr str) {
context.console_append<const char*>(str);
......@@ -1335,8 +1341,8 @@ class compiler_builtins : public context_aware_api {
class math_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
math_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
void diveq_i128(unsigned __int128* self, const unsigned __int128* other) {
fc::uint128_t s(*self);
......@@ -1538,8 +1544,8 @@ REGISTER_INTRINSICS(system_api,
);
REGISTER_INTRINSICS(action_api,
(read_action, int(int, int) )
(action_size, int() )
(read_action_data, int(int, int) )
(action_data_size, int() )
(current_receiver, int64_t() )
(publication_time, int32_t() )
(current_sender, int64_t() )
......
......@@ -46,7 +46,8 @@ namespace eosio { namespace testing {
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);
transaction_trace push_nonce( account_name from, const string& v = "blah" );
// use when just want any old non-context free action
transaction_trace push_dummy(account_name from, const string& v = "blah");
transaction_trace transfer( account_name from, account_name to, asset amount, string memo, account_name currency );
transaction_trace transfer( account_name from, account_name to, string amount, string memo, account_name currency );
......
......@@ -190,17 +190,28 @@ namespace eosio { namespace testing {
}
}
transaction_trace base_tester::push_nonce(account_name from, const string& v) {
transaction_trace base_tester::push_dummy(account_name from, const string& v) {
// use reqauth for a normal action, this could be anything
variant pretty_trx = fc::mutable_variant_object()
("actions", fc::variants({
fc::mutable_variant_object()
("account", name(config::system_account_name))
("name", "nonce")
("name", "reqauth")
("authorization", fc::variants({
fc::mutable_variant_object()
("actor", from)
("permission", name(config::active_name))
}))
("data", fc::mutable_variant_object()
("from", from)
)
})
)
// lets also push a context free action, the multi chain test will then also include a context free action
("context_free_actions", fc::variants({
fc::mutable_variant_object()
("account", name(config::system_account_name))
("name", "nonce")
("data", fc::mutable_variant_object()
("value", v)
)
......
......@@ -344,7 +344,7 @@ void account_history_plugin_impl::applied_block(const chain::block_trace& trace)
{
if (act_trace.act.name == NEW_ACCOUNT)
{
const auto create = act_trace.act.as<chain::contracts::newaccount>();
const auto create = act_trace.act.data_as<chain::contracts::newaccount>();
add(db, create.owner.keys, create.name, OWNER);
add(db, create.active.keys, create.name, ACTIVE);
add(db, create.recovery.keys, create.name, RECOVERY);
......@@ -355,7 +355,7 @@ void account_history_plugin_impl::applied_block(const chain::block_trace& trace)
}
else if (act_trace.act.name == UPDATE_AUTH)
{
const auto update = act_trace.act.as<chain::contracts::updateauth>();
const auto update = act_trace.act.data_as<chain::contracts::updateauth>();
remove<public_key_history_multi_index, by_account_permission>(db, update.account, update.permission);
add(db, update.data.keys, update.account, update.permission);
......@@ -364,7 +364,7 @@ void account_history_plugin_impl::applied_block(const chain::block_trace& trace)
}
else if (act_trace.act.name == DELETE_AUTH)
{
const auto del = act_trace.act.as<chain::contracts::deleteauth>();
const auto del = act_trace.act.data_as<chain::contracts::deleteauth>();
remove<public_key_history_multi_index, by_account_permission>(db, del.account, del.permission);
remove<account_control_history_multi_index, by_controlled_authority>(db, del.account, del.permission);
......
......@@ -650,7 +650,7 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) {
} else if (msg.name == newaccount) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
auto newaccount = msg.as<chain::contracts::newaccount>();
auto newaccount = msg.data_as<chain::contracts::newaccount>();
// create new account
bsoncxx::builder::stream::document doc{};
......@@ -667,7 +667,7 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) {
} else if (msg.name == setabi) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
auto setabi = msg.as<chain::contracts::setabi>();
auto setabi = msg.data_as<chain::contracts::setabi>();
auto from_account = find_account(accounts, setabi.account);
document update_from{};
......
......@@ -212,7 +212,7 @@ fc::variant push_transaction( signed_transaction& trx, packed_transaction::compr
trx.set_reference_block(info.head_block_id);
if (tx_force_unique) {
trx.actions.emplace_back( generate_nonce() );
trx.context_free_actions.emplace_back( generate_nonce() );
}
if (!tx_skip_sign) {
......
......@@ -84,7 +84,7 @@ FC_REFLECT_TEMPLATE((uint64_t T), test_chain_action<T>, BOOST_PP_SEQ_NIL);
bool expect_assert_message(const fc::exception& ex, string expected) {
BOOST_TEST_MESSAGE("LOG : " << ex.get_log().at(0).get_message());
BOOST_TEST_MESSAGE("LOG : " << "expected: " << expected << ", actual: " << ex.get_log().at(0).get_message());
return (ex.get_log().at(0).get_message().find(expected) != std::string::npos);
}
......@@ -120,6 +120,25 @@ string U128Str(unsigned __int128 i)
return fc::variant(fc::uint128_t(i)).get_string();
}
template <typename T>
void CallAction(tester& test, T ac, const vector<account_name>& scope = {N(testapi)}) {
signed_transaction trx;
auto pl = vector<permission_level>{{scope[0], config::active_name}};
if (scope.size() > 1)
for (int i = 1; i < scope.size(); i++)
pl.push_back({scope[i], config::active_name});
action act(pl, ac);
trx.actions.push_back(act);
test.set_tapos(trx);
auto sigs = trx.sign(test.get_private_key(scope[0], "active"), chain_id_type());
trx.get_signature_keys(chain_id_type());
auto res = test.push_transaction(trx);
BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed);
test.produce_block();
}
template <typename T>
void CallFunction(tester& test, T ac, const vector<char>& data, const vector<account_name>& scope = {N(testapi)}) {
......@@ -364,6 +383,89 @@ BOOST_FIXTURE_TEST_CASE(action_tests, tester) { try {
}
);
dummy_action da = { DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C };
CallAction(*this, da);
} FC_LOG_AND_RETHROW() }
/*************************************************************************************
* context free action tests
*************************************************************************************/
BOOST_FIXTURE_TEST_CASE(cf_action_tests, tester) { try {
produce_blocks(2);
create_account( N(testapi) );
produce_blocks(1000);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
cf_action cfa;
signed_transaction trx;
action act({}, cfa);
trx.context_free_actions.push_back(act);
trx.context_free_data.emplace_back(fc::raw::pack<uint32_t>(100)); // verify payload matches context free data
trx.context_free_data.emplace_back(fc::raw::pack<uint32_t>(200));
set_tapos(trx);
// signing a transaction with only context_free_actions should not be allowed
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) {
return expect_assert_message(e, "signatures");
}
);
// clear signatures, so should now pass
trx.signatures.clear();
auto res = push_transaction(trx);
BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed);
// add a normal action along with cfa
dummy_action da = { DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C };
auto pl = vector<permission_level>{{N(testapi), config::active_name}};
action act1(pl, da);
trx.actions.push_back(act1);
// run normal passing case
sigs = trx.sign(get_private_key(N(testapi), "active"), chain_id_type());
res = push_transaction(trx);
BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed);
// attempt to access context free api in non context free action
da = { DUMMY_ACTION_DEFAULT_A, 200, DUMMY_ACTION_DEFAULT_C };
action act2(pl, da);
trx.signatures.clear();
trx.actions.clear();
trx.actions.push_back(act2);
// 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) {
return expect_assert_message(e, "may only be called from context_free");
}
);
// back to normal action
trx.signatures.clear();
trx.actions.clear();
trx.actions.push_back(act1);
// attempt to access non context free api
for (uint32_t i = 200; i <= 204; ++i) {
trx.context_free_actions.clear();
trx.context_free_data.clear();
cfa.payload = i;
cfa.cfd_idx = 1;
action cfa_act({}, cfa);
trx.context_free_actions.emplace_back(cfa_act);
trx.signatures.clear();
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) {
return expect_assert_message(e, "context_free: only context free api's can be used in this context");
}
);
}
produce_block();
} FC_LOG_AND_RETHROW() }
......@@ -485,7 +587,8 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, tester) { try {
// test send_action_large
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), fc::assert_exception,
[](const fc::assert_exception& e) {
return expect_assert_message(e, "data_len < config::default_max_inline_action_size: inline action too big");
return expect_assert_message(e, "abort()");
//return expect_assert_message(e, "data_len < config::default_max_inline_action_size: inline action too big");
}
);
......
......@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE( push_block ) { try {
test1.create_account(N(alice));
test2.control->push_block(test1.produce_block());
test1.push_nonce(N(alice), "Foo!");
test1.push_dummy(N(alice), "Foo!");
test2.control->push_block(test1.produce_block());
} FC_LOG_AND_RETHROW() }/// schedule_test
......
......@@ -246,11 +246,11 @@ BOOST_FIXTURE_TEST_CASE( prove_action_in_block, tester ) { try {
produce_blocks(50);
push_nonce( N(alice), "AB" );
push_nonce( N(bob), "BC" );
push_nonce( N(carol), "CD" );
push_nonce( N(david), "DE" );
push_nonce( N(elvis), "EF" );
push_dummy(N(alice), "AB");
push_dummy(N(bob), "BC");
push_dummy(N(carol), "CD");
push_dummy(N(david), "DE");
push_dummy(N(elvis), "EF");
produce_blocks(50);
digest_type block_mroot = process_merkle(nodes, move(block_leaves));
......
......@@ -162,7 +162,12 @@ class Node(object):
jStr=Node.filterJsonObject(retStr)
trace and Utils.Print ("RAW > %s"% retStr)
trace and Utils.Print ("JSON> %s"% jStr)
jsonData=json.loads(jStr)
try:
jsonData=json.loads(jStr)
except json.decoder.JSONDecodeError as ex:
Utils.Print ("RAW > %s"% retStr)
Utils.Print ("JSON> %s"% jStr)
return jsonData
@staticmethod
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册