Summary
The Patch release 2.0.3 resolves a known bug identified at the time of the 2.0.0 release, a reported low impact bug, continuing precursor work for an upcoming feature, and some tech debt cleanup.
Bug:
- There was a design assumption that contract maintainers would choose to disable 1.x version(s) of their contracts when they upgrade them to 2.x versions, but this assumption was unfounded and the expected outcome isn’t required or enforced by the host. Thus in the case where there is both an enabled 1.x and 2.x contract version, an attempt to call a 1.x version would result in the loading of an applicable 2.x version of the contract (if any).
Impact:
- LOW - A relatively rare edge case. It was detected in testnet hours before mainnet upgrade to 2.0. However, initial assessment was that the potential impact which was insufficient to stop and unwind the release. Ecosystem impact is a little higher as this bug discourages the upgrading of some 1.x smart contracts, depending upon existent and intended usage.
- If a contract maintainer disables prior 1.x version(s) of their preexisting contract as part of upgrading the contract to 2.x, then they are not affected by this bug. Disabling the prior version of a contract upon upgrade is the preferred practice.
Root Cause:
- Contract major versions (e.g., 1.x vs 2.x) there was no way via the existing interfaces for a caller to specify major version for a specific contract version invocation. Instead, the logic defaulted to the
protocol_version_major
of the highest enabled version.
Change: The transaction structure and the ffi were extended to allow users to precisely identify a specific contract version:
- FFI - new function:
casper_call_package_version
, which includes args formajor_version_ptr
andmajor_version_size
:-
pub fn casper_call_package_version( contract_package_hash_ptr: *const u8, contract_package_hash_size: usize, major_version_ptr: *const u8, major_version_size: usize, contract_version_ptr: *const u8, contract_version_size: usize, entry_point_name_ptr: *const u8, entry_point_name_size: usize, runtime_args_ptr: *const u8, runtime_args_size: usize, result_size: *mut usize, ) -> i32;
-
- Transaction v1
TransactionInvocationTarget
ByPackageHash
&ByPackageName
variants:- new field:
protocol_version_major: Option<ProtocolVersionMajor>
- new field:
Default Behavior:
- When
protocol_version_major
isNone
, the system uses the current major protocol version - When
version
isNone
, the system uses the highest enabled version of the contract - All combinations for these two fields are supported by default ( some + some, some + none, none + some, none + none).
Bug:
- Inconsistent enforcement of minimum bid amount between native
withdraw_bid
and vm1 initiatedwithdraw_bid
. Native logic was correct.
Impact:
- LOW - Inconsistent but basically harmless.
Root Cause:
- Contract runtime instantiation of the vm1 execution engine did not inject the chainspec defined minimum bid, resulting in the value being defaulted to a lower number. Instantiation of native runtime did use the chainspec value.
Fix:
- Changed contract runtime instantiation of vm1 execution engine to inject the chainspec specified value.
Misc:
- ONGOING: Continuing work on vm2 (enabled in some test environments but not intended to be turned on for mainnet as part of this rollout).
- TECH DEBT: Removed several unwraps in
tracking_copy
implementation. Components and utilities should not be allowed to panic if avoidable, such as in this case. Instead, they should either return a message or error code, or raise an event and allow the node to shutdown gracefully, or be made infallible.