std::unique_ptr<wasm_instantiated_module_interface>& get_instantiated_module(const digest_type& code_id, const shared_vector<char>& code) { auto it = instantiation_cache.find(code_id); if(it == instantiation_cache.end()) { IR::Module module; try { Serialization::MemoryInputStream stream((const U8*)code.data(), code.size()); WASM::serialize(stream, module); } catch(Serialization::FatalSerializationException& e) { EOS_ASSERT(false, wasm_serialization_error, e.message.c_str()); } wasm_injections::wasm_binary_injection injector(module); injector.inject(); std::vector<U8> bytes; try { Serialization::ArrayOutputStream outstream; WASM::serialize(outstream, module); bytes = outstream.getBytes(); } catch(Serialization::FatalSerializationException& e) { EOS_ASSERT(false, wasm_serialization_error, e.message.c_str()); } it = instantiation_cache.emplace(code_id, runtime_interface->instantiate_module((const char*)bytes.data(), bytes.size(), parse_initial_memory(module))).first; } return it->second; }
void apply_eosio_deleteauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); auto remove = context.act.data_as<deleteauth>(); context.require_authorization(remove.account); // only here to mark the single authority on this action as used EOS_ASSERT(remove.permission != config::active_name, action_validate_exception, "Cannot delete active authority"); EOS_ASSERT(remove.permission != config::owner_name, action_validate_exception, "Cannot delete owner authority"); auto& authorization = context.control.get_mutable_authorization_manager(); auto& db = context.db; { // Check for links to this permission const auto& index = db.get_index<permission_link_index, by_permission_name>(); auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission)); EOS_ASSERT(range.first == range.second, action_validate_exception, "Cannot delete a linked authority. Unlink the authority first"); } const auto& permission = authorization.get_permission({remove.account, remove.permission}); int64_t old_size = config::billable_size_v<permission_object> + permission.auth.get_billable_size(); authorization.remove_permission( permission ); context.trx_context.add_ram_usage( remove.account, -old_size ); }
std::unique_ptr<wasm_instantiated_module_interface> binaryen_runtime::instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory) { try { vector<char> code(code_bytes, code_bytes + code_size); unique_ptr<Module> module(new Module()); WasmBinaryBuilder builder(*module, code, false); builder.read(); EOS_ASSERT(module->memory.initial * Memory::kPageSize <= wasm_constraints::maximum_linear_memory, binaryen_exception, "exceeds maximum linear memory"); // create a temporary globals to use TrivialGlobalManager globals; for (auto& global : module->globals) { globals[global->name] = ConstantExpressionRunner<TrivialGlobalManager>(globals).visit(global->init).value; } call_indirect_table_type table; table.resize(module->table.initial); for (auto& segment : module->table.segments) { Address offset = ConstantExpressionRunner<TrivialGlobalManager>(globals).visit(segment.offset).value.geti32(); EOS_ASSERT( uint64_t(offset) + segment.data.size() <= module->table.initial, binaryen_exception, ""); for (size_t i = 0; i != segment.data.size(); ++i) { table[offset + i] = segment.data[i]; } } // initialize the import lut import_lut_type import_lut; import_lut.reserve(module->imports.size()); for (auto& import : module->imports) { std::string full_name = string(import->module.c_str()) + "." + string(import->base.c_str()); if (import->kind == ExternalKind::Function) { auto& intrinsic_map = intrinsic_registrator::get_map(); auto intrinsic_itr = intrinsic_map.find(full_name); if (intrinsic_itr != intrinsic_map.end()) { import_lut.emplace(make_pair((uintptr_t)import.get(), intrinsic_itr->second)); continue; } } EOS_ASSERT( !"unresolvable", wasm_exception, "${module}.${export} unresolveable", ("module",import->module.c_str())("export",import->base.c_str()) ); } return std::make_unique<binaryen_instantiated_module>(_memory, initial_memory, move(table), move(import_lut), move(module)); } catch (const ParseException &e) { FC_THROW_EXCEPTION(wasm_execution_error, "Error building interpreter: ${s}", ("s", e.text)); } }
void apply_eosio_linkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); auto requirement = context.act.data_as<linkauth>(); try { EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty"); context.require_authorization(requirement.account); // only here to mark the single authority on this action as used auto& db = context.db; const auto *account = db.find<account_object, by_name>(requirement.account); EOS_ASSERT(account != nullptr, account_query_exception, "Failed to retrieve account: ${account}", ("account", requirement.account)); // Redundant? const auto *code = db.find<account_object, by_name>(requirement.code); EOS_ASSERT(code != nullptr, account_query_exception, "Failed to retrieve code for account: ${account}", ("account", requirement.code)); if( requirement.requirement != config::eosio_any_name ) { const auto *permission = db.find<permission_object, by_name>(requirement.requirement); EOS_ASSERT(permission != nullptr, permission_query_exception, "Failed to retrieve permission: ${permission}", ("permission", requirement.requirement)); } auto link_key = boost::make_tuple(requirement.account, requirement.code, requirement.type); auto link = db.find<permission_link_object, by_action_name>(link_key); if( link ) { EOS_ASSERT(link->required_permission != requirement.requirement, action_validate_exception, "Attempting to update required authority, but new requirement is same as old"); db.modify(*link, [requirement = requirement.requirement](permission_link_object& link) { link.required_permission = requirement; }); } else { const auto& l = db.create<permission_link_object>([&requirement](permission_link_object& link) { link.account = requirement.account; link.code = requirement.code; link.message_type = requirement.type; link.required_permission = requirement.requirement; }); context.trx_context.add_ram_usage( l.account, (int64_t)(config::billable_size_v<permission_link_object>) ); } } FC_CAPTURE_AND_RETHROW((requirement)) }
void apply_eosio_unlinkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); auto& db = context.db; auto unlink = context.act.data_as<unlinkauth>(); context.require_authorization(unlink.account); // only here to mark the single authority on this action as used auto link_key = boost::make_tuple(unlink.account, unlink.code, unlink.type); auto link = db.find<permission_link_object, by_action_name>(link_key); EOS_ASSERT(link != nullptr, action_validate_exception, "Attempting to unlink authority, but no link found"); context.trx_context.add_ram_usage( link->account, -(int64_t)(config::billable_size_v<permission_link_object>) ); db.remove(*link); }
void reflector_verify()const { EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" ); EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); }
friend asset operator + (const asset& a, const asset& b) { EOS_ASSERT(a.get_symbol() == b.get_symbol(), asset_type_exception, "addition between two different asset is not allowed"); return asset(a.amount + b.amount, a.get_symbol()); }
friend bool operator < (const asset& a, const asset& b) { EOS_ASSERT(a.get_symbol() == b.get_symbol(), asset_type_exception, "logical operation between two different asset is not allowed"); return std::tie(a.amount,a.get_symbol()) < std::tie(b.amount,b.get_symbol()); }
asset& operator -= (const asset& o) { EOS_ASSERT(get_symbol() == o.get_symbol(), asset_type_exception, "subtraction between two different asset is not allowed"); amount -= o.amount; return *this; }
explicit asset(share_type a = 0, symbol id = symbol(CORE_SYMBOL)) :amount(a), sym(id) { EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" ); EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" ); }
T data_as()const { EOS_ASSERT( account == T::get_account(), action_type_exception, "account is not consistent with action struct" ); EOS_ASSERT( name == T::get_name(), action_type_exception, "action name is not consistent with action struct" ); return fc::raw::unpack<T>(data); }
inline auto convert_native_to_literal(const interpreter_interface* interface, char* ptr) { const char* base = interface->memory.data; const char* top_of_memory = base + interface->current_memory_size; EOS_ASSERT(ptr >= base && ptr < top_of_memory, wasm_execution_error, "returning pointer not in linear memory"); return Literal((int)(ptr - base)); }
inline array_ptr<T> array_ptr_impl (interpreter_interface* interface, uint32_t ptr, uint32_t length) { EOS_ASSERT( length < INT_MAX/(uint32_t)sizeof(T), binaryen_exception, "length will overflow" ); return array_ptr<T>((T*)(interface->get_validated_pointer(ptr, length * (uint32_t)sizeof(T)))); }
void apply_eosio_updateauth(apply_context& context) { auto update = context.act.data_as<updateauth>(); context.require_authorization(update.account); // only here to mark the single authority on this action as used auto& authorization = context.control.get_mutable_authorization_manager(); auto& db = context.db; EOS_ASSERT(!update.permission.empty(), action_validate_exception, "Cannot create authority with empty name"); EOS_ASSERT( update.permission.to_string().find( "eosio." ) != 0, action_validate_exception, "Permission names that start with 'eosio.' are reserved" ); EOS_ASSERT(update.permission != update.parent, action_validate_exception, "Cannot set an authority as its own parent"); db.get<account_object, by_name>(update.account); EOS_ASSERT(validate(update.auth), action_validate_exception, "Invalid authority: ${auth}", ("auth", update.auth)); if( update.permission == config::active_name ) EOS_ASSERT(update.parent == config::owner_name, action_validate_exception, "Cannot change active authority's parent from owner", ("update.parent", update.parent) ); if (update.permission == config::owner_name) EOS_ASSERT(update.parent.empty(), action_validate_exception, "Cannot change owner authority's parent"); else EOS_ASSERT(!update.parent.empty(), action_validate_exception, "Only owner permission can have empty parent" ); if( update.auth.waits.size() > 0 ) { auto max_delay = context.control.get_global_properties().configuration.max_transaction_delay; EOS_ASSERT( update.auth.waits.back().wait_sec <= max_delay, action_validate_exception, "Cannot set delay longer than max_transacton_delay, which is ${max_delay} seconds", ("max_delay", max_delay) ); } validate_authority_precondition(context, update.auth); auto permission = authorization.find_permission({update.account, update.permission}); // If a parent_id of 0 is going to be used to indicate the absence of a parent, then we need to make sure that the chain // initializes permission_index with a dummy object that reserves the id of 0. authorization_manager::permission_id_type parent_id = 0; if( update.permission != config::owner_name ) { auto& parent = authorization.get_permission({update.account, update.parent}); parent_id = parent.id; } if( permission ) { EOS_ASSERT(parent_id == permission->parent, action_validate_exception, "Changing parent authority is not currently supported"); int64_t old_size = (int64_t)(config::billable_size_v<permission_object> + permission->auth.get_billable_size()); authorization.modify_permission( *permission, update.auth ); int64_t new_size = (int64_t)(config::billable_size_v<permission_object> + permission->auth.get_billable_size()); context.trx_context.add_ram_usage( permission->owner, new_size - old_size ); } else { const auto& p = authorization.create_permission( update.account, update.permission, parent_id, update.auth ); int64_t new_size = (int64_t)(config::billable_size_v<permission_object> + p.auth.get_billable_size()); context.trx_context.add_ram_usage( update.account, new_size ); } }