Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(runtime) - Mitigate the receipt size limit bug #12633

Merged
merged 16 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ fn setup_account(
/// it can be called successfully.
fn setup_contract(env: &mut TestEnv, nonce: &mut u64) {
let block = env.clients[0].chain.get_head_block().unwrap();
let contract = near_test_contracts::rs_contract();
let contract = near_test_contracts::congestion_control_test_contract();

let signer_id: AccountId = ACCOUNT_PARENT_ID.parse().unwrap();
let signer = InMemorySigner::test_signer(&signer_id);
Expand Down Expand Up @@ -787,8 +787,8 @@ fn measure_tx_limit(
let congestion_level = congestion_info.localized_congestion_level(&config);
// congestion should be non-trivial and below the upper limit
assert!(
incoming_congestion > upper_limit_congestion / 4.0,
"{incoming_congestion} > {upper_limit_congestion} / 4 failed, {congestion_info:?}"
incoming_congestion > upper_limit_congestion / 2.0,
"{incoming_congestion} > {upper_limit_congestion} / 2 failed, {congestion_info:?}"
);
assert!(
congestion_level < upper_limit_congestion,
Expand Down
5 changes: 5 additions & 0 deletions runtime/near-test-contracts/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ fn try_main() -> Result<(), Error> {
&["--features", &test_contract_features_string],
"test_contract_rs",
)?;
build_contract(
"./congestion-control-test-contract",
&["--features", &test_contract_features_string],
"congestion_control_test_contract",
)?;

test_contract_features.push("nightly");
let test_contract_features_string = test_contract_features.join(",");
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "congestion-control-test-contract"
version = "0.1.0"
authors = ["Near Inc <[email protected]>"]
publish = false
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
base64 = "0.21"
serde_json = "1"

[profile.release]
codegen-units = 1
# Tell `rustc` to optimize for small code size.
opt-level = "z"
strip = true
lto = true
debug = false
panic = "abort"
rpath = false
debug-assertions = false
incremental = false

[workspace]
members = []

[features]
nightly = []
latest_protocol = []
test_features = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
//! This contract is used for congestion control tests that are sensitive to contract size.
//! For some tests large contract size causes less congestion, and the checks fail.
//! Let's use a separate small contract for these tests.

#![allow(clippy::all)]

#[allow(unused)]
extern "C" {
Comment on lines +7 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Is all of it needed?
  2. Is there any way we can reuse the existing one or refactor it to avoid copy pasting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah there's a lot of new functions. I tried to use the existing ones, but I want to do very specific things and the existing ones don't really do what I want to do.
It'd be nice if there was an easy way to create a per-test contract, maybe inside the test code itself. One giant contract gets a bit chaotic :/

Copy link
Collaborator

@nagisa nagisa Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice if there was an easy way to create a per-test contract, maybe inside the test code itself. One giant contract gets a bit chaotic :/

So there are some programmatically constructed contracts in near-test-contracts but trust me the experience maintaining those is quite a bit worse as you end up having to hand-roll WebAssembly, pretty much.

If we wanted to make it conversible from Rust I think it would still be possible technically, but has very significant drawbacks. There's this saying about maintainability along the lines of "code is written once, read many times", but this quote gets cuts off before it gets to "and compiled a further thousand times more." Unfortunately compiling and linking up a huge number of Rust binaries would be a huge hit for our development experience.

While I don't necessarily object to having a couple additional contract crates, I think in general we should probably aim to have as few of these as possible and try to achieve a good maintainability/readability within the confines of a crate (by e.g. splitting the code up into modules – this also naturally enables reuse of the duplicate code at hand.)

// #############
// # Registers #
// #############
fn read_register(register_id: u64, ptr: u64);
fn register_len(register_id: u64) -> u64;
// ###############
// # Context API #
// ###############
fn current_account_id(register_id: u64);
fn signer_account_id(register_id: u64);
fn signer_account_pk(register_id: u64);
fn predecessor_account_id(register_id: u64);
fn input(register_id: u64);
fn block_index() -> u64;
fn block_timestamp() -> u64;
fn epoch_height() -> u64;
fn storage_usage() -> u64;
// #################
// # Economics API #
// #################
fn account_balance(balance_ptr: u64);
fn attached_deposit(balance_ptr: u64);
fn prepaid_gas() -> u64;
fn used_gas() -> u64;
// ############
// # Math API #
// ############
fn random_seed(register_id: u64);
fn sha256(value_len: u64, value_ptr: u64, register_id: u64);
// #####################
// # Miscellaneous API #
// #####################
fn value_return(value_len: u64, value_ptr: u64);
fn panic();
fn panic_utf8(len: u64, ptr: u64);
fn log_utf8(len: u64, ptr: u64);
fn log_utf16(len: u64, ptr: u64);
fn abort(msg_ptr: u32, filename_ptr: u32, line: u32, col: u32);
// ################
// # Promises API #
// ################
fn promise_create(
account_id_len: u64,
account_id_ptr: u64,
method_name_len: u64,
method_name_ptr: u64,
arguments_len: u64,
arguments_ptr: u64,
amount_ptr: u64,
gas: u64,
) -> u64;
fn promise_then(
promise_index: u64,
account_id_len: u64,
account_id_ptr: u64,
method_name_len: u64,
method_name_ptr: u64,
arguments_len: u64,
arguments_ptr: u64,
amount_ptr: u64,
gas: u64,
) -> u64;
fn promise_and(promise_idx_ptr: u64, promise_idx_count: u64) -> u64;
fn promise_batch_create(account_id_len: u64, account_id_ptr: u64) -> u64;
fn promise_batch_then(promise_index: u64, account_id_len: u64, account_id_ptr: u64) -> u64;
// #######################
// # Promise API actions #
// #######################
fn promise_batch_action_create_account(promise_index: u64);
fn promise_batch_action_deploy_contract(promise_index: u64, code_len: u64, code_ptr: u64);
fn promise_batch_action_function_call(
promise_index: u64,
method_name_len: u64,
method_name_ptr: u64,
arguments_len: u64,
arguments_ptr: u64,
amount_ptr: u64,
gas: u64,
);
#[cfg(feature = "latest_protocol")]
fn promise_batch_action_function_call_weight(
promise_index: u64,
method_name_len: u64,
method_name_ptr: u64,
arguments_len: u64,
arguments_ptr: u64,
amount_ptr: u64,
gas: u64,
gas_weight: u64,
);
fn promise_batch_action_transfer(promise_index: u64, amount_ptr: u64);
fn promise_batch_action_stake(
promise_index: u64,
amount_ptr: u64,
public_key_len: u64,
public_key_ptr: u64,
);
fn promise_batch_action_add_key_with_full_access(
promise_index: u64,
public_key_len: u64,
public_key_ptr: u64,
nonce: u64,
);
fn promise_batch_action_add_key_with_function_call(
promise_index: u64,
public_key_len: u64,
public_key_ptr: u64,
nonce: u64,
allowance_ptr: u64,
receiver_id_len: u64,
receiver_id_ptr: u64,
method_names_len: u64,
method_names_ptr: u64,
);
fn promise_batch_action_delete_key(
promise_index: u64,
public_key_len: u64,
public_key_ptr: u64,
);
fn promise_batch_action_delete_account(
promise_index: u64,
beneficiary_id_len: u64,
beneficiary_id_ptr: u64,
);
// ########################
// # Promise Yield/Resume #
// ########################
fn promise_yield_create(
method_name_len: u64,
method_name_ptr: u64,
arguments_len: u64,
arguments_ptr: u64,
gas: u64,
gas_weight: u64,
register_id: u64,
) -> u64;
fn promise_yield_resume(
data_id_len: u64,
data_id_ptr: u64,
payload_len: u64,
payload_ptr: u64,
) -> u32;
// #######################
// # Promise API results #
// #######################
fn promise_results_count() -> u64;
fn promise_result(result_idx: u64, register_id: u64) -> u64;
fn promise_return(promise_id: u64);
// ###############
// # Storage API #
// ###############
fn storage_write(
key_len: u64,
key_ptr: u64,
value_len: u64,
value_ptr: u64,
register_id: u64,
) -> u64;
fn storage_read(key_len: u64, key_ptr: u64, register_id: u64) -> u64;
fn storage_remove(key_len: u64, key_ptr: u64, register_id: u64) -> u64;
fn storage_has_key(key_len: u64, key_ptr: u64) -> u64;
fn storage_iter_prefix(prefix_len: u64, prefix_ptr: u64) -> u64;
fn storage_iter_range(start_len: u64, start_ptr: u64, end_len: u64, end_ptr: u64) -> u64;
fn storage_iter_next(iterator_id: u64, key_register_id: u64, value_register_id: u64) -> u64;
fn gas(opcodes: u32);
// #################
// # Validator API #
// #################
fn validator_stake(account_id_len: u64, account_id_ptr: u64, stake_ptr: u64);
fn validator_total_stake(stake_ptr: u64);
// ###################
// # Math Extensions #
// ###################
#[cfg(feature = "latest_protocol")]
fn ripemd160(value_len: u64, value_ptr: u64, register_id: u64);
// #################
// # alt_bn128 API #
// #################
#[cfg(feature = "latest_protocol")]
fn alt_bn128_g1_multiexp(value_len: u64, value_ptr: u64, register_id: u64);
#[cfg(feature = "latest_protocol")]
fn alt_bn128_g1_sum(value_len: u64, value_ptr: u64, register_id: u64);
#[cfg(feature = "latest_protocol")]
fn alt_bn128_pairing_check(value_len: u64, value_ptr: u64) -> u64;

#[cfg(feature = "test_features")]
fn sleep_nanos(nanos: u64);

#[cfg(feature = "test_features")]
fn burn_gas(gas: u64);
}

#[unsafe(no_mangle)]
pub unsafe fn loop_forever() {
loop {}
}
5 changes: 5 additions & 0 deletions runtime/near-test-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ pub fn estimator_contract() -> &'static [u8] {
include_bytes!(env!("CONTRACT_estimator_contract"))
}

pub fn congestion_control_test_contract() -> &'static [u8] {
include_bytes!(env!("CONTRACT_congestion_control_test_contract"))
}

#[test]
fn smoke_test() {
assert!(!rs_contract().is_empty());
Expand All @@ -134,6 +138,7 @@ fn smoke_test() {
assert!(!fuzzing_contract().is_empty());
assert!(!backwards_compatible_rs_contract().is_empty());
assert!(!ft_contract().is_empty());
assert!(!congestion_control_test_contract().is_empty());
}

pub struct LargeContract {
Expand Down
Loading