提交 9dfa4ede 编写于 作者: B Brian Johnson

STAT-81 (GH-607) Added logic for tracking db usage and limiting.

上级 b89b918b
......@@ -33,10 +33,10 @@ class wasm_interface {
};
typedef map<name, key_type> TableMap;
struct ModuleState {
Runtime::ModuleInstance* instance = nullptr;
IR::Module* module = nullptr;
int mem_start = 0;
int mem_end = 1<<16;
Runtime::ModuleInstance* instance = nullptr;
IR::Module* module = nullptr;
int mem_start = 0;
int mem_end = 1<<16;
vector<char> init_memory;
fc::sha256 code_version;
TableMap table_key_types;
......@@ -55,19 +55,23 @@ class wasm_interface {
static key_type to_key_type(const types::type_name& type_name);
static std::string to_type_name(key_type key_type);
apply_context* current_apply_context = nullptr;
apply_context* current_validate_context = nullptr;
apply_context* current_apply_context = nullptr;
apply_context* current_validate_context = nullptr;
apply_context* current_precondition_context = nullptr;
Runtime::MemoryInstance* current_memory = nullptr;
Runtime::ModuleInstance* current_module = nullptr;
ModuleState* current_state = nullptr;
Runtime::MemoryInstance* current_memory = nullptr;
Runtime::ModuleInstance* current_module = nullptr;
ModuleState* current_state = nullptr;
wasm_memory* current_memory_management = nullptr;
TableMap* table_key_types = nullptr;
bool tables_fixed = false;
bool tables_fixed = false;
int64_t table_storage_delta = 0;
uint32_t checktime_limit = 0;
int32_t per_code_account_max_db_limit_mbytes = config::default_per_code_account_max_db_limit_mbytes;
uint32_t row_overhead_db_limit_bytes = config::default_row_overhead_db_limit_bytes;
private:
void load( const account_name& name, const chainbase::database& db );
......
......@@ -6,6 +6,7 @@
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <eos/chain/wasm_interface.hpp>
#include <eos/chain/chain_controller.hpp>
#include <eos/chain/rate_limiting_object.hpp>
#include "Platform/Platform.h"
#include "WAST/WAST.h"
#include "Runtime/Runtime.h"
......@@ -25,6 +26,7 @@ namespace eosio { namespace chain {
using namespace IR;
using namespace Runtime;
typedef boost::multiprecision::cpp_bin_float_50 DOUBLE;
const uint32_t bytes_per_mbyte = 1024 * 1024;
class wasm_memory
{
......@@ -129,6 +131,14 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
return func(wasm.current_apply_context, &keys, value, valuelen);
}
int64_t round_to_byte_boundary(int64_t bytes)
{
const unsigned int byte_boundary = sizeof(uint64_t);
int64_t remainder = bytes % byte_boundary;
if (remainder > 0)
bytes += byte_boundary - remainder;
return bytes;
}
#define VERIFY_TABLE(TYPE) \
const auto table_name = name(table); \
......@@ -159,20 +169,63 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
auto lambda = [&](apply_context* ctx, INDEX::value_type::key_type* keys, char *data, uint32_t datalen) -> int32_t { \
return ctx->UPDATEFUNC<INDEX::value_type>( name(scope), name(ctx->code.value), table_name, keys, data, datalen); \
}; \
return validate<decltype(lambda), INDEX::value_type::key_type, INDEX::value_type::number_of_keys>(valueptr, DATASIZE, lambda);
const int32_t ret = validate<decltype(lambda), INDEX::value_type::key_type, INDEX::value_type::number_of_keys>(valueptr, DATASIZE, lambda);
char* key_str(uint64_t key)
{
const char nums[] = "0123456789";
char* ret = new char[512];
char* ret2 = new char[512];
const uint64_t rem = 10;
uint32_t index = 0;
for (; key > 0; ++index)
{
ret[index] = nums[(uint32_t)(key % rem)];
key /= rem;
}
for (uint32_t i = 0; i < index; ++i)
{
ret2[i] = ret[index - 1 - i];
}
ret2[index] = '\0';
return ret2;
}
#define DEFINE_RECORD_UPDATE_FUNCTIONS(OBJTYPE, INDEX) \
#define DEFINE_RECORD_UPDATE_FUNCTIONS(OBJTYPE, INDEX, KEY_SIZE) \
DEFINE_INTRINSIC_FUNCTION4(env,store_##OBJTYPE,store_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
VERIFY_TABLE(OBJTYPE) \
UPDATE_RECORD(store_record, INDEX, valuelen); \
/* ret is -1 if record created, or else it is the length of the data portion of the originally stored */ \
/* structure (it does not include the key portion */ \
const bool created = (ret == -1); \
int64_t& delta = wasm_interface::get().table_storage_delta; \
if (created) \
delta += round_to_byte_boundary(valuelen) + wasm_interface::get().row_overhead_db_limit_bytes; \
else \
/* need to calculate the difference between the original rounded byte size and the new rounded byte size */ \
delta += round_to_byte_boundary(valuelen) - round_to_byte_boundary(KEY_SIZE + ret); \
return created ? 1 : 0; \
} \
DEFINE_INTRINSIC_FUNCTION4(env,update_##OBJTYPE,update_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
VERIFY_TABLE(OBJTYPE) \
UPDATE_RECORD(update_record, INDEX, valuelen); \
/* ret is -1 if record created, or else it is the length of the data portion of the originally stored */ \
/* structure (it does not include the key portion */ \
if (ret == -1) return 0; \
int64_t& delta = wasm_interface::get().table_storage_delta; \
/* need to calculate the difference between the original rounded byte size and the new rounded byte size */ \
delta += round_to_byte_boundary(valuelen) - round_to_byte_boundary(KEY_SIZE + ret); \
return 1; \
} \
DEFINE_INTRINSIC_FUNCTION3(env,remove_##OBJTYPE,remove_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr) { \
VERIFY_TABLE(OBJTYPE) \
UPDATE_RECORD(remove_record, INDEX, sizeof(typename INDEX::value_type::key_type)*INDEX::value_type::number_of_keys); \
/* ret is -1 if record created, or else it is the length of the data portion of the originally stored */ \
/* structure (it does not include the key portion */ \
if (ret == -1) return 0; \
int64_t& delta = wasm_interface::get().table_storage_delta; \
delta -= round_to_byte_boundary(KEY_SIZE + ret) + wasm_interface::get().row_overhead_db_limit_bytes; \
return 1; \
}
#define DEFINE_RECORD_READ_FUNCTION(OBJTYPE, ACTION, FUNCPREFIX, INDEX, SCOPE) \
......@@ -190,14 +243,14 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
DEFINE_RECORD_READ_FUNCTION(OBJTYPE, lower_bound, FUNCPREFIX, INDEX, SCOPE) \
DEFINE_RECORD_READ_FUNCTION(OBJTYPE, upper_bound, FUNCPREFIX, INDEX, SCOPE)
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index);
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index, 8);
DEFINE_RECORD_READ_FUNCTIONS(i64,,key_value_index, by_scope_primary);
DEFINE_RECORD_UPDATE_FUNCTIONS(i128i128, key128x128_value_index);
DEFINE_RECORD_UPDATE_FUNCTIONS(i128i128, key128x128_value_index, 32);
DEFINE_RECORD_READ_FUNCTIONS(i128i128, primary_, key128x128_value_index, by_scope_primary);
DEFINE_RECORD_READ_FUNCTIONS(i128i128, secondary_, key128x128_value_index, by_scope_secondary);
DEFINE_RECORD_UPDATE_FUNCTIONS(i64i64i64, key64x64x64_value_index);
DEFINE_RECORD_UPDATE_FUNCTIONS(i64i64i64, key64x64x64_value_index, 24);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, primary_, key64x64x64_value_index, by_scope_primary);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, secondary_, key64x64x64_value_index, by_scope_secondary);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, tertiary_, key64x64x64_value_index, by_scope_tertiary);
......@@ -208,7 +261,7 @@ DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, tertiary_, key64x64x64_value_index, by_
auto lambda = [&](apply_context* ctx, std::string* keys, char *data, uint32_t datalen) -> int32_t { \
return ctx->FUNCTION<keystr_value_object>( name(scope), name(ctx->code.value), table_name, keys, data, datalen); \
}; \
return validate_str<decltype(lambda)>(keyptr, keylen, valueptr, valuelen, lambda);
const int32_t ret = validate_str<decltype(lambda)>(keyptr, keylen, valueptr, valuelen, lambda);
#define READ_RECORD_STR(FUNCTION) \
VERIFY_TABLE(str) \
......@@ -219,14 +272,34 @@ DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, tertiary_, key64x64x64_value_index, by_
return validate_str<decltype(lambda)>(keyptr, keylen, valueptr, valuelen, lambda);
DEFINE_INTRINSIC_FUNCTION6(env,store_str,store_str,i32,i64,scope,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
UPDATE_RECORD_STR(store_record)
UPDATE_RECORD_STR(store_record)
const bool created = (ret == -1);
auto& delta = wasm_interface::get().table_storage_delta;
if (created)
{
delta += round_to_byte_boundary(keylen + valuelen) + wasm_interface::get().row_overhead_db_limit_bytes;
}
else
// need to calculate the difference between the original rounded byte size and the new rounded byte size
delta += round_to_byte_boundary(keylen + valuelen) - round_to_byte_boundary(keylen + ret);
return created ? 1 : 0;
}
DEFINE_INTRINSIC_FUNCTION6(env,update_str,update_str,i32,i64,scope,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
UPDATE_RECORD_STR(update_record)
UPDATE_RECORD_STR(update_record)
if (ret == -1) return 0;
auto& delta = wasm_interface::get().table_storage_delta;
// need to calculate the difference between the original rounded byte size and the new rounded byte size
delta += round_to_byte_boundary(keylen + valuelen) - round_to_byte_boundary(keylen + ret);
return 1;
}
DEFINE_INTRINSIC_FUNCTION4(env,remove_str,remove_str,i32,i64,scope,i64,table,i32,keyptr,i32,keylen) {
int32_t valueptr=0, valuelen=0;
UPDATE_RECORD_STR(remove_record)
int32_t valueptr=0, valuelen=0;
UPDATE_RECORD_STR(remove_record)
if (ret == -1) return 0;
auto& delta = wasm_interface::get().table_storage_delta;
delta -= round_to_byte_boundary(keylen + ret) + wasm_interface::get().row_overhead_db_limit_bytes;
return 1;
}
DEFINE_INTRINSIC_FUNCTION7(env,load_str,load_str,i32,i64,scope,i64,code,i64,table,i32,keyptr,i32,keylen,i32,valueptr,i32,valuelen) {
......@@ -765,6 +838,27 @@ DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
vm_apply();
if (table_storage_delta != 0)
{
auto rate_limiting = c.db.find<rate_limiting_object, by_name>(c.code);
if (rate_limiting == nullptr)
{
EOS_ASSERT(table_storage_delta <= per_code_account_max_db_limit_mbytes * bytes_per_mbyte, tx_code_db_limit_exceeded, "Database limit exceeded for account=${name}",("name", c.code));
c.mutable_db.create<rate_limiting_object>([delta=this->table_storage_delta,code=c.code](rate_limiting_object& rlo) {
rlo.name = code;
rlo.per_code_account_db_bytes = delta;
});
}
else
{
EOS_ASSERT(table_storage_delta <= (per_code_account_max_db_limit_mbytes * bytes_per_mbyte) - rate_limiting->per_code_account_db_bytes, tx_code_db_limit_exceeded, "Database limit exceeded for account=${name}",("name", c.code));
c.mutable_db.modify(*rate_limiting, [delta=this->table_storage_delta] (rate_limiting_object& rlo) {
rlo.per_code_account_db_bytes += delta;
});
}
}
} FC_CAPTURE_AND_RETHROW() }
void wasm_interface::init( apply_context& c ) {
......@@ -864,11 +958,12 @@ DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
throw;
}
}
current_module = state.instance;
current_memory = getDefaultMemory( current_module );
current_state = &state;
table_key_types = &state.table_key_types;
tables_fixed = state.tables_fixed;
current_module = state.instance;
current_memory = getDefaultMemory( current_module );
current_state = &state;
table_key_types = &state.table_key_types;
tables_fixed = state.tables_fixed;
table_storage_delta = 0;
}
wasm_memory::wasm_memory(wasm_interface& interface)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册