提交 0eca825f 编写于 作者: K Khaled Al-Hassanieh

Merge branch 'slim' of github.com:EOSIO/eos into slim

......@@ -6,11 +6,6 @@
#include <eosiolib/types.hpp>
#include <eosiolib/action.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/math.hpp>
#include <eosiolib/multi_index.hpp>
#include <eosiolib/dispatcher.hpp>
#include <eosiolib/contract.hpp>
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/system.h>
extern "C" {
/**
* @defgroup mathcapi Math C API
* @brief Defines basic mathematical operations for higher abstractions to use.
* @ingroup mathapi
*
* @{
*/
/**
* Multiply two 128 bit unsigned integers and assign the value to the first parameter.
* @brief Multiply two 128 unsigned bit integers. Throws exception if pointers are invalid.
* @param self Pointer to the value to be multiplied. It will be replaced with the result.
* @param other Pointer to the Value to be multiplied.
*
* Example:
* @code
* uint128_t self(100);
* uint128_t other(100);
* multeq_i128(&self, &other);
* printi128(self); // Output: 10000
* @endcode
*/
void multeq_i128( uint128_t* self, const uint128_t* other );
/**
* Divide two 128 bit unsigned integers and assign the value to the first parameter.
* It will throw an exception if the value of other is zero.
* @brief Divide two 128 unsigned bit integers and throws an exception in case of invalid pointers
* @param self Pointer to numerator. It will be replaced with the result
* @param other Pointer to denominator
* Example:
* @code
* uint128_t self(100);
* uint128_t other(100);
* diveq_i128(&self, &other);
* printi128(self); // Output: 1
* @endcode
*/
void diveq_i128 ( uint128_t* self, const uint128_t* other );
/**
* Get the result of addition between two double interpreted as 64 bit unsigned integer
* This function will first reinterpret_cast both inputs to double (50 decimal digit precision), add them together, and reinterpret_cast the result back to 64 bit unsigned integer.
* @brief Addition between two double
* @param a Value in double interpreted as 64 bit unsigned integer
* @param b Value in double interpreted as 64 bit unsigned integer
* @return Result of addition reinterpret_cast to 64 bit unsigned integers
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(5), i64_to_double(10) );
* uint64_t b = double_div( i64_to_double(5), i64_to_double(2) );
* uint64_t res = double_add( a, b );
* printd(res); // Output: 3
* @endcode
*/
uint64_t double_add(uint64_t a, uint64_t b);
/**
* Get the result of multiplication between two double interpreted as 64 bit unsigned integer
* This function will first reinterpret_cast both inputs to double (50 decimal digit precision), multiply them together, and reinterpret_cast the result back to 64 bit unsigned integer.
* @brief Multiplication between two double
* @param a Value in double interpreted as 64 bit unsigned integer
* @param b Value in double interpreted as 64 bit unsigned integer
* @return Result of multiplication reinterpret_cast to 64 bit unsigned integers
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(10), i64_to_double(10) );
* uint64_t b = double_div( i64_to_double(5), i64_to_double(2) );
* uint64_t res = double_mult( a, b );
* printd(res); // Output: 2.5
* @endcode
*/
uint64_t double_mult(uint64_t a, uint64_t b);
/**
* Get the result of division between two double interpreted as 64 bit unsigned integer
* This function will first reinterpret_cast both inputs to double (50 decimal digit precision), divide numerator with denominator, and reinterpret_cast the result back to 64 bit unsigned integer.
* Throws an error if b is zero (after it is reinterpret_cast to double)
* @brief Division between two double
* @param a Numerator in double interpreted as 64 bit unsigned integer
* @param b Denominator in double interpreted as 64 bit unsigned integer
* @return Result of division reinterpret_cast to 64 bit unsigned integers
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(10), i64_to_double(100) );
* printd(a); // Output: 0.1
* @endcode
*/
uint64_t double_div(uint64_t a, uint64_t b);
/**
* Get the result of less than comparison between two double
* This function will first reinterpret_cast both inputs to double (50 decimal digit precision) before doing the less than comparison.
* @brief Less than comparison between two double
* @param a Value in double interpreted as 64 bit unsigned integer
* @param b Value in double interpreted as 64 bit unsigned integer
* @return 1 if first input is smaller than second input, 0 otherwise
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(10), i64_to_double(10) );
* uint64_t b = double_div( i64_to_double(5), i64_to_double(2) );
* uint64_t res = double_lt( a, b );
* printi(res); // Output: 1
* @endcode
*/
uint32_t double_lt(uint64_t a, uint64_t b);
/**
* Get the result of equality check between two double
* This function will first reinterpret_cast both inputs to double (50 decimal digit precision) before doing equality check.
* @brief Equality check between two double
* @param a Value in double interpreted as 64 bit unsigned integer
* @param b Value in double interpreted as 64 bit unsigned integer
* @return 1 if first input is equal to second input, 0 otherwise
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(10), i64_to_double(10) );
* uint64_t b = double_div( i64_to_double(5), i64_to_double(2) );
* uint64_t res = double_eq( a, b );
* printi(res); // Output: 0
* @endcode
*/
uint32_t double_eq(uint64_t a, uint64_t b);
/**
* Get the result of greater than comparison between two double
* This function will first reinterpret_cast both inputs to double (50 decimal digit precision) before doing the greater than comparison.
* @brief Greater than comparison between two double
* @param a Value in double interpreted as 64 bit unsigned integer
* @param b Value in double interpreted as 64 bit unsigned integer
* @return 1 if first input is greater than second input, 0 otherwise
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(10), i64_to_double(10) );
* uint64_t b = double_div( i64_to_double(5), i64_to_double(2) );
* uint64_t res = double_gt( a, b );
* printi(res); // Output: 0
* @endcode
*/
uint32_t double_gt(uint64_t a, uint64_t b);
/**
* Convert double (interpreted as 64 bit unsigned integer) to 64 bit unsigned integer.
* This function will first reinterpret_cast the input to double (50 decimal digit precision) then convert it to double, then reinterpret_cast it to 64 bit unsigned integer.
* @brief Convert double to 64 bit unsigned integer
* @param a - value in double interpreted as 64 bit unsigned integer
* @return Result of conversion in 64 bit unsigned integer
*
* Example:
* @code
* uint64_t a = double_div( i64_to_double(5), i64_to_double(2) );
* uint64_t res = double_to_i64( a );
* printi(res); // Output: 2
* @endcode
*/
uint64_t double_to_i64(uint64_t a);
/**
* Convert 64 bit unsigned integer to double (interpreted as 64 bit unsigned integer).
* This function will convert the input to double (50 decimal digit precision) then reinterpret_cast it to 64 bit unsigned integer.
* @brief Convert 64 bit unsigned integer to double (interpreted as 64 bit unsigned integer)
* @param a - value to be converted
* @return Result of conversion in double (interpreted as 64 bit unsigned integer)
*
* Example:
* @code
* uint64_t res = i64_to_double( 3 );
* printd(res); // Output: 3
* @endcode
*/
uint64_t i64_to_double(uint64_t a);
/// @}
} // extern "C"
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/math.h>
namespace eosio {
/**
* @defgroup mathapi Math API
* @brief Defines common math functions
* @ingroup contractdev
*/
/**
* @defgroup mathcppapi Math C++ API
* @brief Defines common math functions and helper types
* @ingroup mathapi
*
* @{
*/
/**
* Multiply two 128 bit unsigned integers and assign the value to the first parameter.
* This wraps multeq_i128 from @ref mathcapi.
* @brief wraps multeq_i128 from @ref mathcapi
* @param self Value to be multiplied. It will be replaced with the result
* @param other Value integer to be multiplied.
*
* Example:
* @code
* uint128_t self(100);
* uint128_t other(100);
* multeq(self, other);
* std::cout << self; // Output: 10000
* @endcode
*/
inline void multeq( uint128_t& self, const uint128_t& other ) {
multeq_i128( &self, &other );
}
/**
* Divide two 128 bit unsigned integers and assign the value to the first parameter.
* It will throw an exception if other is zero.
* This wraps diveq_i128 from @ref mathcapi
* @brief wraps diveq_i128 from @ref mathcapi
* @param self Numerator. It will be replaced with the result
* @param other Denominator
*
* Example:
* @code
* uint128_t self(100);
* uint128_t other(100);
* diveq(self, other);
* std::cout << self; // Output: 1
* @endcode
*/
inline void diveq( uint128_t& self, const uint128_t& other ) {
diveq_i128( &self, &other );
}
/**
* @brief A struct that wraps uint128 integer and defines common operator overloads
*/
struct uint128 {
public:
uint128( uint128_t i = 0 ):value(i){}
uint128( uint64_t i ):value(i){}
uint128( uint32_t i ):value(i){}
friend uint128 operator * ( uint128 a, const uint128& b ) {
return a *= b;
}
friend uint128 operator / ( uint128 a, const uint128& b ) {
return a /= b;
}
friend bool operator <= ( const uint128& a, const uint128& b ) {
return a.value <= b.value;
}
friend bool operator >= ( const uint128& a, const uint128& b ) {
return a.value >= b.value;
}
uint128& operator *= ( const uint128_t& other ) {
multeq( value, other );
return *this;
}
uint128& operator *= ( const uint128& other ) {
multeq( value, other.value );
return *this;
}
uint128& operator /= ( const uint128_t& other ) {
diveq( value, other );
return *this;
}
uint128& operator /= ( const uint128& other ) {
diveq( value, other.value );
return *this;
}
explicit operator uint64_t()const {
eosio_assert( !(value >> 64), "cast to 64 bit loss of precision" );
return uint64_t(value);
}
private:
uint128_t value = 0;
};
/**
* Get the smaller of the given values
* @brief Defined similar to std::min()
* @param a Value to compare
* @param b Value to compare
* @return The smaller of a and b. If they are equivalent, returns a
*
* Example:
* @code
* uint128_t a(1);
* uint128_t b(2);
* std::cout << min(a, b); // Output: 1
* @endcode
*/
template<typename T>
T min( const T& a, const T&b ) {
return a < b ? a : b;
}
/**
* Get the greater of the given values.
* @brief Define similar to std::max()
* @param a Value to compare
* @param b Value to compare
* @return The greater of a and b. If they are equivalent, returns a
*
* Example:
* @code
* uint128_t a(1);
* uint128_t b(2);
* std::cout << max(a, b); // Output: 2
* @endcode
*/
template<typename T>
T max( const T& a, const T&b ) {
return a > b ? a : b;
}
/// @} /// mathcppapi
}
......@@ -5,7 +5,6 @@
#pragma once
#include <eosiolib/print.h>
#include <eosiolib/types.hpp>
#include <eosiolib/math.hpp>
#include <eosiolib/fixed_key.hpp>
#include <utility>
......
#pragma once
#include <eosiolib/math.hpp>
#include <eosiolib/print.hpp>
namespace eosio {
/**
* @defgroup real Real number
* @ingroup mathcppapi
* @brief Real number data type with basic operators. Wrap double class of Math C API.
*
* Example:
* @code
* real a(100);
* real b(10);
* real c = a+b
* real d = a / b
* real e = a*b
* if(a == b) {}
* if(a > b) {}
* if(a < b) {}
* auto val = d.value();
* @endcode
* @{
*/
class real {
private:
uint64_t val;
public:
/**
* @brief Constructor to double object from uint64 value
*
* @details Constructor to double object from uint64 value
* @param _val data
*/
real(const uint64_t &_val) : val(_val) {}
uint64_t value() const { return val; }
// Arithmetic operations
real operator+(const real &rhs) const;
real operator*(const real &rhs) const;
real operator/(const real &rhs) const;
// Comparison operators
friend bool operator==(const real &c1, const real &c2);
friend bool operator>(const real &c1, const real &c2);
friend bool operator<(const real &c1, const real &c2);
};
/**
* @brief Add two real variables
*
* @details Add two real variables
* @param rhs double variable to be added with this
* @return the sum of this and rhs
*/
real real::operator+(const real &rhs) const {
auto _result = double_add(value(), rhs.value());
return real(_result);
}
/**
* @brief Multiply two real variables
*
* @details Multiply two real variables
* @param rhs double variable to be multiplied with this
* @return the result after multiplication
*/
real real::operator*(const real &rhs) const {
auto _result = double_mult(value(), rhs.value());
return real(_result);
}
/**
* @brief Division between two real variables
*
* @details Division between two real variables
* @param rhs double variable to be multiplied with this
* @return the result after division
*/
real real::operator/(const real &rhs) const {
auto _result = double_div(i64_to_double(value()), i64_to_double(rhs.value()));
return real(_result);
}
/**
* @brief Compares two double variables c1 and c2
*
* @details Compares two double variables c1 and c2
* @return if c1 == c2, return true, otherwise false
*/
bool operator==(const real &c1, const real &c2) {
auto res = double_eq(c1.value(), c2.value());
return (res == 1);
}
/**
* @brief Compares two double variables c1 and c2
*
* @details Compares two double variables c1 and c2
* @return if c1 > c2, return true, otherwise false
*/
bool operator>(const real &c1, const real &c2) {
auto res = double_gt(c1.value(), c2.value());
return (res == 1);
}
/**
* @brief Compares two double variables c1 and c2
*
* @details Compares two double variables c1 and c2
* @return if c1 < c2, return true, otherwise false
*/
bool operator<(const real &c1, const real &c2) {
auto res = double_lt(c1.value(), c2.value());
return (res == 1);
}
/// @} real
}
......@@ -10,9 +10,7 @@
#include "test_print.cpp"
#include "test_types.cpp"
#include "test_fixedpoint.cpp"
#include "test_math.cpp"
#include "test_compiler_builtins.cpp"
#include "test_real.cpp"
#include "test_crypto.cpp"
#include "test_chain.cpp"
#include "test_transaction.cpp"
......@@ -97,15 +95,6 @@ extern "C" {
WASM_TEST_HANDLER(test_print, test_printdf);
WASM_TEST_HANDLER(test_print, test_printqf);
//test_math
WASM_TEST_HANDLER(test_math, test_multeq);
WASM_TEST_HANDLER(test_math, test_diveq);
WASM_TEST_HANDLER(test_math, test_i64_to_double);
WASM_TEST_HANDLER(test_math, test_double_to_i64);
WASM_TEST_HANDLER(test_math, test_diveq_by_0);
WASM_TEST_HANDLER(test_math, test_double_api);
WASM_TEST_HANDLER(test_math, test_double_api_div_0);
//test crypto
WASM_TEST_HANDLER(test_crypto, test_recover_key);
WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_true);
......@@ -163,13 +152,6 @@ extern "C" {
WASM_TEST_HANDLER(test_fixedpoint, test_division);
WASM_TEST_HANDLER(test_fixedpoint, test_division_by_0);
// test double
WASM_TEST_HANDLER(test_real, create_instances);
WASM_TEST_HANDLER(test_real, test_addition);
WASM_TEST_HANDLER(test_real, test_multiplication);
WASM_TEST_HANDLER(test_real, test_division);
WASM_TEST_HANDLER(test_real, test_division_by_0);
// test checktime
WASM_TEST_HANDLER(test_checktime, checktime_pass);
WASM_TEST_HANDLER(test_checktime, checktime_failure);
......
......@@ -73,16 +73,6 @@ struct test_action {
static void test_publication_time();
};
struct test_math {
static void test_multeq();
static void test_diveq();
static void test_diveq_by_0();
static void test_double_api();
static void test_double_api_div_0();
static void test_i64_to_double();
static void test_double_to_i64();
};
struct test_db {
static void primary_i64_general(uint64_t receiver, uint64_t code, uint64_t action);
static void primary_i64_lowerbound(uint64_t receiver, uint64_t code, uint64_t action);
......@@ -196,14 +186,6 @@ struct test_fixedpoint {
static void test_division_by_0();
};
struct test_real {
static void create_instances();
static void test_addition();
static void test_multiplication();
static void test_division();
static void test_division_by_0();
};
struct test_compiler_builtins {
static void test_multi3();
static void test_divti3();
......
#include <eosiolib/types.hpp>
#include <eosiolib/action.hpp>
#include <eosiolib/math.hpp>
#include "test_api.hpp"
void test_math::test_multeq() {
u128_action act = eosio::unpack_action_data<u128_action>();
uint128_t self = *(act.values);
uint128_t other = *(act.values+1);
eosio::multeq(self, other);
eosio_assert( self == act.values[2], "test_multeq act.values[0] == act.values[2]" );
}
void test_math::test_diveq() {
u128_action act = eosio::unpack_action_data<u128_action>();
uint128_t self = *(act.values);
uint128_t other = *(act.values+1);
eosio::diveq(self, other);
eosio_assert( self == act.values[2], "test_diveq act.values[0] == act.values[2]" );
}
void test_math::test_diveq_by_0() {
unsigned __int128 a = 100;
unsigned __int128 b = 0;
eosio::diveq(a, b);
}
void test_math::test_i64_to_double()
{
uint64_t i[4];
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");
d = i64_to_double(uint64_t(-2));
eosio_assert(i[1] == d, "test_i64_to_double i[1] == d");
d = i64_to_double(100000);
eosio_assert(i[2] == d, "test_i64_to_double i[2] == d");
d = i64_to_double(uint64_t(-100000));
eosio_assert(i[3] == d, "test_i64_to_double i[3] == d");
d = i64_to_double(0);
eosio_assert(0 == d, "test_i64_to_double 0 == d");
}
void test_math::test_double_to_i64()
{
uint64_t d[4];
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");
i = (int64_t)double_to_i64(d[1]);
eosio_assert(-2 == i, "test_double_to_i64 -2 == i");
i = (int64_t)double_to_i64(d[2]);
eosio_assert(100000 == i, "test_double_to_i64 100000 == i");
i = (int64_t)double_to_i64(d[3]);
eosio_assert(-100000 == i, "test_double_to_i64 -100000 == i");
i = (int64_t)double_to_i64(0);
eosio_assert(0 == i, "test_double_to_i64 0 == i");
}
void test_math::test_double_api() {
uint64_t res = double_mult(
double_div( i64_to_double(2), i64_to_double(7) ),
double_add( i64_to_double(3), i64_to_double(2) )
);
eosio_assert( double_to_i64(res) == 1, "double funcs");
res = double_eq(
double_div( i64_to_double(5), i64_to_double(9) ),
double_div( i64_to_double(5), i64_to_double(9) )
);
eosio_assert(res == 1, "double_eq");
res = double_gt(
double_div( i64_to_double(9999999), i64_to_double(7777777) ),
double_div( i64_to_double(9999998), i64_to_double(7777777) )
);
eosio_assert(res == 1, "double_gt");
res = double_lt(
double_div( i64_to_double(9999998), i64_to_double(7777777) ),
double_div( i64_to_double(9999999), i64_to_double(7777777) )
);
eosio_assert(res == 1, "double_lt");
}
void test_math::test_double_api_div_0() {
double_div( i64_to_double(1),
double_add(
i64_to_double((uint64_t)-5), i64_to_double(5)
));
eosio_assert(false, "should've thrown an error");
}
#include <eosiolib/real.hpp>
#include <eosiolib/eosio.hpp>
#include "test_api.hpp"
void test_real::create_instances() {
eosio::real lhs1(5);
eosio_assert(lhs1.value() == 5, "real instance value is wrong");
}
void test_real::test_division() {
eosio::real lhs1(5);
eosio::real rhs1(10);
eosio::real result1 = lhs1 / rhs1;
uint64_t a = double_div(i64_to_double(5), i64_to_double(10));
eosio_assert(a == result1.value(), "real division result is wrong");
}
void test_real::test_division_by_0() {
eosio::real lhs1(5);
eosio::real rhs1(0);
eosio::real result1 = lhs1 / rhs1;
// in order to get rid of unused parameter warning
result1 = 0;
eosio_assert(false, "should've thrown an error");
}
void test_real::test_multiplication() {
eosio::real lhs1(5);
eosio::real rhs1(10);
eosio::real result1 = lhs1 * rhs1;
uint64_t res = double_mult( 5, 10 );
eosio_assert(res == result1.value(), "real multiplication result is wrong");
}
void test_real::test_addition()
{
eosio::real lhs1(5);
eosio::real rhs1(10);
eosio::real result1 = lhs1 / rhs1;
uint64_t a = double_div(i64_to_double(5), i64_to_double(10));
eosio::real lhs2(5);
eosio::real rhs2(2);
eosio::real result2 = lhs2 / rhs2;
uint64_t b = double_div(i64_to_double(5), i64_to_double(2));
eosio::real sum = result1+result2;
uint64_t c = double_add( a, b );
eosio_assert(sum.value() == c, "real addition operation result is wrong");
}
......@@ -14,6 +14,23 @@
using boost::container::flat_set;
namespace eosio { namespace chain {
static inline void print_debug(account_name receiver, const action_trace& ar) {
if(fc::logger::get(DEFAULT_LOGGER).is_enabled(fc::log_level::debug)) {
if (!ar.console.empty()) {
auto prefix = fc::format_string(
"\n[(${a},${n})->${r}]",
fc::mutable_variant_object()
("a", ar.act.account)
("n", ar.act.name)
("r", receiver));
dlog(prefix + ": CONSOLE OUTPUT BEGIN =====================\n"
+ ar.console
+ prefix + ": CONSOLE OUTPUT END =====================" );
}
}
}
action_trace apply_context::exec_one()
{
const auto& gpo = control.get_global_properties();
......@@ -53,6 +70,8 @@ action_trace apply_context::exec_one()
t.total_inline_cpu_usage = cpu_usage;
t.console = _pending_console_output.str();
print_debug(receiver, t);
executed.emplace_back( move(r) );
total_cpu_usage += cpu_usage;
......@@ -82,6 +101,7 @@ void apply_context::exec()
ncontext.processing_deadline = processing_deadline;
ncontext.published_time = published_time;
ncontext.max_cpu = max_cpu - total_cpu_usage;
ncontext.exec();
fc::move_append( executed, move(ncontext.executed) );
total_cpu_usage += ncontext.total_cpu_usage;
......@@ -95,6 +115,7 @@ void apply_context::exec()
apply_context ncontext( mutable_controller, _inline_actions[i], trx, recurse_depth + 1 );
ncontext.processing_deadline = processing_deadline;
ncontext.published_time = published_time;
ncontext.max_cpu = max_cpu - total_cpu_usage;
ncontext.id = id;
ncontext.exec();
fc::move_append( executed, move(ncontext.executed) );
......@@ -213,13 +234,8 @@ void apply_context::execute_context_free_inline( action&& a ) {
void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx ) {
trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary
//QUESTION: Do we need to validate other things about the transaction at this point such as:
// * uniqueness?
// * that there is at least one action and at least one authorization in the transaction?
// * that the context free actions have no authorizations?
// * that the max_kcpu_usage and max_net_usage fields do not cause overflow?
trx.validate();
FC_ASSERT( trx.context_free_actions.size() == 0, "context free actions are not currently allowed in generated transactions" );
control.validate_referenced_accounts( trx );
control.validate_expiration( trx );
......@@ -259,17 +275,30 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
uint32_t trx_size = 0;
auto& d = control.db();
d.create<generated_transaction_object>( [&]( auto& gtx ) {
gtx.trx_id = id;
gtx.sender = receiver;
gtx.sender_id = sender_id;
gtx.payer = payer;
gtx.published = control.pending_block_time();
gtx.delay_until = gtx.published + delay;
gtx.expiration = gtx.delay_until + fc::milliseconds(config::deferred_trx_expiration_window_ms);
trx_size = gtx.set( trx );
});
if ( auto ptr = d.find<generated_transaction_object,by_sender_id>(boost::make_tuple(receiver, sender_id)) ) {
d.modify<generated_transaction_object>( *ptr, [&]( auto& gtx ) {
gtx.sender = receiver;
gtx.sender_id = sender_id;
gtx.payer = payer;
gtx.published = control.pending_block_time();
gtx.delay_until = gtx.published + delay;
gtx.expiration = gtx.delay_until + fc::milliseconds(config::deferred_trx_expiration_window_ms);
trx_size = gtx.set( trx );
});
} else {
d.create<generated_transaction_object>( [&]( auto& gtx ) {
gtx.trx_id = id;
gtx.sender = receiver;
gtx.sender_id = sender_id;
gtx.payer = payer;
gtx.published = control.pending_block_time();
gtx.delay_until = gtx.published + delay;
gtx.expiration = gtx.delay_until + fc::milliseconds(config::deferred_trx_expiration_window_ms);
trx_size = gtx.set( trx );
});
}
auto& rl = control.get_mutable_resource_limits_manager();
rl.add_pending_account_ram_usage( payer, config::billable_size_v<generated_transaction_object> + trx_size );
......
......@@ -64,16 +64,6 @@ struct controller_impl {
*/
map<digest_type, transaction_metadata_ptr> unapplied_transactions;
block_id_type head_block_id()const {
return head->id;
}
time_point head_block_time()const {
return head->header.timestamp;
}
const block_header& head_block_header()const {
return head->header;
}
void pop_block() {
auto prev = fork_db.get_block( head->header.previous );
FC_ASSERT( prev, "attempt to pop beyond last irreversible block" );
......@@ -309,18 +299,9 @@ struct controller_impl {
conf.genesis.initial_timestamp );
}
void set_pending_tapos() {
const auto& tapos_block_summary = db.get<block_summary_object>((uint16_t)pending->_pending_block_state->block_num);
db.modify( tapos_block_summary, [&]( auto& bs ) {
bs.block_id = pending->_pending_block_state->id;
});
}
void commit_block( bool add_to_fork_db ) {
set_pending_tapos();
resource_limits.process_account_limit_updates();
resource_limits.process_block_usage( pending->_pending_block_state->block_num );
void commit_block( bool add_to_fork_db ) {
if( add_to_fork_db ) {
pending->_pending_block_state->validated = true;
auto new_bsp = fork_db.add( pending->_pending_block_state );
......@@ -408,7 +389,10 @@ struct controller_impl {
fc::move_append( pending->_actions, move(trx_context.executed) );
trx_context.trace->receipt = push_receipt( gto.trx_id, transaction_receipt::executed, trx_context.trace->kcpu_usage(), 0 );
trx_context.trace->receipt = push_receipt( gto.trx_id,
transaction_receipt::executed,
trx_context.trace->kcpu_usage(),
0 );
db.remove( gto );
......@@ -514,7 +498,7 @@ struct controller_impl {
trx_context.deadline = deadline;
trx_context.published = self.pending_block_time();
trx_context.net_usage = self.validate_net_usage( trx ); // / 8; // <-- BUG? Needed to be removed to fix auth_tests/no_double_billing
trx_context.net_usage = self.validate_net_usage( trx ); // Returns multiple of 8
trx_context.is_input = !implicit;
trx_context.exec();
......@@ -522,9 +506,9 @@ struct controller_impl {
if( !implicit ) {
if( trx_context.delay == fc::seconds(0) ) {
trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::executed, trace->kcpu_usage(), trx_context.net_usage );
trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::executed, trace->kcpu_usage(), trx_context.net_usage/8 );
} else {
trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::delayed, trace->kcpu_usage(), trx_context.net_usage );
trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::delayed, trace->kcpu_usage(), trx_context.net_usage/8 );
}
}
......@@ -583,6 +567,9 @@ struct controller_impl {
} catch ( ... ) {
ilog( "on block transaction failed, but shouldn't impact block generation, system contract needs update" );
}
clear_expired_input_transactions();
update_producers_authority();
} // start_block
......@@ -662,7 +649,7 @@ struct controller_impl {
fork_db.mark_in_current_chain( *itr , false );
pop_block();
}
FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
"loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
......@@ -686,7 +673,7 @@ struct controller_impl {
fork_db.mark_in_current_chain( *itr , false );
pop_block();
}
FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
"loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
// re-apply good blocks
......@@ -753,46 +740,47 @@ struct controller_impl {
);
*/
// Update resource limits:
resource_limits.process_account_limit_updates();
const auto& chain_config = self.get_global_properties().configuration;
resource_limits.set_block_parameters(
{EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct), chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}},
{EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}}
);
resource_limits.process_block_usage(pending->_pending_block_state->block_num);
set_action_merkle();
set_trx_merkle();
auto p = pending->_pending_block_state;
p->id = p->header.id();
create_block_summary();
const auto& chain_config = self.get_global_properties().configuration;
resource_limits.set_block_parameters(
{EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct), chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}},
{EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}}
);
create_block_summary(p->id);
} FC_CAPTURE_AND_RETHROW() }
void update_producers_authority() {
const auto& producers = pending->_pending_block_state->active_schedule.producers;
//TODO: Complete implementation
}
void create_block_summary() {
auto p = pending->_pending_block_state;
auto sid = p->block_num & 0xffff;
void create_block_summary(const block_id_type& id) {
auto block_num = block_header::num_from_id(id);
auto sid = block_num & 0xffff;
db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
bso.block_id = p->id;
bso.block_id = id;
});
}
void clear_expired_transactions() {
void clear_expired_input_transactions() {
//Look for expired transactions in the deduplication list, and remove them.
auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
while( (!dedupe_index.empty()) && (head_block_time() > fc::time_point(dedupe_index.begin()->expiration) ) ) {
auto now = self.pending_block_time();
while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
transaction_idx.remove(*dedupe_index.begin());
}
// Look for expired transactions in the pending generated list, and remove them.
// TODO: expire these by sending error to handler
auto& generated_transaction_idx = db.get_mutable_index<generated_transaction_multi_index>();
const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
while( (!generated_index.empty()) && (head_block_time() > generated_index.begin()->expiration) ) {
// TODO: destroy_generated_transaction(*generated_index.begin());
}
}
fc::microseconds limit_delay( fc::microseconds delay )const {
......@@ -826,12 +814,12 @@ struct controller_impl {
on_block_act.account = config::system_account_name;
on_block_act.name = N(onblock);
on_block_act.authorization = vector<permission_level>{{config::system_account_name, config::active_name}};
on_block_act.data = fc::raw::pack(head_block_header());
on_block_act.data = fc::raw::pack(self.head_block_header());
signed_transaction trx;
trx.actions.emplace_back(std::move(on_block_act));
trx.set_reference_block(head_block_id());
trx.expiration = head_block_time() + fc::seconds(1);
trx.set_reference_block(self.head_block_id());
trx.expiration = self.head_block_time() + fc::seconds(1);
return trx;
}
......@@ -894,15 +882,6 @@ void controller::commit_block() {
my->commit_block(true);
}
block_state_ptr controller::head_block_state()const {
return my->head;
}
block_state_ptr controller::pending_block_state()const {
if( my->pending ) return my->pending->_pending_block_state;
return block_state_ptr();
}
void controller::abort_block() {
my->abort_block();
}
......@@ -954,31 +933,46 @@ void controller::push_scheduled_transaction( const transaction_id_type& trxid, f
uint32_t controller::head_block_num()const {
return my->head->block_num;
}
time_point controller::head_block_time()const {
return my->head->header.timestamp;
}
block_id_type controller::head_block_id()const {
return my->head->id;
}
account_name controller::head_block_producer()const {
return my->head->header.producer;
}
uint32_t controller::last_irreversible_block_num() const {
return my->head->bft_irreversible_blocknum;
const block_header& controller::head_block_header()const {
return my->head->header;
}
block_id_type controller::last_irreversible_block_id() const {
//QUESTION/BUG: What if lib has not advanced for over 2^16 blocks?
const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)my->head->bft_irreversible_blocknum);
return tapos_block_summary.block_id;
block_state_ptr controller::head_block_state()const {
return my->head;
}
time_point controller::head_block_time()const {
return my->head_block_time();
block_state_ptr controller::pending_block_state()const {
if( my->pending ) return my->pending->_pending_block_state;
return block_state_ptr();
}
time_point controller::pending_block_time()const {
FC_ASSERT( my->pending, "no pending block" );
return my->pending->_pending_block_state->header.timestamp;
}
uint32_t controller::last_irreversible_block_num() const {
return my->head->bft_irreversible_blocknum;
}
block_id_type controller::last_irreversible_block_id() const {
auto lib_num = my->head->bft_irreversible_blocknum;
const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)lib_num);
if( block_header::num_from_id(tapos_block_summary.block_id) == lib_num )
return tapos_block_summary.block_id;
return fetch_block_by_number(lib_num)->id();
}
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
return my->db.get<dynamic_global_property_object>();
}
......@@ -1086,6 +1080,8 @@ const producer_schedule_type& controller::active_producers()const {
}
const producer_schedule_type& controller::pending_producers()const {
if ( !(my->pending) )
return my->head->pending_schedule;
return my->pending->_pending_block_state->pending_schedule;
}
......@@ -1164,10 +1160,15 @@ uint64_t controller::validate_net_usage( const transaction_metadata_ptr& trx )co
actual_net_usage = ((actual_net_usage + 7)/8) * 8; // Round up to nearest multiple of 8
uint32_t net_usage_limit = trx->trx.max_net_usage_words.value * 8UL; // overflow checked in validate_transaction_without_state
EOS_ASSERT( net_usage_limit == 0 || actual_net_usage <= net_usage_limit, tx_resource_exhausted,
"declared net usage limit of transaction is too low: ${actual_net_usage} > ${declared_limit}",
("actual_net_usage", actual_net_usage)("declared_limit",net_usage_limit) );
uint32_t net_usage_limit = cfg.max_transaction_net_usage;
// TODO: reduce net_usage_limit to the minimum of the amount that the paying accounts can afford to pay
uint32_t trx_specified_net_usage_limit = trx->trx.max_net_usage_words.value * 8UL; // overflow checked in transaction_header::validate()
if( trx_specified_net_usage_limit > 0 )
net_usage_limit = std::min( net_usage_limit, trx_specified_net_usage_limit );
EOS_ASSERT( actual_net_usage <= net_usage_limit, tx_resource_exhausted,
"net usage of transaction is too high: ${actual_net_usage} > ${net_usage_limit}",
("actual_net_usage", actual_net_usage)("net_usage_limit",net_usage_limit) );
return actual_net_usage;
}
......
......@@ -70,7 +70,7 @@ const static uint32_t producers_authority_threshold_pct = 66 * config::percen
const static uint16_t max_recursion_depth = 6;
const static uint32_t default_base_per_transaction_net_usage = 100; // 100 bytes minimum (for signature and misc overhead)
const static uint32_t default_base_per_transaction_net_usage = 48; // 48 bytes minimum (for misc overhead)
const static uint32_t default_base_per_transaction_cpu_usage = 500; // TODO: is this reasonable?
const static uint32_t default_base_per_action_cpu_usage = 1000;
const static uint32_t default_base_setcode_cpu_usage = 2 * 1024 * 1024; /// overbilling cpu usage for setcode to cover incidental
......
......@@ -110,14 +110,6 @@ namespace eosio { namespace chain {
chainbase::database& db()const;
uint32_t head_block_num()const;
time_point head_block_time()const;
time_point pending_block_time()const;
block_state_ptr head_block_state()const;
block_state_ptr pending_block_state()const;
const account_object& get_account( account_name n )const;
const global_property_object& get_global_properties()const;
const dynamic_global_property_object& get_dynamic_global_properties()const;
......@@ -129,9 +121,15 @@ namespace eosio { namespace chain {
fc::microseconds limit_delay( fc::microseconds delay )const;
uint32_t head_block_num()const;
time_point head_block_time()const;
block_id_type head_block_id()const;
account_name head_block_producer()const;
const block_header& head_block_header()const;
block_state_ptr head_block_state()const;
time_point pending_block_time()const;
block_state_ptr pending_block_state()const;
const producer_schedule_type& active_producers()const;
const producer_schedule_type& pending_producers()const;
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <array>
#include <algorithm>
#include <type_traits>
#include <fc/exception/exception.hpp>
namespace eosio {
using chain::uint128_t;
template<size_t Size>
class fixed_key;
template<size_t Size>
bool operator==(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
template<size_t Size>
bool operator!=(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
template<size_t Size>
bool operator>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
template<size_t Size>
bool operator<(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
/**
* @defgroup fixed_key fixed size key sorted lexicographically
* @ingroup types
* @{
*/
template<size_t Size>
class fixed_key {
private:
template<bool...> struct bool_pack;
template<bool... bs>
using all_true = std::is_same< bool_pack<bs..., true>, bool_pack<true, bs...> >;
template<typename Word, size_t NumWords>
static void set_from_word_sequence(const std::array<Word, NumWords>& arr, fixed_key<Size>& key)
{
auto itr = key._data.begin();
word_t temp_word = 0;
const size_t sub_word_shift = 8 * sizeof(Word);
const size_t num_sub_words = sizeof(word_t) / sizeof(Word);
auto sub_words_left = num_sub_words;
for( auto&& w : arr ) {
if( sub_words_left > 1 ) {
temp_word |= static_cast<word_t>(w);
temp_word <<= sub_word_shift;
--sub_words_left;
continue;
}
FC_ASSERT( sub_words_left == 1, "unexpected error in fixed_key constructor" );
temp_word |= static_cast<word_t>(w);
sub_words_left = num_sub_words;
*itr = temp_word;
temp_word = 0;
++itr;
}
if( sub_words_left != num_sub_words ) {
if( sub_words_left > 1 )
temp_word <<= 8 * (sub_words_left-1);
*itr = temp_word;
}
}
public:
typedef uint128_t word_t;
static constexpr size_t num_words() { return (Size + sizeof(word_t) - 1) / sizeof(word_t); }
static constexpr size_t padded_bytes() { return num_words() * sizeof(word_t) - Size; }
/**
* @brief Default constructor to fixed_key object
*
* @details Default constructor to fixed_key object which initializes all bytes to zero
*/
fixed_key() : _data() {}
/**
* @brief Constructor to fixed_key object from std::array of num_words() words
*
* @details Constructor to fixed_key object from std::array of num_words() words
* @param arr data
*/
fixed_key(const std::array<word_t, num_words()>& arr)
{
std::copy(arr.begin(), arr.end(), _data.begin());
}
template<typename Word, size_t NumWords,
typename Enable = typename std::enable_if<std::is_integral<Word>::value &&
!std::is_same<Word, bool>::value &&
sizeof(Word) < sizeof(word_t)>::type >
fixed_key(const std::array<Word, NumWords>& arr)
{
static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(Word)) * sizeof(Word),
"size of the backing word size is not divisible by the size of the array element" );
static_assert( sizeof(Word) * NumWords <= Size, "too many words supplied to fixed_key constructor" );
set_from_word_sequence(arr, *this);
}
template<typename FirstWord, typename... Rest>
static
fixed_key<Size>
make_from_word_sequence(typename std::enable_if<std::is_integral<FirstWord>::value &&
!std::is_same<FirstWord, bool>::value &&
sizeof(FirstWord) <= sizeof(word_t) &&
all_true<(std::is_same<FirstWord, Rest>::value)...>::value,
FirstWord>::type first_word,
Rest... rest)
{
static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(FirstWord)) * sizeof(FirstWord),
"size of the backing word size is not divisible by the size of the words supplied as arguments" );
static_assert( sizeof(FirstWord) * (1 + sizeof...(Rest)) <= Size, "too many words supplied to make_from_word_sequence" );
fixed_key<Size> key;
set_from_word_sequence(std::array<FirstWord, 1+sizeof...(Rest)>{{ first_word, rest... }}, key);
return key;
}
const auto& get_array()const { return _data; }
auto data() { return _data.data(); }
auto data()const { return _data.data(); }
auto size()const { return _data.size(); }
std::array<uint8_t, Size> extract_as_byte_array()const {
std::array<uint8_t, Size> arr;
const size_t num_sub_words = sizeof(word_t);
auto arr_itr = arr.begin();
auto data_itr = _data.begin();
for( size_t counter = _data.size(); counter > 0; --counter, ++data_itr ) {
size_t sub_words_left = num_sub_words;
if( counter == 1 ) { // If last word in _data array...
sub_words_left -= padded_bytes();
}
auto temp_word = *data_itr;
for( ; sub_words_left > 0; --sub_words_left ) {
*(arr_itr + sub_words_left - 1) = static_cast<uint8_t>(temp_word & 0xFF);
temp_word >>= 8;
}
arr_itr += num_sub_words;
}
return arr;
}
// Comparison operators
friend bool operator== <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
friend bool operator!= <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
friend bool operator> <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
friend bool operator< <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
private:
std::array<word_t, num_words()> _data;
};
/**
* @brief Compares two fixed_key variables c1 and c2
*
* @details Lexicographically compares two fixed_key variables c1 and c2
* @return if c1 == c2, return true, otherwise false
*/
template<size_t Size>
bool operator==(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
return c1._data == c2._data;
}
/**
* @brief Compares two fixed_key variables c1 and c2
*
* @details Lexicographically compares two fixed_key variables c1 and c2
* @return if c1 != c2, return true, otherwise false
*/
template<size_t Size>
bool operator!=(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
return c1._data != c2._data;
}
/**
* @brief Compares two fixed_key variables c1 and c2
*
* @details Lexicographically compares two fixed_key variables c1 and c2
* @return if c1 > c2, return true, otherwise false
*/
template<size_t Size>
bool operator>(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
return c1._data > c2._data;
}
/**
* @brief Compares two fixed_key variables c1 and c2
*
* @details Lexicographically compares two fixed_key variables c1 and c2
* @return if c1 < c2, return true, otherwise false
*/
template<size_t Size>
bool operator<(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
return c1._data < c2._data;
}
/// @} fixed_key
typedef fixed_key<32> key256;
}
......@@ -43,6 +43,7 @@ namespace eosio { namespace chain {
}
void set_reference_block( const block_id_type& reference_block );
bool verify_reference_block( const block_id_type& reference_block )const;
void validate()const;
};
/**
......@@ -153,7 +154,7 @@ namespace eosio { namespace chain {
deferred_transaction() = default;
deferred_transaction(uint128_t sender_id, account_name sender, account_name payer,time_point_sec execute_after,
deferred_transaction(uint128_t sender_id, account_name sender, account_name payer,time_point_sec execute_after,
const signed_transaction& txn)
: signed_transaction(txn),
sender_id(sender_id),
......
......@@ -57,6 +57,13 @@ bool transaction_header::verify_reference_block( const block_id_type& reference_
ref_block_prefix == (decltype(ref_block_prefix))reference_block._hash[1];
}
void transaction_header::validate()const {
EOS_ASSERT( max_kcpu_usage.value < UINT32_MAX / 1024UL, transaction_exception,
"declared max_kcpu_usage overflows when expanded to max cpu usage" );
EOS_ASSERT( max_net_usage_words.value < UINT32_MAX / 8UL, transaction_exception,
"declared max_net_usage_words overflows when expanded to max net usage" );
}
transaction_id_type transaction::id() const {
digest_type::encoder enc;
fc::raw::pack( enc, *this );
......
......@@ -4,15 +4,13 @@
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/transaction_object.hpp>
#include <eosio/chain/global_property_object.hpp>
namespace eosio { namespace chain {
void transaction_context::exec() {
EOS_ASSERT( trx.max_kcpu_usage.value < UINT32_MAX / 1024UL, transaction_exception, "declared max_kcpu_usage overflows when expanded to max cpu usage" );
EOS_ASSERT( trx.max_net_usage_words.value < UINT32_MAX / 8UL, transaction_exception, "declared max_net_usage_words overflows when expanded to max net usage" );
trx.validate();
control.validate_tapos( trx );
control.validate_referenced_accounts( trx );
......@@ -20,12 +18,11 @@ namespace eosio { namespace chain {
control.validate_expiration( trx );
record_transaction( id, trx.expiration ); /// checks for dupes
}
if( trx.max_kcpu_usage.value != 0 ) {
max_cpu = uint64_t(trx.max_kcpu_usage.value)*1024;
} else {
max_cpu = uint64_t(-1);
}
max_cpu = control.get_global_properties().configuration.max_transaction_cpu_usage;
// TODO: reduce max_cpu to the minimum of the amount that the paying accounts can afford to pay
uint64_t trx_specified_cpu_usage_limit = uint64_t(trx.max_kcpu_usage.value)*1024; // overflow checked in transaction_header::validate()
if( trx_specified_cpu_usage_limit > 0 )
max_cpu = std::min( max_cpu, trx_specified_cpu_usage_limit );
if( apply_context_free ) {
for( const auto& act : trx.context_free_actions ) {
......@@ -46,11 +43,16 @@ namespace eosio { namespace chain {
bill_to_accounts.insert( auth.actor );
}
FC_ASSERT( trace->cpu_usage <= max_cpu, "transaction consumed too many CPU cycles" );
trace->cpu_usage = ((trace->cpu_usage + 1023)/1024)*1024; // Round up to nearest multiple of 1024
EOS_ASSERT( trace->cpu_usage <= max_cpu, tx_resource_exhausted,
"cpu usage of transaction is too high: ${actual_net_usage} > ${cpu_usage_limit}",
("actual_net_usage", trace->cpu_usage)("cpu_usage_limit", max_cpu) );
auto& rl = control.get_mutable_resource_limits_manager();
flat_set<account_name> bta( bill_to_accounts.begin(), bill_to_accounts.end() );
FC_ASSERT( net_usage % 8 == 0, "net_usage must be a multiple of word size (8)" );
rl.add_transaction_usage( bta, trace->cpu_usage, net_usage, block_timestamp_type(control.pending_block_time()).slot );
}
......
......@@ -1432,92 +1432,6 @@ class compiler_builtins : public context_aware_api {
static constexpr uint32_t SHIFT_WIDTH = (sizeof(uint64_t)*8)-1;
};
class math_api : public context_aware_api {
public:
math_api( apply_context& ctx )
:context_aware_api(ctx,true){}
void diveq_i128(unsigned __int128* self, const unsigned __int128* other) {
fc::uint128_t s(*self);
const fc::uint128_t o(*other);
FC_ASSERT( o != 0, "divide by zero" );
s = s/o;
*self = (unsigned __int128)s;
}
void multeq_i128(unsigned __int128* self, const unsigned __int128* other) {
fc::uint128_t s(*self);
const fc::uint128_t o(*other);
s *= o;
*self = (unsigned __int128)s;
}
uint64_t double_add(uint64_t a, uint64_t b) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
+ DOUBLE(*reinterpret_cast<double *>(&b));
double res = c.convert_to<double>();
return *reinterpret_cast<uint64_t *>(&res);
}
uint64_t double_mult(uint64_t a, uint64_t b) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
* DOUBLE(*reinterpret_cast<double *>(&b));
double res = c.convert_to<double>();
return *reinterpret_cast<uint64_t *>(&res);
}
uint64_t double_div(uint64_t a, uint64_t b) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
DOUBLE divisor = DOUBLE(*reinterpret_cast<double *>(&b));
FC_ASSERT(divisor != 0, "divide by zero");
DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a)) / divisor;
double res = c.convert_to<double>();
return *reinterpret_cast<uint64_t *>(&res);
}
uint32_t double_eq(uint64_t a, uint64_t b) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
return DOUBLE(*reinterpret_cast<double *>(&a)) == DOUBLE(*reinterpret_cast<double *>(&b));
}
uint32_t double_lt(uint64_t a, uint64_t b) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
return DOUBLE(*reinterpret_cast<double *>(&a)) < DOUBLE(*reinterpret_cast<double *>(&b));
}
uint32_t double_gt(uint64_t a, uint64_t b) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
return DOUBLE(*reinterpret_cast<double *>(&a)) > DOUBLE(*reinterpret_cast<double *>(&b));
}
uint64_t double_to_i64(uint64_t n) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
return DOUBLE(*reinterpret_cast<double *>(&n)).convert_to<int64_t>();
}
uint64_t i64_to_double(int64_t n) {
using DOUBLE = boost::multiprecision::cpp_bin_float_50;
double res = DOUBLE(n).convert_to<double>();
return *reinterpret_cast<uint64_t *>(&res);
}
};
REGISTER_INTRINSICS(math_api,
(diveq_i128, void(int, int) )
(multeq_i128, void(int, int) )
(double_add, int64_t(int64_t, int64_t) )
(double_mult, int64_t(int64_t, int64_t) )
(double_div, int64_t(int64_t, int64_t) )
(double_eq, int32_t(int64_t, int64_t) )
(double_lt, int32_t(int64_t, int64_t) )
(double_gt, int32_t(int64_t, int64_t) )
(double_to_i64, int64_t(int64_t) )
(i64_to_double, int64_t(int64_t) )
);
REGISTER_INTRINSICS(compiler_builtins,
(__ashlti3, void(int, int64_t, int64_t, int) )
(__ashrti3, void(int, int64_t, int64_t, int) )
......
......@@ -59,6 +59,8 @@ namespace eosio { namespace testing {
fc::variant_object filter_fields(const fc::variant_object& filter, const fc::variant_object& value);
void copy_row(const chain::key_value_object& obj, vector<char>& data);
/**
* @class tester
* @brief provides utility function to simplify the creation of unit tests
......
......@@ -17,6 +17,11 @@ namespace eosio { namespace testing {
return res;
}
void copy_row(const chain::key_value_object& obj, vector<char>& data) {
data.resize( obj.value.size() );
memcpy( data.data(), obj.value.data(), obj.value.size() );
}
bool base_tester::is_same_chain( base_tester& other ) {
return control->head_block_id() == other.control->head_block_id();
}
......
......@@ -14,6 +14,7 @@ set( CMAKE_CXX_STANDARD 14 )
include_directories("${CMAKE_BINARY_DIR}/contracts")
include_directories("${CMAKE_SOURCE_DIR}/contracts")
include_directories("${CMAKE_SOURCE_DIR}/unittests/contracts")
include_directories("${CMAKE_SOURCE_DIR}/libraries/testing/include")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/config.hpp ESCAPE_QUOTES)
......
此差异已折叠。
#pragma once
#include <eosio/chain/webassembly/common.hpp>
// These are handcrafted or otherwise tricky to generate with our tool chain
/*
static const char f32_add_wast[] = R"=====(
(module
(import "env" "eosio_assert" (func $eosio_assert (param i32 i32)))
(table 0 anyfunc)
(memory $0 1)
(export "memory" (memory $0))
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64)
(call $eosio_assert (i32.eq (i32.trunc_u/f32 (f32.const 0x3f800000)) (i32.const 0x0)) (i32.const 0))
)
)
)=====";
*/
static const char aligned_ref_wast[] = R"=====(
(module
(import "env" "sha256" (func $sha256 (param i32 i32 i32)))
(table 0 anyfunc)
(memory $0 32)
(data (i32.const 4) "hello")
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $sha256
(i32.const 4)
(i32.const 5)
(i32.const 16)
)
)
)
)=====";
static const char aligned_const_ref_wast[] = R"=====(
(module
(import "env" "sha256" (func $sha256 (param i32 i32 i32)))
(import "env" "assert_sha256" (func $assert_sha256 (param i32 i32 i32)))
(table 0 anyfunc)
(memory $0 32)
(data (i32.const 4) "hello")
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(local $3 i32)
(call $sha256
(i32.const 4)
(i32.const 5)
(i32.const 16)
)
(call $assert_sha256
(i32.const 4)
(i32.const 5)
(i32.const 16)
)
)
)
)=====";
static const char misaligned_ref_wast[] = R"=====(
(module
(import "env" "sha256" (func $sha256 (param i32 i32 i32)))
(table 0 anyfunc)
(memory $0 32)
(data (i32.const 4) "hello")
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $sha256
(i32.const 4)
(i32.const 5)
(i32.const 5)
)
)
)
)=====";
static const char misaligned_const_ref_wast[] = R"=====(
(module
(import "env" "sha256" (func $sha256 (param i32 i32 i32)))
(import "env" "assert_sha256" (func $assert_sha256 (param i32 i32 i32)))
(import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32)))
(table 0 anyfunc)
(memory $0 32)
(data (i32.const 4) "hello")
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(local $3 i32)
(call $sha256
(i32.const 4)
(i32.const 5)
(i32.const 16)
)
(set_local $3
(call $memcpy
(i32.const 17)
(i32.const 16)
(i32.const 64)
)
)
(call $assert_sha256
(i32.const 4)
(i32.const 5)
(i32.const 17)
)
)
)
)=====";
static const char entry_wast[] = R"=====(
(module
(import "env" "require_auth" (func $require_auth (param i64)))
(import "env" "eosio_assert" (func $eosio_assert (param i32 i32)))
(import "env" "current_time" (func $current_time (result i64)))
(table 0 anyfunc)
(memory $0 1)
(export "memory" (memory $0))
(export "entry" (func $entry))
(export "apply" (func $apply))
(func $entry
(block
(i64.store offset=4
(i32.const 0)
(call $current_time)
)
)
)
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(block
(call $require_auth (i64.const 6121376101093867520))
(call $eosio_assert
(i64.eq
(i64.load offset=4
(i32.const 0)
)
(call $current_time)
)
(i32.const 0)
)
)
)
(start $entry)
)
)=====";
static const char simple_no_memory_wast[] = R"=====(
(module
(import "env" "require_auth" (func $require_auth (param i64)))
(import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32)))
(table 0 anyfunc)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $require_auth (i64.const 11323361180581363712))
(drop
(call $memcpy
(i32.const 0)
(i32.const 1024)
(i32.const 1024)
)
)
)
)
)=====";
static const char mutable_global_wast[] = R"=====(
(module
(import "env" "require_auth" (func $require_auth (param i64)))
(import "env" "eosio_assert" (func $eosio_assert (param i32 i32)))
(table 0 anyfunc)
(memory $0 1)
(export "memory" (memory $0))
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $require_auth (i64.const 7235159549794234880))
(if (i64.eq (get_local $2) (i64.const 0)) (then
(set_global $g0 (i64.const 444))
(return)
))
(if (i64.eq (get_local $2) (i64.const 1)) (then
(call $eosio_assert (i64.eq (get_global $g0) (i64.const 2)) (i32.const 0))
(return)
))
(call $eosio_assert (i32.const 0) (i32.const 0))
)
(global $g0 (mut i64) (i64.const 2))
)
)=====";
static const char biggest_memory_wast[] = R"=====(
(module
(import "env" "eosio_assert" (func $$eosio_assert (param i32 i32)))
(import "env" "require_auth" (func $$require_auth (param i64)))
(table 0 anyfunc)
(memory $$0 ${MAX_WASM_PAGES})
(export "memory" (memory $$0))
(export "apply" (func $$apply))
(func $$apply (param $$0 i64) (param $$1 i64) (param $$2 i64)
(call $$require_auth (i64.const 4294504710842351616))
(call $$eosio_assert
(i32.eq
(grow_memory (i32.const 1))
(i32.const -1)
)
(i32.const 0)
)
)
)
)=====";
static const char too_big_memory_wast[] = R"=====(
(module
(table 0 anyfunc)
(memory $$0 ${MAX_WASM_PAGES_PLUS_ONE})
(export "memory" (memory $$0))
(export "apply" (func $$apply))
(func $$apply (param $$0 i64) (param $$1 i64) (param $$2 i64))
)
)=====";
static const char valid_sparse_table[] = R"=====(
(module
(table 1024 anyfunc)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
(elem (i32.const 0) $apply)
(elem (i32.const 1022) $apply $apply)
)
)=====";
static const char too_big_table[] = R"=====(
(module
(table 1025 anyfunc)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
(elem (i32.const 0) $apply)
(elem (i32.const 1022) $apply $apply)
)
)=====";
static const char memory_init_borderline[] = R"=====(
(module
(memory $0 16)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
(data (i32.const 65532) "sup!")
)
)=====";
static const char memory_init_toolong[] = R"=====(
(module
(memory $0 16)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
(data (i32.const 65533) "sup!")
)
)=====";
static const char memory_init_negative[] = R"=====(
(module
(memory $0 16)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
(data (i32.const -1) "sup!")
)
)=====";
static const char memory_table_import[] = R"=====(
(module
(table (import "foo" "table") 10 anyfunc)
(memory (import "nom" "memory") 0)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
)
)=====";
static const char table_checker_wast[] = R"=====(
(module
(import "env" "require_auth" (func $require_auth (param i64)))
(import "env" "eosio_assert" (func $assert (param i32 i32)))
(type $SIG$vj (func (param i64)))
(table 1024 anyfunc)
(memory $0 1)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $require_auth (i64.const 14547189746360123392))
(call_indirect $SIG$vj
(i64.shr_u
(get_local $2)
(i64.const 32)
)
(i32.wrap/i64
(get_local $2)
)
)
)
(func $apple (type $SIG$vj) (param $0 i64)
(call $assert
(i64.eq
(get_local $0)
(i64.const 555)
)
(i32.const 0)
)
)
(func $bannna (type $SIG$vj) (param $0 i64)
(call $assert
(i64.eq
(get_local $0)
(i64.const 7777)
)
(i32.const 0)
)
)
(elem (i32.const 0) $apple)
(elem (i32.const 1022) $apple $bannna)
)
)=====";
static const char table_checker_proper_syntax_wast[] = R"=====(
(module
(import "env" "require_auth" (func $require_auth (param i64)))
(import "env" "eosio_assert" (func $assert (param i32 i32)))
(import "env" "printi" (func $printi (param i64)))
(type $SIG$vj (func (param i64)))
(table 1024 anyfunc)
(memory $0 1)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $require_auth (i64.const 14547189746360123392))
(call_indirect (type $SIG$vj)
(i64.shr_u
(get_local $2)
(i64.const 32)
)
(i32.wrap/i64
(get_local $2)
)
)
)
(func $apple (type $SIG$vj) (param $0 i64)
(call $assert
(i64.eq
(get_local $0)
(i64.const 555)
)
(i32.const 0)
)
)
(func $bannna (type $SIG$vj) (param $0 i64)
(call $assert
(i64.eq
(get_local $0)
(i64.const 7777)
)
(i32.const 0)
)
)
(elem (i32.const 0) $apple)
(elem (i32.const 1022) $apple $bannna)
)
)=====";
static const char table_checker_small_wast[] = R"=====(
(module
(import "env" "require_auth" (func $require_auth (param i64)))
(import "env" "eosio_assert" (func $assert (param i32 i32)))
(import "env" "printi" (func $printi (param i64)))
(type $SIG$vj (func (param i64)))
(table 128 anyfunc)
(memory $0 1)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $require_auth (i64.const 14547189746360123392))
(call_indirect (type $SIG$vj)
(i64.shr_u
(get_local $2)
(i64.const 32)
)
(i32.wrap/i64
(get_local $2)
)
)
)
(func $apple (type $SIG$vj) (param $0 i64)
(call $assert
(i64.eq
(get_local $0)
(i64.const 555)
)
(i32.const 0)
)
)
(elem (i32.const 0) $apple)
)
)=====";
static const char global_protection_none_get_wast[] = R"=====(
(module
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(drop (get_global 0))
)
)
)=====";
static const char global_protection_some_get_wast[] = R"=====(
(module
(global i32 (i32.const -11))
(global i32 (i32.const 56))
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(drop (get_global 1))
(drop (get_global 2))
)
)
)=====";
static const char global_protection_none_set_wast[] = R"=====(
(module
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(set_global 0 (get_local 1))
)
)
)=====";
static const char global_protection_some_set_wast[] = R"=====(
(module
(global i64 (i64.const -11))
(global i64 (i64.const 56))
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(set_global 2 (get_local 1))
)
)
)=====";
static const std::vector<uint8_t> global_protection_okay_get_wasm{
0x00, 'a', 's', 'm', 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x03, 0x7e, 0x7e, 0x7e, 0x00, //type section containing a function as void(i64,i64,i64)
0x03, 0x02, 0x01, 0x00, //a function
0x06, 0x06, 0x01, 0x7f, 0x00, 0x41, 0x75, 0x0b, //global
0x07, 0x09, 0x01, 0x05, 'a', 'p', 'p', 'l', 'y', 0x00, 0x00, //export function 0 as "apply"
0x0a, 0x07, 0x01, //code section
0x05, 0x00, //function body start with length 5; no locals
0x23, 0x00, //get global 0
0x1a, //drop
0x0b //end
};
static const std::vector<uint8_t> global_protection_none_get_wasm{
0x00, 'a', 's', 'm', 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x03, 0x7e, 0x7e, 0x7e, 0x00, //type section containing a function as void(i64,i64,i64)
0x03, 0x02, 0x01, 0x00, //a function
0x07, 0x09, 0x01, 0x05, 'a', 'p', 'p', 'l', 'y', 0x00, 0x00, //export function 0 as "apply"
0x0a, 0x07, 0x01, //code section
0x05, 0x00, //function body start with length 5; no locals
0x23, 0x00, //get global 0
0x1a, //drop
0x0b //end
};
static const std::vector<uint8_t> global_protection_some_get_wasm{
0x00, 'a', 's', 'm', 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x03, 0x7e, 0x7e, 0x7e, 0x00, //type section containing a function as void(i64,i64,i64)
0x03, 0x02, 0x01, 0x00, //a function
0x06, 0x06, 0x01, 0x7f, 0x00, 0x41, 0x75, 0x0b, //global
0x07, 0x09, 0x01, 0x05, 'a', 'p', 'p', 'l', 'y', 0x00, 0x00, //export function 0 as "apply"
0x0a, 0x07, 0x01, //code section
0x05, 0x00, //function body start with length 5; no locals
0x23, 0x01, //get global 1
0x1a, //drop
0x0b //end
};
static const std::vector<uint8_t> global_protection_okay_set_wasm{
0x00, 'a', 's', 'm', 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x03, 0x7e, 0x7e, 0x7e, 0x00, //type section containing a function as void(i64,i64,i64)
0x03, 0x02, 0x01, 0x00, //a function
0x06, 0x06, 0x01, 0x7e, 0x01, 0x42, 0x75, 0x0b, //global.. this time with i64 & global mutablity
0x07, 0x09, 0x01, 0x05, 'a', 'p', 'p', 'l', 'y', 0x00, 0x00, //export function 0 as "apply"
0x0a, 0x08, 0x01, //code section
0x06, 0x00, //function body start with length 6; no locals
0x20, 0x00, //get local 0
0x24, 0x00, //set global 0
0x0b //end
};
static const std::vector<uint8_t> global_protection_some_set_wasm{
0x00, 'a', 's', 'm', 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x03, 0x7e, 0x7e, 0x7e, 0x00, //type section containing a function as void(i64,i64,i64)
0x03, 0x02, 0x01, 0x00, //a function
0x06, 0x06, 0x01, 0x7e, 0x01, 0x42, 0x75, 0x0b, //global.. this time with i64 & global mutablity
0x07, 0x09, 0x01, 0x05, 'a', 'p', 'p', 'l', 'y', 0x00, 0x00, //export function 0 as "apply"
0x0a, 0x08, 0x01, //code section
0x06, 0x00, //function body start with length 6; no locals
0x20, 0x00, //get local 0
0x24, 0x01, //set global 1
0x0b //end
};
static const char no_apply_wast[] = R"=====(
(module
(func $apply (param $0 i64) (param $1 i64) (param $2 i64))
)
)=====";
static const char apply_wrong_signature_wast[] = R"=====(
(module
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 f64))
)
)=====";
static const char import_injected_wast[] = \
"(module" \
" (export \"apply\" (func $apply))" \
" (import \"" EOSIO_INJECTED_MODULE_NAME "\" \"checktime\" (func $inj (param i32)))" \
" (func $apply (param $0 i64) (param $1 i64) (param $2 i64))" \
")";
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <chainbase/chainbase.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/contract_table_objects.hpp>
#include <eosio/chain/fixed_key.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <chainbase/chainbase.hpp>
#include <identity/identity.wast.hpp>
#include <identity/identity.abi.hpp>
......@@ -17,8 +18,6 @@
#include <algorithm>
#include "test_wasts.hpp"
#ifdef NON_VALIDATING_TEST
#define TESTER tester
#else
......@@ -27,8 +26,6 @@
using namespace eosio;
using namespace eosio::chain;
using namespace eosio::chain::contracts;
using namespace eosio::chain_apis;
using namespace eosio::testing;
using namespace fc;
......@@ -47,23 +44,23 @@ public:
set_abi(N(identitytest), identity_test_abi);
produce_blocks(1);
const auto& accnt = control->get_database().get<account_object,by_name>( N(identity) );
const auto& accnt = control->db().get<account_object,by_name>( N(identity) );
abi_def abi;
BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
abi_ser.set_abi(abi);
const auto& acnt_test = control->get_database().get<account_object,by_name>( N(identitytest) );
const auto& acnt_test = control->db().get<account_object,by_name>( N(identitytest) );
abi_def abi_test;
BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(acnt_test.abi, abi_test), true);
abi_ser_test.set_abi(abi_test);
const global_property_object &gpo = control->get_global_properties();
FC_ASSERT(0 < gpo.active_producers.producers.size(), "No producers");
producer_name = (string)gpo.active_producers.producers.front().producer_name;
const auto& ap = control->active_producers();
FC_ASSERT(0 < ap.producers.size(), "No producers");
producer_name = (string)ap.producers.front().producer_name;
}
uint64_t get_result_uint64() {
const auto& db = control->get_database();
const auto& db = control->db();
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(N(identitytest), 0, N(result)));
FC_ASSERT(t_id != 0, "Table id not found");
......@@ -113,7 +110,7 @@ public:
}
fc::variant get_identity(uint64_t idnt) {
const auto& db = control->get_database();
const auto& db = control->db();
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(N(identity), N(identity), N(ident)));
FC_ASSERT(t_id != 0, "object not found");
......@@ -124,7 +121,7 @@ public:
BOOST_REQUIRE_EQUAL(idnt, itr->primary_key);
vector<char> data;
read_only::copy_inline_row(*itr, data);
copy_row(*itr, data);
return abi_ser.binary_to_variant("identrow", data);
}
......@@ -142,7 +139,7 @@ public:
}
fc::variant get_certrow(uint64_t identity, const string& property, uint64_t trusted, const string& certifier) {
const auto& db = control->get_database();
const auto& db = control->db();
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(N(identity), identity, N( certs )));
if ( !t_id ) {
return fc::variant(nullptr);
......@@ -161,7 +158,7 @@ public:
"Record found in secondary index, but not found in primary index."
);
vector<char> data;
read_only::copy_inline_row(*itr, data);
copy_row(*itr, data);
return abi_ser.binary_to_variant("certrow", data);
} else {
return fc::variant(nullptr);
......@@ -169,7 +166,7 @@ public:
}
fc::variant get_accountrow(const string& account) {
const auto& db = control->get_database();
const auto& db = control->db();
uint64_t acnt = string_to_name(account.c_str());
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(N(identity), acnt, N(account)));
if (!t_id) {
......@@ -179,7 +176,7 @@ public:
auto itr = idx.lower_bound(boost::make_tuple(t_id->id, N(account)));
if( itr != idx.end() && itr->t_id == t_id->id && N(account) == itr->primary_key) {
vector<char> data;
read_only::copy_inline_row(*itr, data);
copy_row(*itr, data);
return abi_ser.binary_to_variant("accountrow", data);
} else {
return fc::variant(nullptr);
......@@ -202,7 +199,7 @@ public:
}
bool get_trust(const string& trustor, const string& trusting) {
const auto& db = control->get_database();
const auto& db = control->db();
const auto* t_id = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(N(identity), string_to_name(trustor.c_str()), N(trust)));
if (!t_id) {
return false;
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册