Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions contracts/sysio.bios/sysio.bios.abi
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,6 @@
"name": "net_usage_leeway",
"type": "uint32"
},
{
"name": "context_free_discount_net_usage_num",
"type": "uint32"
},
{
"name": "context_free_discount_net_usage_den",
"type": "uint32"
},
{
"name": "max_block_cpu_usage",
"type": "uint32"
Expand Down
Binary file modified contracts/sysio.bios/sysio.bios.wasm
Binary file not shown.
36 changes: 17 additions & 19 deletions contracts/sysio.system/src/sysio.system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ namespace sysiosystem {
#ifndef SYSTEM_BLOCKCHAIN_PARAMETERS
set_blockchain_parameters( params );
#else
constexpr size_t param_count = 19;
constexpr size_t param_count = 17;
// an upper bound on the serialized size
char buf[1 + sizeof(params) + param_count];
datastream<char*> stream(buf, sizeof(buf));
Expand All @@ -62,24 +62,22 @@ namespace sysiosystem {
<< uint8_t(1) << params.target_block_net_usage_pct
<< uint8_t(2) << params.max_transaction_net_usage
<< uint8_t(3) << params.net_usage_leeway
<< uint8_t(4) << params.context_free_discount_net_usage_num
<< uint8_t(5) << params.context_free_discount_net_usage_den

<< uint8_t(6) << params.max_block_cpu_usage
<< uint8_t(7) << params.target_block_cpu_usage_pct
<< uint8_t(8) << params.max_transaction_cpu_usage
<< uint8_t(9) << params.min_transaction_cpu_usage

<< uint8_t(10) << params.max_transaction_lifetime
<< uint8_t(11) << params.max_transaction_delay
<< uint8_t(12) << params.max_inline_action_size
<< uint8_t(13) << params.max_inline_action_depth
<< uint8_t(14) << params.max_authority_depth

<< uint8_t(15) << params.max_action_return_value_size
<< uint8_t(16) << params.max_kv_key_size
<< uint8_t(17) << params.max_kv_value_size
<< uint8_t(18) << params.max_kv_secondary_key_size;

<< uint8_t(4) << params.max_block_cpu_usage
<< uint8_t(5) << params.target_block_cpu_usage_pct
<< uint8_t(6) << params.max_transaction_cpu_usage
<< uint8_t(7) << params.min_transaction_cpu_usage

<< uint8_t(8) << params.max_transaction_lifetime
<< uint8_t(9) << params.max_transaction_delay
<< uint8_t(10) << params.max_inline_action_size
<< uint8_t(11) << params.max_inline_action_depth
<< uint8_t(12) << params.max_authority_depth

<< uint8_t(13) << params.max_action_return_value_size
<< uint8_t(14) << params.max_kv_key_size
<< uint8_t(15) << params.max_kv_value_size
<< uint8_t(16) << params.max_kv_secondary_key_size;

set_parameters_packed(buf, stream.tellp());
#endif
Expand Down
8 changes: 0 additions & 8 deletions contracts/sysio.system/sysio.system.abi
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,6 @@
"name": "net_usage_leeway",
"type": "uint32"
},
{
"name": "context_free_discount_net_usage_num",
"type": "uint32"
},
{
"name": "context_free_discount_net_usage_den",
"type": "uint32"
},
{
"name": "max_block_cpu_usage",
"type": "uint32"
Expand Down
Binary file modified contracts/sysio.system/sysio.system.wasm
Binary file not shown.
2 changes: 0 additions & 2 deletions contracts/tests/sysio.system_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ class sysio_system_tester : public TESTER {
("target_block_net_usage_pct", 10 + n )
("max_transaction_net_usage", 1000000 + n )
("net_usage_leeway", 500 + n )
("context_free_discount_net_usage_num", 1 + n )
("context_free_discount_net_usage_den", 100 + n )
("max_block_cpu_usage", 10000000 + n )
("target_block_cpu_usage_pct", 10 + n )
("max_transaction_cpu_usage", 1000000 + n )
Expand Down
2 changes: 0 additions & 2 deletions contracts/tests/sysio.system_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,6 @@ fc::mutable_variant_object config_to_variant( const sysio::chain::chain_config&
( "max_block_net_usage", config.max_block_net_usage )
( "target_block_net_usage_pct", config.target_block_net_usage_pct )
( "max_transaction_net_usage", config.max_transaction_net_usage )
( "context_free_discount_net_usage_num", config.context_free_discount_net_usage_num )
( "context_free_discount_net_usage_den", config.context_free_discount_net_usage_den )
( "max_block_cpu_usage", config.max_block_cpu_usage )
( "target_block_cpu_usage_pct", config.target_block_cpu_usage_pct )
( "max_transaction_cpu_usage", config.max_transaction_cpu_usage )
Expand Down
4 changes: 2 additions & 2 deletions docs/ed25519-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Ed25519ph or Ed25519ctx. The existing `recover_key` API retains its signature
format and ASCII-hex digest behavior. Both verification paths use the same raw
helper and libsodium initialization.

The import is available to normal and context-free actions through the genesis whitelist.
The import is available to every action through the genesis whitelist.

## Acceptance rules

Expand Down Expand Up @@ -109,7 +109,7 @@ bool verify_message(const char* message, uint32_t message_size,

`ed25519_intrinsic_tests` deploys the checked-in WASM fixture and covers published
RFC 8032 vectors, frozen acceptance rules, binary/empty messages, independent
WASM loops of 1/24/68 signatures, invalid sizes, context-free actions, memory
WASM loops of 1/24/68 signatures, invalid sizes, memory
bounds, native export dispatch, already-expired execution, and timeout rollback.
The `ed25519_tests` suite in `test_fc` runs all the same acceptance vectors, including invalid lengths,
through the shared verifier and preserves the transaction digest-recovery convention.
Expand Down
3 changes: 1 addition & 2 deletions docs/kv-behavior-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ comes first is not part of this spec.
| **A9.** A `seek` has no size limit. CDT sends a 513-byte all-0xFF key to reach the end of a table, so a governance limit here would break it. | `kv_intrinsic_probe_tests/it_lower_bound_stays_in_the_prefix`, `lookups_take_a_key_of_any_size` |
| **A10.** A `kv_set` mode other than 0 (upsert), 1 (insert) or 2 (update) throws `kv_invalid_mode`. | `kv_intrinsic_probe_tests/kv_set_unknown_mode_rejected`, `intrinsic_value_tests/kv_set_modes_are_a_closed_set`, `intrinsic_value_tests/kv_set_checks_the_table_id_first` |
| **A11.** In a read-only transaction, `kv_set`, `kv_erase`, `kv_idx_store`, `kv_idx_update` and `kv_idx_erase` throw `table_operation_not_permitted`. Reads work. | `kv_api_tests/read_only_trx_rejects_write`, `read_only_rejects_kv_erase`, `read_only_rejects_kv_idx_store`, `read_only_rejects_kv_idx_update`, `read_only_rejects_kv_idx_erase`, `read_only_trx_allows_every_read`, `read_only_trx_tests/db_read_only_mode_test` |
| **A12.** A context-free action cannot call any KV intrinsic. | `kv_intrinsic_probe_tests/context_free_action_cannot_call_any_kv_intrinsic`, `api_part1_tests/cf_action_tests` |
| **A13.** A key a call only looks up has no size limit: `key` in `kv_get` and `kv_erase`, `pri_key` and `sec_key` in `kv_idx_erase`, `pri_key` and `old_sec_key` in `kv_idx_update`, and `sec_key` in `kv_idx_find`. With no row at that key the call is a plain miss, so a key over 512 bytes misses rather than throws. | `kv_intrinsic_probe_tests/lookups_take_a_key_of_any_size` |
| **A12.** A key a call only looks up has no size limit: `key` in `kv_get` and `kv_erase`, `pri_key` and `sec_key` in `kv_idx_erase`, `pri_key` and `old_sec_key` in `kv_idx_update`, and `sec_key` in `kv_idx_find`. With no row at that key the call is a plain miss, so a key over 512 bytes misses rather than throws. | `kv_intrinsic_probe_tests/lookups_take_a_key_of_any_size` |

## 3. Status values

Expand Down
11 changes: 3 additions & 8 deletions docs/roa-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,6 @@ resources. On a regular action the protocol requires all three of the following
- the **same actor** also appears on that action under a real permission, and
- the transaction carries **signatures** satisfying that paired declared authorization.

A context-free action takes the opposite form. It may carry the marker *alone* — a paired real
permission there is rejected outright — and only when that same actor is already an explicit payer
on one of the transaction's regular actions.

The paired permission is not required to be `active`. `authorization_manager` looks for any entry
whose actor matches the payer and whose permission is not `sysio.payer` itself, then satisfies it
like any other declared authority — so `owner`, or a custom permission linked to that action, works
Expand Down Expand Up @@ -163,8 +159,8 @@ flowchart TD
F --> H["Actor billed CPU and NET, contract not.<br/>Marker authorizes RAM billed to the actor;<br/>contract may still bill RAM to itself."]
```

Declared regular actions only. A context-free action takes the marker alone, as above; inline and
notification execution differ on both authorization and billing, below.
Declared actions only. Inline and notification execution differ on both authorization and billing,
below.

The objective billing map is populated only from the actions a transaction *declares*, and is keyed
on `payer()` — so two declared actions sharing a payer aggregate into one entry. An authorizing
Expand Down Expand Up @@ -705,8 +701,7 @@ Two anchors to calibrate against:

- **NET is small and predictable, but it is not just the action.** Each action is billed its own
serialized size *plus a share of the transaction's overhead* — a fixed 16 bytes, the signatures,
the extensions and the header, divided across the actions and rounded up. A context-free action
is additionally billed the bytes of its matching `context_free_data` entry:
the extensions and the header, divided across the actions and rounded up:

```cpp
// libraries/chain/transaction.cpp
Expand Down
1 change: 0 additions & 1 deletion libraries/chain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ set(CHAIN_WEBASSEMBLY_SOURCES
webassembly/authorization.cpp
webassembly/cf_system.cpp
webassembly/cf_transaction.cpp
webassembly/context_free.cpp
webassembly/console.cpp
webassembly/crypto.cpp
webassembly/database.cpp
Expand Down
106 changes: 33 additions & 73 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ apply_context::apply_context(controller& con, transaction_context& trx_ctx, uint
action_trace& trace = trx_ctx.get_action_trace(action_ordinal);
act = &trace.act;
receiver = trace.receiver;
context_free = trace.context_free;
}

void apply_context::exec_one()
Expand Down Expand Up @@ -99,38 +98,36 @@ void apply_context::exec_one()
action_return_value.clear();
receiver_account = &db.get<account_object,by_name>( receiver );
receiver_account_metadata = db.find<account_metadata_object,by_name>( receiver );
if( !(context_free && control.skip_trx_checks()) ) {
privileged = receiver_account_metadata != nullptr && receiver_account_metadata->is_privileged();
auto native = control.find_apply_handler( receiver, act->account, act->name );
if( native ) {
if( trx_context.enforce_whiteblacklist && control.is_speculative_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act->account, act->name );
}
(*native)( *this );
privileged = receiver_account_metadata != nullptr && receiver_account_metadata->is_privileged();
auto native = control.find_apply_handler( receiver, act->account, act->name );
if( native ) {
if( trx_context.enforce_whiteblacklist && control.is_speculative_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act->account, act->name );
}
(*native)( *this );
}

if( receiver_account_metadata != nullptr && receiver_account_metadata->code_hash != digest_type() ) {
if( trx_context.enforce_whiteblacklist && control.is_speculative_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act->account, act->name );
}
try {
control.get_wasm_interface().apply( receiver_account_metadata->code_hash,
receiver_account_metadata->vm_type,
receiver_account_metadata->vm_version,
*this );
} catch( const wasm_exit& ) {}
} else {
// allow inline and notify to non-existing contracts
// allow onblock and native actions when no sysio system contract by allowing no contract on sysio
if (receiver != sysio::chain::config::system_account_name && act->account == receiver && get_sender().empty()) {
SYS_ASSERT(false, action_validate_exception,
"No contract for action {} on account {}", act->name, receiver);
}
if( receiver_account_metadata != nullptr && receiver_account_metadata->code_hash != digest_type() ) {
if( trx_context.enforce_whiteblacklist && control.is_speculative_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act->account, act->name );
}
try {
control.get_wasm_interface().apply( receiver_account_metadata->code_hash,
receiver_account_metadata->vm_type,
receiver_account_metadata->vm_version,
*this );
} catch( const wasm_exit& ) {}
} else {
// allow inline and notify to non-existing contracts
// allow onblock and native actions when no sysio system contract by allowing no contract on sysio
if (receiver != sysio::chain::config::system_account_name && act->account == receiver && get_sender().empty()) {
SYS_ASSERT(false, action_validate_exception,
"No contract for action {} on account {}", act->name, receiver);
}
validate_account_ram_deltas();
}
validate_account_ram_deltas();
} FC_RETHROW_EXCEPTIONS( warn, "{} <= {}::{} pending console output: {}",
receiver, act->account, act->name, _pending_console_output )

Expand Down Expand Up @@ -265,14 +262,10 @@ void apply_context::exec()
exec_one();
}

if( !_cfa_inline_actions.empty() || !_inline_actions.empty() ) {
if( !_inline_actions.empty() ) {
SYS_ASSERT( recurse_depth < control.get_global_properties().configuration.max_inline_action_depth,
transaction_exception, "max inline action depth per transaction reached" );

for( uint32_t ordinal : _cfa_inline_actions ) {
trx_context.execute_action( ordinal, recurse_depth + 1 );
}

for( uint32_t ordinal : _inline_actions ) {
trx_context.execute_action( ordinal, recurse_depth + 1 );
}
Expand Down Expand Up @@ -343,7 +336,7 @@ void apply_context::require_recipient( account_name recipient ) {
if( !has_recipient(recipient) ) {
_notified.emplace_back(
recipient,
schedule_action( action_ordinal, recipient, false )
schedule_action( action_ordinal, recipient )
);

if( auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()) ) {
Expand Down Expand Up @@ -407,46 +400,28 @@ void apply_context::execute_inline( action&& a ) {

auto inline_receiver = a.account;
_inline_actions.emplace_back(
schedule_action( std::move(a), inline_receiver, false )
schedule_action( std::move(a), inline_receiver )
);

if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_send_inline();
}
}

void apply_context::execute_context_free_inline( action&& a ) {
auto* code = control.db().find<account_object, by_name>(a.account);
SYS_ASSERT( code != nullptr, action_validate_exception,
"inline action's code account {} does not exist", a.account );

SYS_ASSERT( a.authorization.size() == 0, action_validate_exception,
"inline context-free actions cannot have authorizations" );

auto inline_receiver = a.account;
_cfa_inline_actions.emplace_back(
schedule_action( std::move(a), inline_receiver, true )
);

if( auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_send_context_free_inline();
}
}

uint32_t apply_context::schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free )
uint32_t apply_context::schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver )
{
uint32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule,
receiver, context_free,
receiver,
action_ordinal, first_receiver_action_ordinal );

act = &trx_context.get_action_trace( action_ordinal ).act;
return scheduled_action_ordinal;
}

uint32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free )
uint32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver )
{
uint32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule),
receiver, context_free,
receiver,
action_ordinal, first_receiver_action_ordinal );

act = &trx_context.get_action_trace( action_ordinal ).act;
Expand Down Expand Up @@ -497,21 +472,6 @@ int apply_context::get_action( uint32_t type, uint32_t index, char* buffer, size
return ps;
}

int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const
{
const auto& trx = trx_context.packed_trx.get_signed_transaction();

if( index >= trx.context_free_data.size() ) return -1;

auto s = trx.context_free_data[index].size();
if( buffer_size == 0 ) return s;

auto copy_size = std::min( buffer_size, s );
memcpy( buffer, trx.context_free_data[index].data(), copy_size );

return copy_size;
}

uint64_t apply_context::next_global_sequence() {
const auto& p = control.get_dynamic_global_properties();
if ( trx_context.is_read_only() ) {
Expand Down
Loading
Loading