github near/nearcore 2.14.0-rc.1

latest release: crates-0.38.0-rc.1
pre-release4 hours ago
CODE_COLOR: CODE_YELLOW_TESTNET
RELEASE_VERSION: 2.14.0-rc.1
PROTOCOL_UPGRADE: TRUE
DATABASE_UPGRADE: TRUE
SECURITY_UPGRADE: FALSE

Protocol Changes

  • Remove gas rewards: executing a FunctionCall no longer pays part of the burned gas back to the contract account as a reward. The burnt_gas_reward parameter is changed from 30% (3/10) to 0%. See HSP-027
  • Bounded the combined size of a receipt's resolved promise inputs with a new max_receipt_total_input_size limit of 4_194_944 bytes. Receipts which exceed the limit fail with the new TotalPromiseInputSizeExceeded error without executing their actions. Previously this data was effectively unbounded, as it is read into the state witness before the per-receipt storage proof limit starts counting.
  • Added an ml_dsa_verify host function so contracts can verify FIPS 204 ML-DSA-65 signatures on-chain. It takes the signature (3309 bytes), an arbitrary-length message, and the raw 1952-byte public key, each passed either from memory or from a register, and returns 1 for a valid signature or 0 for an invalid one; a wrongly-sized signature or public key aborts the call with MlDsaVerifyInvalidInput. The message is verified as-is with an empty context string, so callers must not pre-hash it. It costs a fixed base cost of 540 Ggas and a dynamic per-byte cost of 11 Mgas per byte.
  • The per-receipt storage proof limit now applies to every action in a receipt, not just FunctionCall. The recorded proof is checked after each action, and a receipt that goes over per_receipt_storage_proof_size_limit (4 MB) fails at that action with the new ReceiptStorageProofSizeExceeded error; the actions after it do not run. Clients that decode ActionErrorKind should expect the new variant. (#16171)
  • Removed the DelegateV2 meta-transaction action introduced in 2.13.0. A new transaction or receipt carrying it is now rejected at action validation with the new ActionsValidationError::RemovedProtocolFeature error. Its inner nonce advances a gas key of the delegate sender, which the SPICE pending transaction queue does not track, because that queue reads only the outer transaction's signer, public key and nonce index. Gas keys (NEP-611) therefore can no longer sign meta transactions at all, since the older Delegate action already rejects a gas key signer with DelegateActionRequiresNonGasKey. Receipts created before the upgrade keep executing, so meta transactions already in flight across the upgrade boundary still complete. The Action::DelegateV2 and VersionedDelegateActionPayload types stay in the codebase to hold a place for a future delegate action version. Clients that decode ActionsValidationError should expect the new variant.
  • Early chunk producer reassignment. A chunk producer that stops producing used to keep its chunk slots until the end of the epoch, because the kickout set only applies at an epoch boundary. The protocol now tracks per-shard production stats within the epoch and stops assigning new chunks to a producer on a shard once it has missed at least 100 chunks there and its produced-to-expected ratio on that shard has fallen below 80%. The freed slot goes to a healthy producer. Stats never cross an epoch boundary, and a 1000-block grace window at the start of each epoch delays the first possible exclusion to roughly block 1000 of the epoch. A safety valve keeps the least-bad producer eligible when the rule would exclude every distinct producer on a shard, so a shard can never run out of chunk producers. The resulting assignment is precomputed per block and persisted in the ChunkProducers database column, keyed by the chunk's grandparent block, and chunk validation reads that row verbatim instead of re-sampling. Partial state witness, contract-accesses and contract-deploys network messages switch to their V2 wire variants at the same protocol version, since they now carry the grandparent anchor needed to resolve the producer. See Early chunk producer reassignment.
  • Rejected a WithdrawFromGasKey action nested inside a delegate action, with the new ActionsValidationError::WithdrawFromGasKeyNotAllowedInDelegate error. WithdrawFromGasKey stays valid as a top-level action; only the nesting is refused. The SPICE pending transaction queue scans only a transaction's top-level actions for WithdrawFromGasKey, so a nested one drains a gas key that the queue still counts as funded. Receipts created before the upgrade keep executing, so delegate actions already in flight across the upgrade boundary still complete. Clients that decode ActionsValidationError should expect the new variant.
  • A FunctionCall to a contract whose compiled module fails to load now charges the contract-loading fee and aborts, instead of finalizing as a zero-gas no-op. The fee is contract_loading_base plus contract_loading_bytes per byte of contract code, and it is burned even though the call runs no contract code. The call failed before this change too, so the only difference is that the caller now pays for the loading work. (#15923, #16315)
  • Fixed a FunctionCall to a just-distributed global contract failing when the call runs in the same chunk as the distribution receipt and the compiled contract is not in the node's contract cache. The distribution now records the code with the chunk's contract tracker, as a regular DeployContract already does, so the call finds the code instead of failing with CodeDoesNotExist. (#16371)
  • Fixed two ML-DSA-65 cost-charging issues, both of which are no-ops for the classical signature schemes where the relevant quantities coincide. Gas keys now price the exec (storage) fee on the on-trie identifier length (32-byte key hash for ML-DSA-65) and the send (transmission) fee on the wire length, instead of pricing the exec fee on the wire length. Meta transactions now meter the inner DelegateAction signature verification compute on the receiver shard that actually runs the verification, instead of the signer shard, so it counts against the right shard's compute limit. (#16064)
  • Added the sha3_256, sha3_384 and sha3_512 host functions so contracts can compute FIPS-202 SHA-3 digests. Each takes the input either from memory or from a register and writes the digest (32, 48 or 64 bytes respectively) into a register. sha3_256 costs a base of ~5.88 Ggas plus ~21.5 Mgas per input byte; sha3_384 and sha3_512 cost a base of ~5.81 Ggas plus ~36.6 Mgas per input byte. (#16006, #16029)
  • Limited the total number of WASM locals in a contract to at most one local per two bytes of contract code. This size-dependent limit applies alongside the existing absolute limit of 1,000,000 locals per contract. #16348
  • Stabilized universal accounts: a 0u account scheme that unifies implicit and contract-created (deterministic) account creation under one post-quantum-safe derivation. See #16096 for the full set of changes.
  • A FunctionCall action with an empty method_name is now rejected at action validation with the new ActionsValidationError::FunctionCallEmptyMethodName error, so the transaction is refused before it is admitted. Previously such a transaction was admitted and failed on-chain in the VM with MethodResolveError::MethodEmptyName, still burning gas. Clients that decode ActionsValidationError should expect the new variant. (#16089)
  • Capped the total number of storage entries carried by the state-init actions in one receipt at 1_500, counted across the receipt and into nested delegate actions. A receipt over the limit is rejected at action validation with the new ActionsValidationError::TotalNumberOfStateInitEntriesExceeded error. (#16408)

Non-protocol Changes

  • The ChunkProducers database column is now created by every build rather than only by nightly builds, which raises DB_VERSION from 49 to 50. A node started read-write migrates its hot and cold databases in place on startup; the migration only creates the column family and rewrites no data. A read-only process cannot create a column family, so a node opened read-only against a version-49 database will refuse to start. Start the node read-write once before pointing a read-only process at the data directory. (#16301)
  • State sync now verifies reconstructed shard data against the next new chunk before block sync. A mismatch stops the node and preserves the data directory for diagnosis instead of attributing the failure to the chunk producer. (#15994)
  • Removed the option to disable state snapshots. Nodes now always take a state snapshot every epoch, which is what lets them serve state parts to peers over decentralized state sync and is required by cloud archival. Config change: the store.state_snapshot_config field is gone, along with its state_snapshot_type values Enabled/Disabled and the legacy aliases EveryEpoch/ForReshardingOnly. A config.json that still contains store.state_snapshot_config keeps loading (the field is ignored), but a node that previously set it to Disabled (or ForReshardingOnly) will now take snapshots every epoch. Offline tools such as fork-network continue to run without snapshots.
  • Removed the long-deprecated num_block_producer_seats_per_shard, avg_hidden_validator_seats_per_shard, and num_chunk_only_producer_seats fields from EpochConfig. They were given serde defaults in 2.12 and are unused. Existing epoch-config JSON files that still contain these keys keep loading, as the keys are now ignored. (#15481)
  • Removed centralized (external-storage) state sync. Nodes now always sync state from peers, which has been the default for a long time. Breaking config change: state_sync.sync no longer accepts ExternalStorage; a node whose config.json still sets "state_sync": {"sync": {"ExternalStorage": ... }} will fail to start. Remove the state_sync.sync block (peer-based sync is the default) before upgrading. The deprecated --state-sync-bucket flag and the state-parts-dump-check tool are also removed. Dumping state to external storage (state_sync.dump) is unchanged.
  • Added optional pagination to EXPERIMENTAL_view_access_key_list and the view_access_key_list query. The request takes after_key and limit, and the response returns last_key to fetch the following page. A new node-config knob view_access_keys_limit (default 100) bounds the number of keys returned per response; when unset (null) it falls back to the default of 100. Behavioral change: an unpaginated view_access_key_list request (no limit/after_key) now fails for any account holding more than view_access_keys_limit (default 100) access keys; such callers must switch to paginated requests. A paginated request whose limit exceeds the configured bound is clamped down to it rather than rejected. Operators can raise or lower the bound via view_access_keys_limit.
  • Transaction-status timeouts (tx, EXPERIMENTAL_tx_status, and send_tx/broadcast_tx_commit with wait_until) now carry a cause in the TIMEOUT_ERROR's info payload explaining how far the transaction got: NOT_OBSERVED, PENDING (with the last-known status), DOES_NOT_TRACK_SHARD, or ERROR (with debug_info). The info payload is absent on responses from older nodes, so clients should treat it as optional. Previously the timeout gave no detail.
  • Added three Prometheus metrics for the blocks delay tracker: near_blocks_delay_tracker_entries (gauge, labelled by map), near_blocks_delay_tracker_refused_blocks_total (labelled by reason), and near_blocks_delay_tracker_missing_entries_total (labelled by mark). The tracker now records a block only while its height is within [head - 50, head + 500) and only up to 8 blocks per height, so /debug/api/chain_processing_status no longer lists blocks far from the head. Its blocks_delay_tracker error logs about a block that "was not marked received" are now a counter and a debug log, since a missing entry is expected once tracking is bounded.
  • Raised the minimum supported Rust version to 1.95.0. Building nearcore from source now requires a Rust 1.95.0 toolchain.
  • tools/debug-ui now builds with Vite instead of the unmaintained Create React App (react-scripts). Build output layout and the port 3000 dev server are unchanged, so deployment needs no change. Building now requires Node ^20.19.0 || >=22.12.0. (#16175)
  • Stabilized EXPERIMENTAL_tx_status and renamed it to tx_status. EXPERIMENTAL_tx_status keeps working as a deprecated alias, with the same request and response types. Metrics change: the near_rpc_wait_until_count metric now labels tx, tx_status and EXPERIMENTAL_tx_status separately; previously both tx and EXPERIMENTAL_tx_status were counted under the tx_status label. (#16270)
  • DBCol::EpochLightClientBlocks now holds a versioned StoredLightClientBlock instead of the LightClientBlockView RPC type, which raises DB_VERSION from 50 to 51. A node started read-write migrates its hot database in place on startup, rewriting one row per epoch; the column holds a few thousand rows in total. The column is never garbage collected, so its rows were written by binaries going back to 2020 and appear in several borsh layouts; the migration reads each of them and rewrites it as the versioned type. A row that no layout reads stops the migration and names its epoch id rather than being guessed at. (#16394)

Protocol upgrade voting

This release upgrades the protocol version from 85 to 87.
Voting for protocol version 87 will start on Wednesday September 23rd 00:00 UTC.
To continue participating in consensus, you need to upgrade your node before this time.

If voting succeeds in one epoch, the protocol upgrade to version 87 is expected to happen 7-14 hours after the voting epoch ends.

Don't miss a new nearcore release

NewReleases is sending notifications on new releases.