Repository: near/nearcore
Pull request #13370: feat: remove pessimistic gas pricing
Author: login: jakmeier
Created: 2025-04-15T09:11:25Z | Merged: 2025-04-20T18:08:46Z

With `ProtocolFeature::ReducedGasRefunds` enabled, we remove the pessimistic gas price increase. This PR makes this change for nightly only.

This is the first part for NEP-536, which aims to reduce the number of gas refund receipts that are generated in the system. Pessimistic gas pricing is one major cause for such refunds, as it forces all non-local receipts to pay more gas than it likely needs.

# Testing strategy

There is already a number of integration tests that had to be updated, since the number of receipts has changed. (The refunding receipts is missing with the feature enabled.) This should be enough to test the basic functionality.

The other features for NEP-536, which adds a fee for all remaining gas refunds, will require new integration tests which will also indirectly test that pessimistic gas pricing no longer applies.


Diff:
diff --git a/chain/chain/src/runtime/mod.rs b/chain/chain/src/runtime/mod.rs
index 29037a008c3..8639f0d138a 100644
--- a/chain/chain/src/runtime/mod.rs
+++ b/chain/chain/src/runtime/mod.rs
@@ -530,7 +530,8 @@ impl RuntimeAdapter for NightshadeRuntime {
     ) -> Result<(), InvalidTxError> {
         let runtime_config = self.runtime_config_store.get_config(current_protocol_version);
 
-        let cost = tx_cost(runtime_config, &validated_tx.to_tx(), gas_price)?;
+        let cost =
+            tx_cost(runtime_config, &validated_tx.to_tx(), gas_price, current_protocol_version)?;
         let shard_uid = shard_layout
             .account_id_to_shard_uid(validated_tx.to_signed_tx().transaction.signer_id());
         let state_update = self.tries.new_trie_update(shard_uid, state_root);
@@ -676,28 +677,27 @@ impl RuntimeAdapter for NightshadeRuntime {
                 let (mut signer, mut access_key) =
                     get_signer_and_access_key(&state_update, &validated_tx)
                         .map_err(|_| Error::InvalidTransactions)?;
-                let verify_result =
-                    tx_cost(runtime_config, &validated_tx.to_tx(), prev_block.next_gas_price)
-                        .map_err(InvalidTxError::from)
-                        .and_then(|cost| {
-                            verify_and_charge_tx_ephemeral(
-                                runtime_config,
-                                &mut signer,
-                                &mut access_key,
-                                &validated_tx,
-                                &cost,
-                                Some(next_block_height),
-                            )
-                        })
-                        .and_then(|verification_res| {
-                            set_tx_state_changes(
-                                &mut state_update,
-                                &validated_tx,
-                                &signer,
-                                &access_key,
-                            );
-                            Ok(verification_res)
-                        });
+                let verify_result = tx_cost(
+                    runtime_config,
+                    &validated_tx.to_tx(),
+                    prev_block.next_gas_price,
+                    protocol_version,
+                )
+                .map_err(InvalidTxError::from)
+                .and_then(|cost| {
+                    verify_and_charge_tx_ephemeral(
+                        runtime_config,
+                        &mut signer,
+                        &mut access_key,
+                        &validated_tx,
+                        &cost,
+                        Some(next_block_height),
+                    )
+                })
+                .and_then(|verification_res| {
+                    set_tx_state_changes(&mut state_update, &validated_tx, &signer, &access_key);
+                    Ok(verification_res)
+                });
 
                 match verify_result {
                     Ok(cost) => {
diff --git a/chain/indexer/src/streamer/mod.rs b/chain/indexer/src/streamer/mod.rs
index d264bd4512e..9e2bb2f3719 100644
--- a/chain/indexer/src/streamer/mod.rs
+++ b/chain/indexer/src/streamer/mod.rs
@@ -134,6 +134,7 @@ pub async fn build_streamer_message(
                 .filter(|tx| tx.transaction.signer_id == tx.transaction.receiver_id)
                 .collect::<Vec<&IndexerTransactionWithOutcome>>(),
             &block,
+            protocol_config_view.protocol_version,
         )
         .await?;
 
@@ -340,6 +341,7 @@ async fn find_local_receipt_by_id_in_block(
 ) -> Result<Option<views::ReceiptView>, FailedToFetchData> {
     let chunks = fetch_block_new_chunks(&client, &block, shard_tracker).await?;
 
+    let protocol_config_view = fetch_protocol_config(&client, block.header.hash).await?;
     let mut shards_outcomes = fetch_outcomes(&client, block.header.hash).await?;
 
     for chunk in chunks {
@@ -366,6 +368,7 @@ async fn find_local_receipt_by_id_in_block(
                 &runtime_config,
                 vec![&indexer_transaction],
                 &block,
+                protocol_config_view.protocol_version,
             )
             .await?;
 
diff --git a/chain/indexer/src/streamer/utils.rs b/chain/indexer/src/streamer/utils.rs
index e41bb4ba1df..c0c59a31776 100644
--- a/chain/indexer/src/streamer/utils.rs
+++ b/chain/indexer/src/streamer/utils.rs
@@ -2,6 +2,7 @@ use actix::Addr;
 
 use near_indexer_primitives::IndexerTransactionWithOutcome;
 use near_parameters::RuntimeConfig;
+use near_primitives::types::ProtocolVersion;
 use near_primitives::views;
 use node_runtime::config::tx_cost;
 
@@ -13,6 +14,7 @@ pub(crate) async fn convert_transactions_sir_into_local_receipts(
     runtime_config: &RuntimeConfig,
     txs: Vec<&IndexerTransactionWithOutcome>,
     block: &views::BlockView,
+    protocol_version: ProtocolVersion,
 ) -> Result<Vec<views::ReceiptView>, FailedToFetchData> {
     if txs.is_empty() {
         return Ok(vec![]);
@@ -43,7 +45,8 @@ pub(crate) async fn convert_transactions_sir_into_local_receipts(
                 },
             );
             // Can't use ValidatedTransaction here because transactions in a chunk can be invalid (RelaxedChunkValidation feature)
-            let cost = tx_cost(&runtime_config, &tx, prev_block_gas_price).unwrap();
+            let cost =
+                tx_cost(&runtime_config, &tx, prev_block_gas_price, protocol_version).unwrap();
             views::ReceiptView {
                 predecessor_id: indexer_tx.transaction.signer_id.clone(),
                 receiver_id: indexer_tx.transaction.receiver_id.clone(),
diff --git a/core/parameters/res/runtime_configs/149.yaml b/core/parameters/res/runtime_configs/149.yaml
new file mode 100644
index 00000000000..9f277688b7d
--- /dev/null
+++ b/core/parameters/res/runtime_configs/149.yaml
@@ -0,0 +1,10 @@
+pessimistic_gas_price_inflation: {
+  old: {
+    numerator: 103,
+    denominator: 100,
+  },
+  new: {
+    numerator: 1,
+    denominator: 1,
+  }
+}
\ No newline at end of file
diff --git a/core/parameters/src/config_store.rs b/core/parameters/src/config_store.rs
index 46bb2d57d65..1140be83ec3 100644
--- a/core/parameters/src/config_store.rs
+++ b/core/parameters/src/config_store.rs
@@ -56,6 +56,7 @@ static CONFIG_DIFFS: &[(ProtocolVersion, &str)] = &[
     (74, include_config!("74.yaml")),
     (77, include_config!("77.yaml")),
     (129, include_config!("129.yaml")),
+    (149, include_config!("149.yaml")),
 ];
 
 /// Testnet parameters for versions <= 29, which (incorrectly) differed from mainnet parameters
diff --git a/core/parameters/src/snapshots/near_parameters__config_store__tests__149.json.snap b/core/parameters/src/snapshots/near_parameters__config_store__tests__149.json.snap
new file mode 100644
index 00000000000..887bcc311c6
--- /dev/null
+++ b/core/parameters/src/snapshots/near_parameters__config_store__tests__149.json.snap
@@ -0,0 +1,259 @@
+---
+source: core/parameters/src/config_store.rs
+expression: config_view
+---
+{
+  "storage_amount_per_byte": "10000000000000000000",
+  "transaction_costs": {
+    "action_receipt_creation_config": {
+      "send_sir": 108059500000,
+      "send_not_sir": 108059500000,
+      "execution": 108059500000
+    },
+    "data_receipt_creation_config": {
+      "base_cost": {
+        "send_sir": 36486732312,
+        "send_not_sir": 36486732312,
+        "execution": 36486732312
+      },
+      "cost_per_byte": {
+        "send_sir": 17212011,
+        "send_not_sir": 47683715,
+        "execution": 17212011
+      }
+    },
+    "action_creation_config": {
+      "create_account_cost": {
+        "send_sir": 3850000000000,
+        "send_not_sir": 3850000000000,
+        "execution": 3850000000000
+      },
+      "deploy_contract_cost": {
+        "send_sir": 184765750000,
+        "send_not_sir": 184765750000,
+        "execution": 184765750000
+      },
+      "deploy_contract_cost_per_byte": {
+        "send_sir": 6812999,
+        "send_not_sir": 47683715,
+        "execution": 64572944
+      },
+      "function_call_cost": {
+        "send_sir": 200000000000,
+        "send_not_sir": 200000000000,
+        "execution": 780000000000
+      },
+      "function_call_cost_per_byte": {
+        "send_sir": 2235934,
+        "send_not_sir": 47683715,
+        "execution": 2235934
+      },
+      "transfer_cost": {
+        "send_sir": 115123062500,
+        "send_not_sir": 115123062500,
+        "execution": 115123062500
+      },
+      "stake_cost": {
+        "send_sir": 141715687500,
+        "send_not_sir": 141715687500,
+        "execution": 102217625000
+      },
+      "add_key_cost": {
+        "full_access_cost": {
+          "send_sir": 101765125000,
+          "send_not_sir": 101765125000,
+          "execution": 101765125000
+        },
+        "function_call_cost": {
+          "send_sir": 102217625000,
+          "send_not_sir": 102217625000,
+          "execution": 102217625000
+        },
+        "function_call_cost_per_byte": {
+          "send_sir": 1925331,
+          "send_not_sir": 47683715,
+          "execution": 1925331
+        }
+      },
+      "delete_key_cost": {
+        "send_sir": 94946625000,
+        "send_not_sir": 94946625000,
+        "execution": 94946625000
+      },
+      "delete_account_cost": {
+        "send_sir": 147489000000,
+        "send_not_sir": 147489000000,
+        "execution": 147489000000
+      },
+      "delegate_cost": {
+        "send_sir": 200000000000,
+        "send_not_sir": 200000000000,
+        "execution": 200000000000
+      }
+    },
+    "storage_usage_config": {
+      "num_bytes_account": 100,
+      "num_extra_bytes_record": 40
+    },
+    "burnt_gas_reward": [
+      3,
+      10
+    ],
+    "pessimistic_gas_price_inflation_ratio": [
+      1,
+      1
+    ]
+  },
+  "wasm_config": {
+    "ext_costs": {
+      "base": 264768111,
+      "contract_loading_base": 35445963,
+      "contract_loading_bytes": 1089295,
+      "read_memory_base": 2609863200,
+      "read_memory_byte": 3801333,
+      "write_memory_base": 2803794861,
+      "write_memory_byte": 2723772,
+      "read_register_base": 2517165186,
+      "read_register_byte": 98562,
+      "write_register_base": 2865522486,
+      "write_register_byte": 3801564,
+      "utf8_decoding_base": 3111779061,
+      "utf8_decoding_byte": 291580479,
+      "utf16_decoding_base": 3543313050,
+      "utf16_decoding_byte": 163577493,
+      "sha256_base": 4540970250,
+      "sha256_byte": 24117351,
+      "keccak256_base": 5879491275,
+      "keccak256_byte": 21471105,
+      "keccak512_base": 5811388236,
+      "keccak512_byte": 36649701,
+      "ripemd160_base": 853675086,
+      "ripemd160_block": 680107584,
+      "ed25519_verify_base": 210000000000,
+      "ed25519_verify_byte": 9000000,
+      "ecrecover_base": 278821988457,
+      "log_base": 3543313050,
+      "log_byte": 13198791,
+      "storage_write_base": 64196736000,
+      "storage_write_key_byte": 70482867,
+      "storage_write_value_byte": 31018539,
+      "storage_write_evicted_byte": 32117307,
+      "storage_read_base": 56356845749,
+      "storage_read_key_byte": 30952533,
+      "storage_read_value_byte": 5611004,
+      "storage_large_read_overhead_base": 1,
+      "storage_large_read_overhead_byte": 1,
+      "storage_remove_base": 53473030500,
+      "storage_remove_key_byte": 38220384,
+      "storage_remove_ret_value_byte": 11531556,
+      "storage_has_key_base": 54039896625,
+      "storage_has_key_byte": 30790845,
+      "storage_iter_create_prefix_base": 0,
+      "storage_iter_create_prefix_byte": 0,
+      "storage_iter_create_range_base": 0,
+      "storage_iter_create_from_byte": 0,
+      "storage_iter_create_to_byte": 0,
+      "storage_iter_next_base": 0,
+      "storage_iter_next_key_byte": 0,
+      "storage_iter_next_value_byte": 0,
+      "touching_trie_node": 16101955926,
+      "read_cached_trie_node": 2280000000,
+      "promise_and_base": 1465013400,
+      "promise_and_per_promise": 5452176,
+      "promise_return": 560152386,
+      "validator_stake_base": 911834726400,
+      "validator_total_stake_base": 911834726400,
+      "contract_compile_base": 0,
+      "contract_compile_bytes": 0,
+      "alt_bn128_g1_multiexp_base": 713000000000,
+      "alt_bn128_g1_multiexp_element": 320000000000,
+      "alt_bn128_g1_sum_base": 3000000000,
+      "alt_bn128_g1_sum_element": 5000000000,
+      "alt_bn128_pairing_check_base": 9686000000000,
+      "alt_bn128_pairing_check_element": 5102000000000,
+      "yield_create_base": 153411779276,
+      "yield_create_byte": 15643988,
+      "yield_resume_base": 1195627285210,
+      "yield_resume_byte": 47683715,
+      "bls12381_p1_sum_base": 16500000000,
+      "bls12381_p1_sum_element": 6000000000,
+      "bls12381_p2_sum_base": 18600000000,
+      "bls12381_p2_sum_element": 15000000000,
+      "bls12381_g1_multiexp_base": 16500000000,
+      "bls12381_g1_multiexp_element": 930000000000,
+      "bls12381_g2_multiexp_base": 18600000000,
+      "bls12381_g2_multiexp_element": 1995000000000,
+      "bls12381_map_fp_to_g1_base": 1500000000,
+      "bls12381_map_fp_to_g1_element": 252000000000,
+      "bls12381_map_fp2_to_g2_base": 1500000000,
+      "bls12381_map_fp2_to_g2_element": 900000000000,
+      "bls12381_pairing_base": 2130000000000,
+      "bls12381_pairing_element": 2130000000000,
+      "bls12381_p1_decompress_base": 15000000000,
+      "bls12381_p1_decompress_element": 81000000000,
+      "bls12381_p2_decompress_base": 15000000000,
+      "bls12381_p2_decompress_element": 165000000000
+    },
+    "grow_mem_cost": 1,
+    "regular_op_cost": 822756,
+    "vm_kind": "<REDACTED>",
+    "discard_custom_sections": true,
+    "storage_get_mode": "FlatStorage",
+    "fix_contract_loading_cost": true,
+    "implicit_account_creation": true,
+    "eth_implicit_accounts": true,
+    "limit_config": {
+      "max_gas_burnt": 300000000000000,
+      "max_stack_height": 262144,
+      "initial_memory_pages": 1024,
+      "max_memory_pages": 2048,
+      "registers_memory_limit": 1073741824,
+      "max_register_size": 104857600,
+      "max_number_registers": 100,
+      "max_number_logs": 100,
+      "max_total_log_length": 16384,
+      "max_total_prepaid_gas": 300000000000000,
+      "max_actions_per_receipt": 100,
+      "max_number_bytes_method_names": 2000,
+      "max_length_method_name": 256,
+      "max_arguments_length": 4194304,
+      "max_length_returned_data": 4194304,
+      "max_contract_size": 4194304,
+      "max_transaction_size": 1572864,
+      "max_receipt_size": 4194304,
+      "max_length_storage_key": 2048,
+      "max_length_storage_value": 4194304,
+      "max_promises_per_function_call_action": 1024,
+      "max_number_input_data_dependencies": 128,
+      "max_functions_number_per_contract": 10000,
+      "max_locals_per_contract": 1000000,
+      "account_id_validity_rules_version": 1,
+      "yield_timeout_length_in_blocks": 200,
+      "max_yield_payload_size": 1024,
+      "per_receipt_storage_proof_size_limit": 4000000
+    }
+  },
+  "account_creation_config": {
+    "min_allowed_top_level_account_length": 65,
+    "registrar_account_id": "registrar"
+  },
+  "congestion_control_config": {
+    "max_congestion_incoming_gas": 400000000000000000,
+    "max_congestion_outgoing_gas": 10000000000000000,
+    "max_congestion_memory_consumption": 1000000000,
+    "max_congestion_missed_chunks": 5,
+    "max_outgoing_gas": 300000000000000000,
+    "min_outgoing_gas": 1000000000000000,
+    "allowed_shard_outgoing_gas": 1000000000000000,
+    "max_tx_gas": 500000000000000,
+    "min_tx_gas": 20000000000000,
+    "reject_tx_congestion_threshold": 0.8,
+    "outgoing_receipts_usual_size_limit": 102400,
+    "outgoing_receipts_big_size_limit": 4718592
+  },
+  "witness_config": {
+    "main_storage_proof_size_soft_limit": 4000000,
+    "combined_transactions_size_limit": 4194304,
+    "new_transactions_validation_state_size_soft_limit": 572864
+  }
+}
diff --git a/core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_149.json.snap b/core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_149.json.snap
new file mode 100644
index 00000000000..887bcc311c6
--- /dev/null
+++ b/core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_149.json.snap
@@ -0,0 +1,259 @@
+---
+source: core/parameters/src/config_store.rs
+expression: config_view
+---
+{
+  "storage_amount_per_byte": "10000000000000000000",
+  "transaction_costs": {
+    "action_receipt_creation_config": {
+      "send_sir": 108059500000,
+      "send_not_sir": 108059500000,
+      "execution": 108059500000
+    },
+    "data_receipt_creation_config": {
+      "base_cost": {
+        "send_sir": 36486732312,
+        "send_not_sir": 36486732312,
+        "execution": 36486732312
+      },
+      "cost_per_byte": {
+        "send_sir": 17212011,
+        "send_not_sir": 47683715,
+        "execution": 17212011
+      }
+    },
+    "action_creation_config": {
+      "create_account_cost": {
+        "send_sir": 3850000000000,
+        "send_not_sir": 3850000000000,
+        "execution": 3850000000000
+      },
+      "deploy_contract_cost": {
+        "send_sir": 184765750000,
+        "send_not_sir": 184765750000,
+        "execution": 184765750000
+      },
+      "deploy_contract_cost_per_byte": {
+        "send_sir": 6812999,
+        "send_not_sir": 47683715,
+        "execution": 64572944
+      },
+      "function_call_cost": {
+        "send_sir": 200000000000,
+        "send_not_sir": 200000000000,
+        "execution": 780000000000
+      },
+      "function_call_cost_per_byte": {
+        "send_sir": 2235934,
+        "send_not_sir": 47683715,
+        "execution": 2235934
+      },
+      "transfer_cost": {
+        "send_sir": 115123062500,
+        "send_not_sir": 115123062500,
+        "execution": 115123062500
+      },
+      "stake_cost": {
+        "send_sir": 141715687500,
+        "send_not_sir": 141715687500,
+        "execution": 102217625000
+      },
+      "add_key_cost": {
+        "full_access_cost": {
+          "send_sir": 101765125000,
+          "send_not_sir": 101765125000,
+          "execution": 101765125000
+        },
+        "function_call_cost": {
+          "send_sir": 102217625000,
+          "send_not_sir": 102217625000,
+          "execution": 102217625000
+        },
+        "function_call_cost_per_byte": {
+          "send_sir": 1925331,
+          "send_not_sir": 47683715,
+          "execution": 1925331
+        }
+      },
+      "delete_key_cost": {
+        "send_sir": 94946625000,
+        "send_not_sir": 94946625000,
+        "execution": 94946625000
+      },
+      "delete_account_cost": {
+        "send_sir": 147489000000,
+        "send_not_sir": 147489000000,
+        "execution": 147489000000
+      },
+      "delegate_cost": {
+        "send_sir": 200000000000,
+        "send_not_sir": 200000000000,
+        "execution": 200000000000
+      }
+    },
+    "storage_usage_config": {
+      "num_bytes_account": 100,
+      "num_extra_bytes_record": 40
+    },
+    "burnt_gas_reward": [
+      3,
+      10
+    ],
+    "pessimistic_gas_price_inflation_ratio": [
+      1,
+      1
+    ]
+  },
+  "wasm_config": {
+    "ext_costs": {
+      "base": 264768111,
+      "contract_loading_base": 35445963,
+      "contract_loading_bytes": 1089295,
+      "read_memory_base": 2609863200,
+      "read_memory_byte": 3801333,
+      "write_memory_base": 2803794861,
+      "write_memory_byte": 2723772,
+      "read_register_base": 2517165186,
+      "read_register_byte": 98562,
+      "write_register_base": 2865522486,
+      "write_register_byte": 3801564,
+      "utf8_decoding_base": 3111779061,
+      "utf8_decoding_byte": 291580479,
+      "utf16_decoding_base": 3543313050,
+      "utf16_decoding_byte": 163577493,
+      "sha256_base": 4540970250,
+      "sha256_byte": 24117351,
+      "keccak256_base": 5879491275,
+      "keccak256_byte": 21471105,
+      "keccak512_base": 5811388236,
+      "keccak512_byte": 36649701,
+      "ripemd160_base": 853675086,
+      "ripemd160_block": 680107584,
+      "ed25519_verify_base": 210000000000,
+      "ed25519_verify_byte": 9000000,
+      "ecrecover_base": 278821988457,
+      "log_base": 3543313050,
+      "log_byte": 13198791,
+      "storage_write_base": 64196736000,
+      "storage_write_key_byte": 70482867,
+      "storage_write_value_byte": 31018539,
+      "storage_write_evicted_byte": 32117307,
+      "storage_read_base": 56356845749,
+      "storage_read_key_byte": 30952533,
+      "storage_read_value_byte": 5611004,
+      "storage_large_read_overhead_base": 1,
+      "storage_large_read_overhead_byte": 1,
+      "storage_remove_base": 53473030500,
+      "storage_remove_key_byte": 38220384,
+      "storage_remove_ret_value_byte": 11531556,
+      "storage_has_key_base": 54039896625,
+      "storage_has_key_byte": 30790845,
+      "storage_iter_create_prefix_base": 0,
+      "storage_iter_create_prefix_byte": 0,
+      "storage_iter_create_range_base": 0,
+      "storage_iter_create_from_byte": 0,
+      "storage_iter_create_to_byte": 0,
+      "storage_iter_next_base": 0,
+      "storage_iter_next_key_byte": 0,
+      "storage_iter_next_value_byte": 0,
+      "touching_trie_node": 16101955926,
+      "read_cached_trie_node": 2280000000,
+      "promise_and_base": 1465013400,
+      "promise_and_per_promise": 5452176,
+      "promise_return": 560152386,
+      "validator_stake_base": 911834726400,
+      "validator_total_stake_base": 911834726400,
+      "contract_compile_base": 0,
+      "contract_compile_bytes": 0,
+      "alt_bn128_g1_multiexp_base": 713000000000,
+      "alt_bn128_g1_multiexp_element": 320000000000,
+      "alt_bn128_g1_sum_base": 3000000000,
+      "alt_bn128_g1_sum_element": 5000000000,
+      "alt_bn128_pairing_check_base": 9686000000000,
+      "alt_bn128_pairing_check_element": 5102000000000,
+      "yield_create_base": 153411779276,
+      "yield_create_byte": 15643988,
+      "yield_resume_base": 1195627285210,
+      "yield_resume_byte": 47683715,
+      "bls12381_p1_sum_base": 16500000000,
+      "bls12381_p1_sum_element": 6000000000,
+      "bls12381_p2_sum_base": 18600000000,
+      "bls12381_p2_sum_element": 15000000000,
+      "bls12381_g1_multiexp_base": 16500000000,
+      "bls12381_g1_multiexp_element": 930000000000,
+      "bls12381_g2_multiexp_base": 18600000000,
+      "bls12381_g2_multiexp_element": 1995000000000,
+      "bls12381_map_fp_to_g1_base": 1500000000,
+      "bls12381_map_fp_to_g1_element": 252000000000,
+      "bls12381_map_fp2_to_g2_base": 1500000000,
+      "bls12381_map_fp2_to_g2_element": 900000000000,
+      "bls12381_pairing_base": 2130000000000,
+      "bls12381_pairing_element": 2130000000000,
+      "bls12381_p1_decompress_base": 15000000000,
+      "bls12381_p1_decompress_element": 81000000000,
+      "bls12381_p2_decompress_base": 15000000000,
+      "bls12381_p2_decompress_element": 165000000000
+    },
+    "grow_mem_cost": 1,
+    "regular_op_cost": 822756,
+    "vm_kind": "<REDACTED>",
+    "discard_custom_sections": true,
+    "storage_get_mode": "FlatStorage",
+    "fix_contract_loading_cost": true,
+    "implicit_account_creation": true,
+    "eth_implicit_accounts": true,
+    "limit_config": {
+      "max_gas_burnt": 300000000000000,
+      "max_stack_height": 262144,
+      "initial_memory_pages": 1024,
+      "max_memory_pages": 2048,
+      "registers_memory_limit": 1073741824,
+      "max_register_size": 104857600,
+      "max_number_registers": 100,
+      "max_number_logs": 100,
+      "max_total_log_length": 16384,
+      "max_total_prepaid_gas": 300000000000000,
+      "max_actions_per_receipt": 100,
+      "max_number_bytes_method_names": 2000,
+      "max_length_method_name": 256,
+      "max_arguments_length": 4194304,
+      "max_length_returned_data": 4194304,
+      "max_contract_size": 4194304,
+      "max_transaction_size": 1572864,
+      "max_receipt_size": 4194304,
+      "max_length_storage_key": 2048,
+      "max_length_storage_value": 4194304,
+      "max_promises_per_function_call_action": 1024,
+      "max_number_input_data_dependencies": 128,
+      "max_functions_number_per_contract": 10000,
+      "max_locals_per_contract": 1000000,
+      "account_id_validity_rules_version": 1,
+      "yield_timeout_length_in_blocks": 200,
+      "max_yield_payload_size": 1024,
+      "per_receipt_storage_proof_size_limit": 4000000
+    }
+  },
+  "account_creation_config": {
+    "min_allowed_top_level_account_length": 65,
+    "registrar_account_id": "registrar"
+  },
+  "congestion_control_config": {
+    "max_congestion_incoming_gas": 400000000000000000,
+    "max_congestion_outgoing_gas": 10000000000000000,
+    "max_congestion_memory_consumption": 1000000000,
+    "max_congestion_missed_chunks": 5,
+    "max_outgoing_gas": 300000000000000000,
+    "min_outgoing_gas": 1000000000000000,
+    "allowed_shard_outgoing_gas": 1000000000000000,
+    "max_tx_gas": 500000000000000,
+    "min_tx_gas": 20000000000000,
+    "reject_tx_congestion_threshold": 0.8,
+    "outgoing_receipts_usual_size_limit": 102400,
+    "outgoing_receipts_big_size_limit": 4718592
+  },
+  "witness_config": {
+    "main_storage_proof_size_soft_limit": 4000000,
+    "combined_transactions_size_limit": 4194304,
+    "new_transactions_validation_state_size_soft_limit": 572864
+  }
+}
diff --git a/core/primitives-core/src/version.rs b/core/primitives-core/src/version.rs
index 8e4408db8e2..00dbfe6b0be 100644
--- a/core/primitives-core/src/version.rs
+++ b/core/primitives-core/src/version.rs
@@ -296,6 +296,13 @@ pub enum ProtocolFeature {
     /// Enable optimistic block production.
     ProduceOptimisticBlock,
     GlobalContracts,
+    /// NEP: https://github.com/near/NEPs/pull/536
+    ///
+    /// Reduce the number of gas refund receipts by charging the current gas
+    /// price rather than a pessimistic gas price. Also, introduce a new fee of
+    /// 5% for gas refunds and charge the signer this fee for gas refund
+    /// receipts.
+    ReducedGasRefunds,
 }
 
 impl ProtocolFeature {
@@ -395,6 +402,7 @@ impl ProtocolFeature {
             // that always enables this for mocknet (see config_mocknet function).
             ProtocolFeature::ShuffleShardAssignments => 143,
             ProtocolFeature::ExcludeExistingCodeFromWitnessForCodeLen => 148,
+            ProtocolFeature::ReducedGasRefunds => 149,
             // Place features that are not yet in Nightly below this line.
         }
     }
diff --git a/integration-tests/src/node/runtime_node.rs b/integration-tests/src/node/runtime_node.rs
index 3bc818b560a..5dfbdbb83c4 100644
--- a/integration-tests/src/node/runtime_node.rs
+++ b/integration-tests/src/node/runtime_node.rs
@@ -3,7 +3,7 @@ use std::sync::{Arc, RwLock};
 use near_chain_configs::Genesis;
 use near_crypto::{InMemorySigner, Signer};
 use near_parameters::{RuntimeConfig, RuntimeConfigStore};
-use near_primitives::types::AccountId;
+use near_primitives::types::{AccountId, Balance};
 use testlib::runtime_utils::{add_test_contract, alice_account, bob_account, carol_account};
 
 use crate::node::Node;
@@ -16,6 +16,7 @@ pub struct RuntimeNode {
     pub signer: Arc<Signer>,
     pub genesis: Genesis,
     account_id: AccountId,
+    gas_price: Balance,
 }
 
 impl RuntimeNode {
@@ -41,7 +42,8 @@ impl RuntimeNode {
             epoch_length: genesis.config.epoch_length,
             runtime_config,
         }));
-        RuntimeNode { signer, client, genesis, account_id: account_id.clone() }
+        let gas_price = genesis.config.min_gas_price;
+        RuntimeNode { signer, client, genesis, account_id: account_id.clone(), gas_price }
     }
 
     pub fn new_from_genesis(account_id: &AccountId, genesis: Genesis) -> Self {
@@ -70,6 +72,7 @@ impl RuntimeNode {
     pub fn free(account_id: &AccountId) -> Self {
         let mut genesis =
             Genesis::test(vec![alice_account(), bob_account(), "carol.near".parse().unwrap()], 3);
+        genesis.config.min_gas_price = 0;
         add_test_contract(&mut genesis, &bob_account());
         Self::new_from_genesis_and_config(account_id, genesis, RuntimeConfig::free())
     }
@@ -105,6 +108,7 @@ impl Node for RuntimeNode {
             self.account_id.clone(),
             self.signer.clone(),
             self.client.clone(),
+            self.gas_price,
         ))
     }
 }
diff --git a/integration-tests/src/tests/nearcore/rpc_nodes.rs b/integration-tests/src/tests/nearcore/rpc_nodes.rs
index 7db8c6eec01..9b1d955c3a1 100644
--- a/integration-tests/src/tests/nearcore/rpc_nodes.rs
+++ b/integration-tests/src/tests/nearcore/rpc_nodes.rs
@@ -22,7 +22,7 @@ use near_primitives::transaction::{PartialExecutionStatus, SignedTransaction};
 use near_primitives::types::{
     BlockId, BlockReference, EpochId, EpochReference, Finality, TransactionOrReceiptId,
 };
-use near_primitives::version::ProtocolVersion;
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature, ProtocolVersion};
 use near_primitives::views::{ExecutionOutcomeView, ExecutionStatusView, TxExecutionStatus};
 use std::time::Duration;
 
@@ -382,9 +382,15 @@ fn ultra_slow_test_tx_not_enough_balance_must_return_error() {
                 }
                 sleep(std::time::Duration::from_millis(500)).await;
             }
+            let expected_cost = if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) {
+                "1100000000000044636512500000000000"
+            } else {
+                "1100000000000045306060187500000000"
+            };
             let _ = client
                 .broadcast_tx_commit(to_base64(&bytes))
                 .map_err(|err| {
+                    println!("testing: {:?}", err.data);
                     assert_eq!(
                         err.data.unwrap(),
                         serde_json::json!({"TxExecutionError": {
@@ -392,7 +398,7 @@ fn ultra_slow_test_tx_not_enough_balance_must_return_error() {
                                 "NotEnoughBalance": {
                                     "signer_id": "near.0",
                                     "balance": "950000000000000000000000000000000", // If something changes in setup just update this value
-                                    "cost": "1100000000000045306060187500000000",
+                                    "cost": expected_cost,
                                 }
                             }
                         }})
diff --git a/integration-tests/src/tests/runtime/deployment.rs b/integration-tests/src/tests/runtime/deployment.rs
index 1d036325063..d52339a5f51 100644
--- a/integration-tests/src/tests/runtime/deployment.rs
+++ b/integration-tests/src/tests/runtime/deployment.rs
@@ -3,7 +3,7 @@ use near_chain_configs::Genesis;
 use near_parameters::RuntimeConfigStore;
 use near_primitives::transaction::{Action, DeployContractAction, SignedTransaction};
 use near_primitives::types::AccountId;
-use near_primitives::version::PROTOCOL_VERSION;
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature};
 use near_primitives::views::FinalExecutionStatus;
 
 const ONE_NEAR: u128 = 10u128.pow(24);
@@ -51,7 +51,9 @@ fn test_deploy_max_size_contract() {
         )
         .unwrap();
     assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
 
     // Deploy contract
     let wasm_binary = near_test_contracts::sized_contract(contract_size as usize);
diff --git a/integration-tests/src/tests/runtime/sanity_checks.rs b/integration-tests/src/tests/runtime/sanity_checks.rs
index ec258a95114..f883e18db0d 100644
--- a/integration-tests/src/tests/runtime/sanity_checks.rs
+++ b/integration-tests/src/tests/runtime/sanity_checks.rs
@@ -3,7 +3,7 @@ use near_chain_configs::Genesis;
 use near_parameters::{ExtCosts, RuntimeConfig, RuntimeConfigStore};
 use near_primitives::serialize::to_base64;
 use near_primitives::types::AccountId;
-use near_primitives::version::PROTOCOL_VERSION;
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature};
 use near_primitives::views::{
     CostGasUsed, ExecutionOutcomeWithIdView, ExecutionStatusView, FinalExecutionStatus,
 };
@@ -60,7 +60,9 @@ fn setup_runtime_node_with_contract(wasm_binary: &[u8]) -> RuntimeNode {
         )
         .unwrap();
     assert_eq!(tx_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(tx_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(tx_result.receipts_outcome.len(), num_expected_receipts);
 
     let tx_result =
         node_user.deploy_contract(test_contract_account(), wasm_binary.to_vec()).unwrap();
@@ -127,7 +129,10 @@ fn test_cost_sanity() {
     assert_eq!(res.transaction_outcome.outcome.metadata.gas_profile, None);
 
     let receipts_status = get_receipts_status_with_clear_hash(&res.receipts_outcome);
-    insta::assert_yaml_snapshot!("receipts_status", receipts_status);
+    insta::assert_yaml_snapshot!(
+        if cfg!(feature = "nightly") { "receipts_status_nightly" } else { "receipts_status" },
+        receipts_status
+    );
 
     let receipts_gas_profile = res
         .receipts_outcome
@@ -178,7 +183,14 @@ fn test_cost_sanity_nondeterministic() {
     assert_eq!(res.transaction_outcome.outcome.metadata.gas_profile, None);
 
     let receipts_status = get_receipts_status_with_clear_hash(&res.receipts_outcome);
-    insta::assert_yaml_snapshot!("receipts_status_nondeterministic", receipts_status);
+    insta::assert_yaml_snapshot!(
+        if cfg!(feature = "nightly") {
+            "receipts_status_nondeterministic_nightly"
+        } else {
+            "receipts_status_nondeterministic"
+        },
+        receipts_status
+    );
 
     let receipts_gas_profile = res
         .receipts_outcome
diff --git a/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_gas_profile_nightly.snap b/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_gas_profile_nightly.snap
index eb854e36d17..ce1647543d0 100644
--- a/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_gas_profile_nightly.snap
+++ b/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_gas_profile_nightly.snap
@@ -427,8 +427,6 @@ expression: receipts_gas_profile
     [],
     [],
     [],
-    [],
-    [],
     [
         CostGasUsed {
             cost_category: "WASM_HOST_COST",
@@ -449,7 +447,6 @@ expression: receipts_gas_profile
     [],
     [],
     [],
-    [],
     [
         CostGasUsed {
             cost_category: "WASM_HOST_COST",
@@ -496,5 +493,4 @@ expression: receipts_gas_profile
         },
     ],
     [],
-    [],
 ]
diff --git a/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_status_nightly.snap b/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_status_nightly.snap
new file mode 100644
index 00000000000..cb72c4fbc87
--- /dev/null
+++ b/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_status_nightly.snap
@@ -0,0 +1,35 @@
+---
+source: integration-tests/src/tests/runtime/sanity_checks.rs
+expression: receipts_status
+---
+- SuccessReceiptId: "11111111111111111111111111111111"
+- Failure:
+    ActionError:
+      index: 0
+      kind:
+        FunctionCallError:
+          ExecutionError: "Smart contract panicked: explicit guest panic"
+- SuccessValue: ""
+- Failure:
+    ActionError:
+      index: 0
+      kind:
+        FunctionCallError:
+          ExecutionError: "Smart contract panicked: xyz"
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
+- SuccessValue: ""
diff --git a/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_status_nondeterministic_nightly.snap b/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_status_nondeterministic_nightly.snap
new file mode 100644
index 00000000000..c85a858af5e
--- /dev/null
+++ b/integration-tests/src/tests/runtime/snapshots/integration_tests__tests__runtime__sanity_checks__receipts_status_nondeterministic_nightly.snap
@@ -0,0 +1,6 @@
+---
+source: integration-tests/src/tests/runtime/sanity_checks.rs
+expression: receipts_status
+---
+- SuccessValue: ""
+- SuccessValue: ""
diff --git a/integration-tests/src/tests/runtime/test_evil_contracts.rs b/integration-tests/src/tests/runtime/test_evil_contracts.rs
index c3af36b4d82..c4013b375ca 100644
--- a/integration-tests/src/tests/runtime/test_evil_contracts.rs
+++ b/integration-tests/src/tests/runtime/test_evil_contracts.rs
@@ -1,5 +1,6 @@
 use crate::node::{Node, RuntimeNode};
 use near_primitives::errors::{ActionError, ActionErrorKind, FunctionCallError};
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature};
 use near_primitives::views::FinalExecutionStatus;
 use std::mem::size_of;
 
@@ -27,7 +28,9 @@ fn setup_test_contract(wasm_binary: &[u8]) -> RuntimeNode {
         )
         .unwrap();
     assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
 
     let transaction_result = node_user
         .deploy_contract("test_contract.alice.near".parse().unwrap(), wasm_binary.to_vec())
diff --git a/integration-tests/src/tests/runtime/test_yield_resume.rs b/integration-tests/src/tests/runtime/test_yield_resume.rs
index 8df6bff83aa..c62ae7ffe15 100644
--- a/integration-tests/src/tests/runtime/test_yield_resume.rs
+++ b/integration-tests/src/tests/runtime/test_yield_resume.rs
@@ -1,4 +1,5 @@
 use crate::node::{Node, RuntimeNode};
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature};
 use near_primitives::views::FinalExecutionStatus;
 
 /// Initial balance used in tests.
@@ -23,7 +24,9 @@ fn setup_test_contract(wasm_binary: &[u8]) -> RuntimeNode {
         )
         .unwrap();
     assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
 
     let transaction_result = node_user
         .deploy_contract("test_contract.alice.near".parse().unwrap(), wasm_binary.to_vec())
diff --git a/integration-tests/src/tests/standard_cases/mod.rs b/integration-tests/src/tests/standard_cases/mod.rs
index 60330e81bc9..beae73c1659 100644
--- a/integration-tests/src/tests/standard_cases/mod.rs
+++ b/integration-tests/src/tests/standard_cases/mod.rs
@@ -17,6 +17,7 @@ use near_primitives::errors::{
 use near_primitives::hash::{CryptoHash, hash};
 use near_primitives::types::{AccountId, Balance};
 use near_primitives::utils::{derive_eth_implicit_account_id, derive_near_implicit_account_id};
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature};
 use near_primitives::views::{
     AccessKeyView, AccountView, ExecutionMetadataView, FinalExecutionOutcomeView,
     FinalExecutionStatus,
@@ -357,7 +358,9 @@ pub fn transfer_tokens_to_implicit_account(node: impl Node, public_key: PublicKe
     let transaction_result =
         node_user.send_money(account_id.clone(), receiver_id.clone(), tokens_used).unwrap();
     assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
     let new_root = node_user.get_state_root();
     assert_ne!(root, new_root);
     assert_eq!(node_user.get_access_key_nonce_for_signer(account_id).unwrap(), 1);
@@ -390,7 +393,9 @@ pub fn transfer_tokens_to_implicit_account(node: impl Node, public_key: PublicKe
         node_user.send_money(account_id.clone(), receiver_id.clone(), tokens_used).unwrap();
 
     assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
     let new_root = node_user.get_state_root();
     assert_ne!(root, new_root);
     assert_eq!(node_user.get_access_key_nonce_for_signer(account_id).unwrap(), 2);
@@ -531,7 +536,9 @@ pub fn test_refund_on_send_money_to_non_existent_account(node: impl Node) {
             .into()
         )
     );
-    assert_eq!(transaction_result.receipts_outcome.len(), 3);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 2 } else { 3 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
     let new_root = node_user.get_state_root();
     assert_ne!(root, new_root);
     let result1 = node_user.view_account(account_id).unwrap();
@@ -1161,7 +1168,9 @@ pub fn test_unstake_while_not_staked(node: impl Node) {
         )
         .unwrap();
     assert_eq!(transaction_result.status, FinalExecutionStatus::SuccessValue(Vec::new()));
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
     let transaction_result =
         node_user.stake(eve_dot_alice_account(), node.block_signer().public_key(), 0).unwrap();
     assert_eq!(
@@ -1255,7 +1264,9 @@ pub fn test_delete_account_fail(node: impl Node) {
             .into()
         )
     );
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
     assert!(node.user().view_account(&bob_account()).is_ok());
     assert_eq!(
         node.user().view_account(&node.account_id().unwrap()).unwrap().amount,
@@ -1277,7 +1288,9 @@ pub fn test_delete_account_no_account(node: impl Node) {
             .into()
         )
     );
-    assert_eq!(transaction_result.receipts_outcome.len(), 2);
+    let num_expected_receipts =
+        if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) { 1 } else { 2 };
+    assert_eq!(transaction_result.receipts_outcome.len(), num_expected_receipts);
 }
 
 pub fn test_delete_account_while_staking(node: impl Node) {
@@ -1321,13 +1334,19 @@ pub fn test_smart_contract_free(node: impl Node) {
     let node_user = node.user();
     let root = node_user.get_state_root();
     let transaction_result = node_user
-        .function_call(alice_account(), bob_account(), "run_test", vec![], 10u64.pow(14), 0)
+        .function_call(alice_account(), bob_account(), "run_test", vec![], 10u64.pow(13), 0)
         .unwrap();
     assert_eq!(
         transaction_result.status,
         FinalExecutionStatus::SuccessValue(10i32.to_le_bytes().to_vec())
     );
-    assert_eq!(transaction_result.receipts_outcome.len(), 1);
+    let num_expected_receipts = 1;
+    assert_eq!(
+        transaction_result.receipts_outcome.len(),
+        num_expected_receipts,
+        "{:?}",
+        transaction_result.receipts_outcome
+    );
 
     let total_gas_burnt = transaction_result.transaction_outcome.outcome.gas_burnt
         + transaction_result.receipts_outcome.iter().map(|t| t.outcome.gas_burnt).sum::<u64>();
diff --git a/integration-tests/src/user/runtime_user.rs b/integration-tests/src/user/runtime_user.rs
index 3d2bd300f52..2b4a2ec501a 100644
--- a/integration-tests/src/user/runtime_user.rs
+++ b/integration-tests/src/user/runtime_user.rs
@@ -3,7 +3,6 @@ use std::collections::{HashMap, HashSet};
 use std::sync::{Arc, RwLock};
 
 use itertools::Itertools;
-use near_chain_configs::MIN_GAS_PRICE;
 use near_crypto::{PublicKey, Signer};
 use near_jsonrpc_primitives::errors::ServerError;
 use near_parameters::RuntimeConfig;
@@ -15,7 +14,7 @@ use near_primitives::hash::CryptoHash;
 use near_primitives::receipt::Receipt;
 use near_primitives::test_utils::MockEpochInfoProvider;
 use near_primitives::transaction::SignedTransaction;
-use near_primitives::types::{AccountId, BlockHeightDelta, MerkleHash, ShardId};
+use near_primitives::types::{AccountId, Balance, BlockHeightDelta, MerkleHash, ShardId};
 use near_primitives::version::PROTOCOL_VERSION;
 use near_primitives::views::{
     AccessKeyView, AccountView, BlockView, CallResult, ChunkView, ContractCodeView,
@@ -58,6 +57,7 @@ pub struct RuntimeUser {
     pub transactions: RefCell<HashSet<SignedTransaction>>,
     pub epoch_info_provider: MockEpochInfoProvider,
     pub runtime_config: Arc<RuntimeConfig>,
+    pub gas_price: Balance,
 }
 
 impl RuntimeUser {
@@ -65,6 +65,7 @@ impl RuntimeUser {
         account_id: AccountId,
         signer: Arc<Signer>,
         client: Arc<RwLock<MockClient>>,
+        gas_price: Balance,
     ) -> Self {
         let runtime_config = Arc::new(client.read().unwrap().runtime_config.clone());
         RuntimeUser {
@@ -77,6 +78,7 @@ impl RuntimeUser {
             transactions: RefCell::new(Default::default()),
             epoch_info_provider: MockEpochInfoProvider::default(),
             runtime_config,
+            gas_price,
         }
     }
 
@@ -193,7 +195,7 @@ impl RuntimeUser {
             block_timestamp: 0,
             shard_id,
             epoch_height: 0,
-            gas_price: MIN_GAS_PRICE,
+            gas_price: self.gas_price,
             gas_limit: None,
             random_seed: Default::default(),
             epoch_id: Default::default(),
diff --git a/pytest/tests/sanity/meta_tx.py b/pytest/tests/sanity/meta_tx.py
index 4c328051264..776d9a11622 100644
--- a/pytest/tests/sanity/meta_tx.py
+++ b/pytest/tests/sanity/meta_tx.py
@@ -86,6 +86,13 @@ def test_meta_tx(self):
 
         nodes[0].send_tx_and_wait(meta_tx, 100)
 
+        # send_tx_and_wait does not guarantee that all receipts changes are
+        # observable on RPC queries, yet.
+        # For meta transactions without refund, the access key is added in the
+        # last receipt of the transaction, which is not observable at this point.
+        # Waiting for one more block fixes that.
+        nodes[0].wait_at_least_one_block()
+
         self.assertEqual(check_account_status(nodes[0], CANDIDATE_ACCOUNT),
                          (2, CANDIDATE_STARTING_AMOUNT))
 
diff --git a/pytest/tests/sanity/rosetta.py b/pytest/tests/sanity/rosetta.py
index 7987e538ffa..6291dc36a27 100644
--- a/pytest/tests/sanity/rosetta.py
+++ b/pytest/tests/sanity/rosetta.py
@@ -860,8 +860,18 @@ def test_implicit_account(self) -> None:
         }], block['transactions'])
 
         # Fetch the receipt through Rosetta RPC.
+        # TODO(#13397): After stabilizing ReducedGasRefunds, remove the check
+        # for gas refunds, there should no longer be any refunds in this case.
         result = RosettaExecResult(self.rosetta, block, receipt_id)
         related = result.related(0)
+        hasGasRefund = related is not None
+        relatedTransactions = ({
+            'related_transactions': [{
+                'direction': 'forward',
+                'transaction_identifier': related.identifier
+            }]
+        } if hasGasRefund else {})
+
         self.assertEqual(
             {
                 'transaction_identifier': result.identifier,
@@ -887,46 +897,43 @@ def test_implicit_account(self) -> None:
                         }
                     }
                 }],
-                'related_transactions': [{
-                    'direction': 'forward',
-                    'transaction_identifier': related and related.identifier
-                }],
-                'metadata': {
+                **relatedTransactions, 'metadata': {
                     'type': 'TRANSACTION'
                 }
             }, result.transaction())
 
-        # Fetch the next receipt through Rosetta RPC.
-        self.assertEqual(
-            {
-                'metadata': {
-                    'type': 'TRANSACTION'
-                },
-                'operations': [{
-                    'account': {
-                        'address': 'test0'
+        # Fetch the refund receipt through Rosetta RPC, if any.
+        if hasGasRefund:
+            self.assertEqual(
+                {
+                    'metadata': {
+                        'type': 'TRANSACTION'
                     },
-                    'amount': {
-                        'currency': {
-                            'decimals': 24,
-                            'symbol': 'NEAR'
+                    'operations': [{
+                        'account': {
+                            'address': 'test0'
                         },
-                        'value': '12524843062500000000'
-                    },
-                    'operation_identifier': {
-                        'index': 0
-                    },
-                    'status': 'SUCCESS',
-                    'type': 'TRANSFER',
-                    'metadata': {
-                        'predecessor_id': {
-                            'address': 'system'
+                        'amount': {
+                            'currency': {
+                                'decimals': 24,
+                                'symbol': 'NEAR'
+                            },
+                            'value': '12524843062500000000'
                         },
-                        'transfer_fee_type': 'GAS_REFUND'
-                    }
-                }],
-                'transaction_identifier': related.identifier
-            }, related.transaction())
+                        'operation_identifier': {
+                            'index': 0
+                        },
+                        'status': 'SUCCESS',
+                        'type': 'TRANSFER',
+                        'metadata': {
+                            'predecessor_id': {
+                                'address': 'system'
+                            },
+                            'transfer_fee_type': 'GAS_REFUND'
+                        }
+                    }],
+                    'transaction_identifier': related.identifier
+                }, related.transaction())
 
         # 2. Delete the account.
         logger.info(f'Deleting implicit account: {implicit.account_id}')
diff --git a/runtime/runtime-params-estimator/src/estimator_context.rs b/runtime/runtime-params-estimator/src/estimator_context.rs
index 0c020c11b0f..aea521d3649 100644
--- a/runtime/runtime-params-estimator/src/estimator_context.rs
+++ b/runtime/runtime-params-estimator/src/estimator_context.rs
@@ -457,7 +457,9 @@ impl Testbed<'_> {
             PROTOCOL_VERSION,
         )
         .expect("expected no validation error");
-        let cost = tx_cost(&self.apply_state.config, &validated_tx.to_tx(), gas_price).unwrap();
+        let cost =
+            tx_cost(&self.apply_state.config, &validated_tx.to_tx(), gas_price, PROTOCOL_VERSION)
+                .unwrap();
         let (mut signer, mut access_key) = get_signer_and_access_key(&state_update, &validated_tx)
             .expect("getting signer and access key should not fail in estimator");
 
diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs
index 211b97a400a..d948cfe67c5 100644
--- a/runtime/runtime/src/config.rs
+++ b/runtime/runtime/src/config.rs
@@ -3,6 +3,8 @@
 use near_primitives::account::AccessKeyPermission;
 use near_primitives::action::DeployGlobalContractAction;
 use near_primitives::errors::IntegerOverflowError;
+use near_primitives::version::ProtocolFeature;
+use near_vm_runner::logic::ProtocolVersion;
 use num_bigint::BigUint;
 use num_traits::cast::ToPrimitive;
 use num_traits::pow::Pow;
@@ -241,6 +243,7 @@ pub fn tx_cost(
     config: &RuntimeConfig,
     tx: &Transaction,
     gas_price: Balance,
+    protocol_version: ProtocolVersion,
 ) -> Result<TransactionCost, IntegerOverflowError> {
     let sender_is_receiver = tx.receiver_id() == tx.signer_id();
     let fees = &config.fees;
@@ -253,27 +256,10 @@ pub fn tx_cost(
         total_prepaid_gas(&tx.actions())?,
         total_prepaid_send_fees(config, &tx.actions())?,
     )?;
-    // If signer is equals to receiver the receipt will be processed at the same block as this
-    // transaction. Otherwise it will processed in the next block and the gas might be inflated.
-    let initial_receipt_hop = if sender_is_receiver { 0 } else { 1 };
-    // The pessimistic gas pricing is a best-effort limit which can be breached in case of
-    // congestion when receipts are delayed before they execute. Hence there is not much
-    // value to tie this limit to the function call base cost. Making it constant limits
-    // overcharging to 6x, which was the value before the cost increase.
-    let minimum_new_receipt_gas = 4_855_842_000_000; // 4.855TGas.
-    // In case the config is free, we don't care about the maximum depth.
-    let receipt_gas_price = if gas_price == 0 {
-        0
+    let receipt_gas_price = if ProtocolFeature::ReducedGasRefunds.enabled(protocol_version) {
+        gas_price
     } else {
-        let maximum_depth =
-            if minimum_new_receipt_gas > 0 { prepaid_gas / minimum_new_receipt_gas } else { 0 };
-        let inflation_exponent = u8::try_from(initial_receipt_hop + maximum_depth)
-            .map_err(|_| IntegerOverflowError {})?;
-        safe_gas_price_inflated(
-            gas_price,
-            fees.pessimistic_gas_price_inflation_ratio,
-            inflation_exponent,
-        )?
+        pessimistic_gas_price(gas_price, sender_is_receiver, fees, prepaid_gas)?
     };
 
     let mut gas_remaining =
@@ -356,6 +342,40 @@ pub fn total_prepaid_gas(actions: &[Action]) -> Result<Gas, IntegerOverflowError
     Ok(total_gas)
 }
 
+/// Calculates a maximum expected gas price increase during the execution of the transaction.
+///
+/// Note: this is no longer used with ProtocolFeature::ReducedGasRefunds
+fn pessimistic_gas_price(
+    gas_price: u128,
+    sender_is_receiver: bool,
+    fees: &std::sync::Arc<near_parameters::RuntimeFeesConfig>,
+    prepaid_gas: u64,
+) -> Result<u128, IntegerOverflowError> {
+    // If signer is equals to receiver the receipt will be processed at the same block as this
+    // transaction. Otherwise it will processed in the next block and the gas might be inflated.
+    let initial_receipt_hop = if sender_is_receiver { 0 } else { 1 };
+    // The pessimistic gas pricing is a best-effort limit which can be breached in case of
+    // congestion when receipts are delayed before they execute. Hence there is not much
+    // value to tie this limit to the function call base cost. Making it constant limits
+    // overcharging to 6x, which was the value before the cost increase.
+    let minimum_new_receipt_gas = 4_855_842_000_000; // 4.855TGas.
+    // In case the config is free, we don't care about the maximum depth.
+    let receipt_gas_price = if gas_price == 0 {
+        0
+    } else {
+        let maximum_depth =
+            if minimum_new_receipt_gas > 0 { prepaid_gas / minimum_new_receipt_gas } else { 0 };
+        let inflation_exponent = u8::try_from(initial_receipt_hop + maximum_depth)
+            .map_err(|_| IntegerOverflowError {})?;
+        safe_gas_price_inflated(
+            gas_price,
+            fees.pessimistic_gas_price_inflation_ratio,
+            inflation_exponent,
+        )?
+    };
+    Ok(receipt_gas_price)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs
index 37b6bf7712f..4408e14b460 100644
--- a/runtime/runtime/src/lib.rs
+++ b/runtime/runtime/src/lib.rs
@@ -442,7 +442,12 @@ impl Runtime {
                 }
             };
 
-            let cost = match tx_cost(&apply_state.config, validated_tx.to_tx(), gas_price) {
+            let cost = match tx_cost(
+                &apply_state.config,
+                validated_tx.to_tx(),
+                gas_price,
+                current_protocol_version,
+            ) {
                 Ok(c) => c,
                 Err(e) => {
                     processed_transactions.push(ProcessedTransaction {
diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs
index 798d7b50e0a..fa9b7e0e08c 100644
--- a/runtime/runtime/src/verifier.rs
+++ b/runtime/runtime/src/verifier.rs
@@ -732,7 +732,7 @@ mod tests {
                 return;
             }
         };
-        let cost = match tx_cost(config, &validated_tx.to_tx(), gas_price) {
+        let cost = match tx_cost(config, &validated_tx.to_tx(), gas_price, PROTOCOL_VERSION) {
             Ok(c) => c,
             Err(err) => {
                 assert_eq!(InvalidTxError::from(err), expected_err);
@@ -776,7 +776,8 @@ mod tests {
         };
         let (mut signer, mut access_key) = get_signer_and_access_key(state_update, &validated_tx)?;
 
-        let transaction_cost = tx_cost(config, &validated_tx.to_tx(), gas_price)?;
+        let transaction_cost =
+            tx_cost(config, &validated_tx.to_tx(), gas_price, current_protocol_version)?;
         let vr = verify_and_charge_tx_ephemeral(
             config,
             &mut signer,
diff --git a/runtime/runtime/tests/test_async_calls.rs b/runtime/runtime/tests/test_async_calls.rs
index 0285518864b..e34b35d20c6 100644
--- a/runtime/runtime/tests/test_async_calls.rs
+++ b/runtime/runtime/tests/test_async_calls.rs
@@ -6,6 +6,7 @@ use near_primitives::hash::CryptoHash;
 use near_primitives::receipt::{ActionReceipt, ReceiptEnum};
 use near_primitives::serialize::to_base64;
 use near_primitives::types::AccountId;
+use near_primitives::version::{PROTOCOL_VERSION, ProtocolFeature};
 
 pub mod runtime_group_tools;
 
@@ -589,17 +590,28 @@ fn test_simple_transfer() {
                         assert_eq!(function_call_action.deposit, 0);
                      }
                      => [r1, ref0] );
-    assert_receipts!(group, "near_1" => r1 @ "near_2",
-                     ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
-                     actions,
-                     a0, Action::Transfer(TransferAction{deposit}), {
-                        assert_eq!(*deposit, 1000000000);
-                     }
-                     => [ref1] );
-
-    assert_refund!(group, ref0 @ "near_0");
-    // For gas price difference
-    assert_refund!(group, ref1 @ "near_0");
+    if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) {
+        assert_receipts!(group, "near_1" => r1 @ "near_2",
+                         ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
+                         actions,
+                         a0, Action::Transfer(TransferAction{deposit}), {
+                            assert_eq!(*deposit, 1000000000);
+                         }
+                         => [] );
+        assert_refund!(group, ref0 @ "near_0");
+    } else {
+        assert_receipts!(group, "near_1" => r1 @ "near_2",
+                         ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
+                         actions,
+                         a0, Action::Transfer(TransferAction{deposit}), {
+                            assert_eq!(*deposit, 1000000000);
+                         }
+                         => [ref1] );
+
+        assert_refund!(group, ref0 @ "near_0");
+        // For gas price difference
+        assert_refund!(group, ref1 @ "near_0");
+    }
 }
 
 #[test]
@@ -657,23 +669,42 @@ fn test_create_account_with_transfer_and_full_key() {
                         assert_eq!(function_call_action.deposit, 0);
                      }
                      => [r1, ref0] );
-    assert_receipts!(group, "near_1" => r1 @ "near_2",
-                     ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
-                     actions,
-                     a0, Action::CreateAccount(CreateAccountAction{}), {},
-                     a1, Action::Transfer(TransferAction{deposit}), {
-                        assert_eq!(*deposit, 10000000000000000000000000);
-                     },
-                     a2, Action::AddKey(add_key_action), {
-                        assert_eq!(add_key_action.public_key, signer_new_account.public_key());
-                        assert_eq!(add_key_action.access_key.nonce, 0);
-                        assert_eq!(add_key_action.access_key.permission, AccessKeyPermission::FullAccess);
-                     }
-                     => [ref1] );
 
-    assert_refund!(group, ref0 @ "near_0");
-    // For gas price difference
-    assert_refund!(group, ref1 @ "near_0");
+    if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) {
+        assert_receipts!(group, "near_1" => r1 @ "near_2",
+            ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
+            actions,
+            a0, Action::CreateAccount(CreateAccountAction{}), {},
+            a1, Action::Transfer(TransferAction{deposit}), {
+                assert_eq!(*deposit, 10000000000000000000000000);
+            },
+            a2, Action::AddKey(add_key_action), {
+                assert_eq!(add_key_action.public_key, signer_new_account.public_key());
+                assert_eq!(add_key_action.access_key.nonce, 0);
+                assert_eq!(add_key_action.access_key.permission, AccessKeyPermission::FullAccess);
+            }
+            => [] );
+
+        assert_refund!(group, ref0 @ "near_0");
+    } else {
+        assert_receipts!(group, "near_1" => r1 @ "near_2",
+            ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
+            actions,
+            a0, Action::CreateAccount(CreateAccountAction{}), {},
+            a1, Action::Transfer(TransferAction{deposit}), {
+                assert_eq!(*deposit, 10000000000000000000000000);
+            },
+            a2, Action::AddKey(add_key_action), {
+                assert_eq!(add_key_action.public_key, signer_new_account.public_key());
+                assert_eq!(add_key_action.access_key.nonce, 0);
+                assert_eq!(add_key_action.access_key.permission, AccessKeyPermission::FullAccess);
+            }
+            => [ref1] );
+
+        assert_refund!(group, ref0 @ "near_0");
+        // For gas price difference
+        assert_refund!(group, ref1 @ "near_0");
+    }
 }
 
 #[test]
@@ -1013,15 +1044,27 @@ fn test_transfer_64len_hex() {
                         assert_eq!(function_call_action.deposit, 0);
                      }
                      => [r1, ref0] );
-    assert_receipts!(group, "near_1" => r1 @ account_id.as_str(),
-                     ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
-                     actions,
-                     a0, Action::Transfer(TransferAction{deposit}), {
-                        assert_eq!(*deposit, TESTING_INIT_BALANCE / 2);
-                     }
-                     => [ref1] );
-    assert_refund!(group, ref0 @ "near_0");
-    assert_refund!(group, ref1 @ "near_0");
+
+    if ProtocolFeature::ReducedGasRefunds.enabled(PROTOCOL_VERSION) {
+        assert_receipts!(group, "near_1" => r1 @ account_id.as_str(),
+        ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
+        actions,
+        a0, Action::Transfer(TransferAction{deposit}), {
+           assert_eq!(*deposit, TESTING_INIT_BALANCE / 2);
+        }
+        => [] );
+        assert_refund!(group, ref0 @ "near_0");
+    } else {
+        assert_receipts!(group, "near_1" => r1 @ account_id.as_str(),
+                         ReceiptEnum::Action(ActionReceipt{actions, ..}), {},
+                         actions,
+                         a0, Action::Transfer(TransferAction{deposit}), {
+                            assert_eq!(*deposit, TESTING_INIT_BALANCE / 2);
+                         }
+                         => [ref1] );
+        assert_refund!(group, ref0 @ "near_0");
+        assert_refund!(group, ref1 @ "near_0");
+    }
 }
 
 #[test]


Reviews:
user: login: akhi3030
body: Changes to production code look straightforward and LGTM.  I have not reviewed the rest of the PR in detail.  If you need a proper review there, let me know.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T08:32:16Z
user: login: nagisa
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T10:06:02Z
user: login: jakmeier
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T21:46:37Z
user: login: jakmeier
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T21:55:11Z
user: login: jakmeier
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T21:59:02Z

Review comments:
diff_hunk: @@ -70,6 +72,7 @@ impl RuntimeNode {
     pub fn free(account_id: &AccountId) -> Self {
         let mut genesis =
             Genesis::test(vec![alice_account(), bob_account(), "carol.near".parse().unwrap()], 3);
+        genesis.config.min_gas_price = 0;
path: integration-tests/src/node/runtime_node.rs
user: login: nagisa
body: commit 2: you say this used to set inflation to 0 but I don't see any changes to that effect (i.e. removing the code that used to set said inflation?)
created_at: 2025-04-18T09:55:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -127,7 +129,10 @@ fn test_cost_sanity() {
     assert_eq!(res.transaction_outcome.outcome.metadata.gas_profile, None);
 
     let receipts_status = get_receipts_status_with_clear_hash(&res.receipts_outcome);
-    insta::assert_yaml_snapshot!("receipts_status", receipts_status);
+    insta::assert_yaml_snapshot!(
+        if cfg!(feature = "nightly") { "receipts_status_nightly" } else { "receipts_status" },
path: integration-tests/src/tests/runtime/sanity_checks.rs
user: login: nagisa
body: Is there a reason this is using compile time conditional compilation while the other tests use runtime checks? Could all the checks be consistent and use `PortocolFeature` everywhere?
created_at: 2025-04-18T09:58:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -356,6 +342,40 @@ pub fn total_prepaid_gas(actions: &[Action]) -> Result<Gas, IntegerOverflowError
     Ok(total_gas)
 }
 
+/// Calculates a maximum expected gas price increase during the execution of the transaction.
+///
+/// Note: this is no longer used with ProtocolFeature::ReducedGasRefunds
+fn pessimistic_gas_price(
+    gas_price: u128,
+    sender_is_receiver: bool,
+    fees: &std::sync::Arc<near_parameters::RuntimeFeesConfig>,
+    prepaid_gas: u64,
+) -> Result<u128, IntegerOverflowError> {
+    // If signer is equals to receiver the receipt will be processed at the same block as this
+    // transaction. Otherwise it will processed in the next block and the gas might be inflated.
+    let initial_receipt_hop = if sender_is_receiver { 0 } else { 1 };
+    // The pessimistic gas pricing is a best-effort limit which can be breached in case of
+    // congestion when receipts are delayed before they execute. Hence there is not much
+    // value to tie this limit to the function call base cost. Making it constant limits
+    // overcharging to 6x, which was the value before the cost increase.
+    let minimum_new_receipt_gas = 4_855_842_000_000; // 4.855TGas.
+    // In case the config is free, we don't care about the maximum depth.
+    let receipt_gas_price = if gas_price == 0 {
+        0
+    } else {
+        let maximum_depth =
+            if minimum_new_receipt_gas > 0 { prepaid_gas / minimum_new_receipt_gas } else { 0 };
+        let inflation_exponent = u8::try_from(initial_receipt_hop + maximum_depth)
+            .map_err(|_| IntegerOverflowError {})?;
+        safe_gas_price_inflated(
+            gas_price,
+            fees.pessimistic_gas_price_inflation_ratio,
path: runtime/runtime/src/config.rs
user: login: nagisa
body: Q: this PR modifies both the inflation rate to be 100% (i.e. no inflation) and special cases this code to not be called at all if the protocol feature is enabled. Are both of these changes necessary at the same time? Maybe it'd be possible to get rid of the parameter changes altogether?
created_at: 2025-04-18T10:04:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,6 +72,7 @@ impl RuntimeNode {
     pub fn free(account_id: &AccountId) -> Self {
         let mut genesis =
             Genesis::test(vec![alice_account(), bob_account(), "carol.near".parse().unwrap()], 3);
+        genesis.config.min_gas_price = 0;
path: integration-tests/src/node/runtime_node.rs
user: login: jakmeier
body: Well, I didn't see a reason to change the parameters in the free runtime config. The free runtime config sets the pessimistic gas price inflation parameter to 0 when it also sets all other parameters. I could set it to 1 but keeping it at 0 seems just as good.

I still  had to fix other code because now this is an unused parameter and previously it was used in all gas price calculations, setting it to 0 even when there was only 1 hop.
created_at: 2025-04-18T21:46:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -356,6 +342,40 @@ pub fn total_prepaid_gas(actions: &[Action]) -> Result<Gas, IntegerOverflowError
     Ok(total_gas)
 }
 
+/// Calculates a maximum expected gas price increase during the execution of the transaction.
+///
+/// Note: this is no longer used with ProtocolFeature::ReducedGasRefunds
+fn pessimistic_gas_price(
+    gas_price: u128,
+    sender_is_receiver: bool,
+    fees: &std::sync::Arc<near_parameters::RuntimeFeesConfig>,
+    prepaid_gas: u64,
+) -> Result<u128, IntegerOverflowError> {
+    // If signer is equals to receiver the receipt will be processed at the same block as this
+    // transaction. Otherwise it will processed in the next block and the gas might be inflated.
+    let initial_receipt_hop = if sender_is_receiver { 0 } else { 1 };
+    // The pessimistic gas pricing is a best-effort limit which can be breached in case of
+    // congestion when receipts are delayed before they execute. Hence there is not much
+    // value to tie this limit to the function call base cost. Making it constant limits
+    // overcharging to 6x, which was the value before the cost increase.
+    let minimum_new_receipt_gas = 4_855_842_000_000; // 4.855TGas.
+    // In case the config is free, we don't care about the maximum depth.
+    let receipt_gas_price = if gas_price == 0 {
+        0
+    } else {
+        let maximum_depth =
+            if minimum_new_receipt_gas > 0 { prepaid_gas / minimum_new_receipt_gas } else { 0 };
+        let inflation_exponent = u8::try_from(initial_receipt_hop + maximum_depth)
+            .map_err(|_| IntegerOverflowError {})?;
+        safe_gas_price_inflated(
+            gas_price,
+            fees.pessimistic_gas_price_inflation_ratio,
path: runtime/runtime/src/config.rs
user: login: jakmeier
body: Yes, the parameter changes could be removed. But then the RPC when queried for the config will report 1.03 as an inflation ratio, without any hints that this is actually depreciated. Like this, it will report a value for new protocol configs that are "correct". (I would deprecate or even remove the parameter, if I knew of a good way of doing it. I can't remember if we ever did that.)

On the other hand, I initially though I would only do the parameter change, without the code changes. But then, I saw you had great progress with limited replayability! :D That's basically why I special case this code to not be called at all. Makes it easy to remove dead code when we no longer versions with pessimistic gas pricing. Otherwise, it's likely to stay in the code base forever.
created_at: 2025-04-18T21:55:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -127,7 +129,10 @@ fn test_cost_sanity() {
     assert_eq!(res.transaction_outcome.outcome.metadata.gas_profile, None);
 
     let receipts_status = get_receipts_status_with_clear_hash(&res.receipts_outcome);
-    insta::assert_yaml_snapshot!("receipts_status", receipts_status);
+    insta::assert_yaml_snapshot!(
+        if cfg!(feature = "nightly") { "receipts_status_nightly" } else { "receipts_status" },
path: integration-tests/src/tests/runtime/sanity_checks.rs
user: login: jakmeier
body: I don't really want to create a separate snapshot for every protocol feature. But having different snapshot for nightly and stable builds is a pattern that is used in several places, so I thought it makes sense to continue using it. 

For example here

https://github.com/near/nearcore/blob/10be926305dbb3b3d6a8f277f8c01b2dbdb16865/integration-tests/src/tests/runtime/sanity_checks.rs#L189-L196
created_at: 2025-04-18T21:59:02Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-04-15T09:22:36Z
body: ## [Codecov](https://app.codecov.io/gh/near/nearcore/pull/13370?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) Report
Attention: Patch coverage is `78.37838%` with `16 lines` in your changes missing coverage. Please review.
> Project coverage is 69.73%. Comparing base [(`978db05`)](https://app.codecov.io/gh/near/nearcore/commit/978db05d8217e6587af0d343a1d0dea4edcb8dd9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) to head [(`341e227`)](https://app.codecov.io/gh/near/nearcore/commit/341e2271cf6a34d318ee3ac6775f0365efa85a71?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near).
> Report is 1 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/near/nearcore/pull/13370?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | Patch % | Lines |
|---|---|---|
| [runtime/runtime/src/config.rs](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&filepath=runtime%2Fruntime%2Fsrc%2Fconfig.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#diff-cnVudGltZS9ydW50aW1lL3NyYy9jb25maWcucnM=) | 84.00% | [0 Missing and 4 partials :warning: ](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) |
| [chain/indexer/src/streamer/mod.rs](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&filepath=chain%2Findexer%2Fsrc%2Fstreamer%2Fmod.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#diff-Y2hhaW4vaW5kZXhlci9zcmMvc3RyZWFtZXIvbW9kLnJz) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) |
| [chain/indexer/src/streamer/utils.rs](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&filepath=chain%2Findexer%2Fsrc%2Fstreamer%2Futils.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#diff-Y2hhaW4vaW5kZXhlci9zcmMvc3RyZWFtZXIvdXRpbHMucnM=) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) |
| [.../runtime-params-estimator/src/estimator\_context.rs](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&filepath=runtime%2Fruntime-params-estimator%2Fsrc%2Festimator_context.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#diff-cnVudGltZS9ydW50aW1lLXBhcmFtcy1lc3RpbWF0b3Ivc3JjL2VzdGltYXRvcl9jb250ZXh0LnJz) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) |
| [runtime/runtime/src/verifier.rs](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&filepath=runtime%2Fruntime%2Fsrc%2Fverifier.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#diff-cnVudGltZS9ydW50aW1lL3NyYy92ZXJpZmllci5ycw==) | 33.33% | [0 Missing and 2 partials :warning: ](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) |
| [chain/chain/src/runtime/mod.rs](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&filepath=chain%2Fchain%2Fsrc%2Fruntime%2Fmod.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#diff-Y2hhaW4vY2hhaW4vc3JjL3J1bnRpbWUvbW9kLnJz) | 95.65% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/near/nearcore/pull/13370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           master   #13370       +/-   ##
===========================================
+ Coverage    1.61%   69.73%   +68.11%     
===========================================
  Files         662      858      +196     
  Lines      115840   170329    +54489     
  Branches   115840   170329    +54489     
===========================================
+ Hits         1875   118775   +116900     
+ Misses     113907    46752    -67155     
- Partials       58     4802     +4744     
```

| [Flag](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | Coverage Δ | |
|---|---|---|
| [backward-compatibility](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | `1.51% <0.00%> (?)` | |
| [db-migration](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | `1.61% <0.00%> (-0.01%)` | :arrow_down: |
| [linux](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | `69.55% <77.02%> (+67.93%)` | :arrow_up: |
| [linux-nightly](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | `69.22% <78.37%> (?)` | |
| [pytests](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | `1.81% <0.00%> (+0.20%)` | :arrow_up: |
| [unittests](https://app.codecov.io/gh/near/nearcore/pull/13370/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near) | `69.56% <78.37%> (?)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/near/nearcore/pull/13370?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=near).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: jakmeier
created_at: 2025-04-16T22:09:18Z
body: The second commit in this PR fixes a weird test case (test_smart_contract_free_runtime).
It relied on pessimistic gas pricing for setting the gas price to 0 in a roundabout way.

I recommend reviewing each commit separately.
author_association: CONTRIBUTOR
user: login: jakmeier
created_at: 2025-04-20T17:05:28Z
body: I fixed some nayduck test in this PR.

But for fixing how the RPC user waits for committed transactions, I created #13398
It's changing code that used by most integration tests, so I'd rather make it a separate PR.
author_association: CONTRIBUTOR