Vasil (Babbage) Hard Fork
Release PR: #487
How to migrate
In case your application must be used continuously by users before and after the hard-fork switch on mainnet, you must plan the migration process.
NOTE: by far most of the changes in the library are backward compatible: all pre-babbage CBOR formats are parsed same as before and also if you are not using any of the new Babbage specific features - the produced CBOR will be in the pre-babbage compatible format, meaning that in most of the cases you can just upgrade your product to the new library version and do nothing else.
One case that requires some additional effort is in case you are using TxBuilderConstants.plutus_default_cost_models() function. The returned cost-models are only valid pre-babbage and later there will be an update that will change what this function returns. But for now there are two new function: .plutus_alonzo_cost_models() (pre-babbage) and .plutus_vasil_cost_models() (babbage). If you are using these provided hardcoded constants you must organise a check that will use either one or the other function depending on the current epoch and the protocol version (whether the hardfork already happened or not). Alternatively you can just dynamically acquire the current valid cost-models from the node or some other API every time and build the parameter object yourself manually, to use instead of the hardcoded values.
API Changes
⚠️ BREAKING CHANGES! #410 #456 #460
Block header body getters
HeaderBody (block header) structure change in #456 , specifically: the functions .nonce_vrf and .leader_vrf don't exist anymore, the yare replaced with .nonce_vrf_or_nothing and .leader_vrf_or_nothing and their return type has changed to potentially return nothing. These function will return non-null result only for blocks BEFORE the hardfork.
Alternative function .vrf_result_or_nothing is added. This function will return non-null result only for blocks AFTER the hardfork.
Helper check functions .has_nonce_and_leader_vrf and .has_vrf_result are also added which will return true only before and after the hardfork, respectively.
Protocol param update: protocol version
The type ProtocolVersions is removed in #410 . It was an incorrect interpretation of the CDDL specification to have the parameter field potentially contain an array of protocol versions. Now the structures properly represent that there is ever strictly one protocol version and two functions changed in the ProtocolParamUpdate type:
.set_protocol_version(ProtocolVersions)is replaced with.set_protocol_version(ProtocolVersion).protocol_version() -> ProtocolVersionsis replaced with.protocol_version() -> ProtocolVersion
So the argument type and the return type has changed in these functions. Be careful with this.
Protocol param update setters
Two protocol parameters are removed from Cardano in that hardfork: the "decentralisation constant" and the "extra entropy".
The setters for these parameters are removed from the type, but the type will still serialise these fields into the byte representation, in case they have beed read during deserialisation.
NOTE: the getter functions for these fields are still there and are usable (even tho deprecated) for the purpose of backward compatibility to parse and read pre-babbage blocks.
TransactionOutput inline scripts and datums #450
The TransactionOutput struct can now contains EITHER a data-hash or an instance of plutus-data itself, to the existing function .set_data_hash, two new setters have been added: .set_plutus_data and .set_script_ref. Corresponding getters .plutus_data and .script_ref both return an optional value or nothing, same as the existing .data_hash. Helper functions .has_data_hash, .has_plutus_data, .has_script_ref have been added.
NOTE: the data-hash and the plutus-data are alternative values and can NOT be both present in an output both at the same time. Setting either one of them will remove the previously present either value from the output, thus .has_data_hash and .has_plutus_data can NEVER be both true, but can both be false. The script-ref value is independent and can be either present or not by itself.
For more details on inlined scripts and datums, see CIP32 and CIP33.
New type ScriptRef is introduced to be used with the .set_script_ref function, and can be one of two forms: ScriptRef.new_native_script(NativeScript) or ScriptRef.new_plutus_script(PlutusScript).
PlutusV2 scripts #458
The new hardfork introduces a new version of the Plutus language PlutusV2, and the language version of the used script must be known to construct a correct transaction. The problem is that the library does not parse the Plutus language itself and does not understand the scripts, it only processed the PlutusScript type as a sequence of bytes (a compiled script).
Thus the version of the used script must be specified by the library user, for this the PlutusScript type have been updated with new functions:
PlutusScript.new_v2(bytes)(as an alternative forPlutusScript.new(bytes))PlutusScript.from_bytes_v2(bytes)(as an alterantive forPlutusScript.from_bytes(bytes))PlutusScript.new_with_version(bytes, Language)PlutusScript.from_bytes_with_version(bytes, Language)
Plus there's a new getter function .language_version() -> Language which returns the version of a script instance.
The type Language is updated to have a new constructor function Language.new_plutus_v2() as an alternative to the existing Language.new_plutus_v1().
Therefore an example of using the above-mentioned ScriptRef type with PlutusV2 would look like:
ScriptRef.new_plutus_script(PlutusScript.from_bytes_v2(bytes));
This script-ref will serialise differently than it would have in case it contained a PlutusV1 script.
NOTE: All the existing APIs that worked with PlutusScript type before will now continue to work in exactly the same way, even tho the underlying serialization have changed depending on the used language version in these scripts. For example, an instance of a TransactionWitnessSet still accepts plutus scripts in exactly the same way, but then depending on the language version in these scripts it may serialize them into different underlying fields.
The API is kept as much backward compatible as possible.
TransactionBuilder changes
There's a special helper module called TxBuilderConstants providing the function .plutus_default_cost_models() which can be used along with the TransactionBuilder.calc_script_data_hash(...). There are now two new functions available in that type:
TxBuilderConstants.plutus_alonzo_cost_models()- returns the same old costmodelsTxBuilderConstants.plutus_vasil_cost_models()- returns the new costmodels including the PlutusV2 language and the updated cost of PlutusV1.
NOTE: The function .plutus_default_cost_models() still returns the Alonzo models. The switch of the default getter will depend on the IOHK posting the protocol update, activating the new models. For now you can use the new specialised functions to use the precise models needed for the network.
NOTE: The CostModel type is internally updated to not assert the expected size of the costs array. Before Babbage this type were always asserting a cost-model always has strictly 166 values, but for PlutusV2 the cost-model contains 175 values, so this assertion is removed.
NOTE: The function TransactionBuilder.calc_script_data_hash(...) is updated to assert and retain only the costmodels for the language version used in the present plutus inputs. E.g. in case only a PlutusV1 script is present in the builder - the function will raise an error in case the V1 cost model is missing in the passed map and then will only use that V1 cost model to calculate the hash.
New min-required-ada math #450
The logic of how the minimal required ADA amount for a UTxO is changing in that hardfork and is now calculated based on cost per BYTE instead of a cost per utxo WORD as it is happening now before the hardfork.
This means there's now a new protocol parameter : coins_per_utxo_byte as a replacement for the previously existing coins_per_utxo_word. The good news is that the parameters are compatible (for now) and the cost per byte is equal to cost per word divided by eight (since a word is 8 bytes long).
Because of this, the existing API is deprecated but is still USABLE, the function .min_ada_required(value, bool, BigNum), and it still accepts the OLD parameter coins_per_utxo_word (WORD!), to keep all the existing code functioning, until it can be updated. All the math within the function is updated to provide the best estimate of the min required ADA for legacy format outputs (no inlined scripts or datums).
The new alternative function is added: min_ada_for_output(TransactionOutput, DataCost). This function accepts an entire output in it's final form and an instance of a DataCost object, which can be created by one of only two ways:
DataCost.new_coins_per_word(BigNum)(DEPRECATED)DataCost.new_coins_per_byte(BigNum)
This is done in order to force the library users to explicitly type out the type of the cost value they are using: per-word (DEPRECATED) or per-byte. Note that the per-word cost type is kept around for now, even tho it is deprecated, because the parameters are compatible for now, and to make the migration process as quick and easy as possible, if needed.
NOTE: that in case you are using new tx-output features like inlined plutus-data or inlined scripts - you can correctly calculate the required min coin ONLY using the new function min_ada_for_output, because the old deprecated function does not have information about these new fields.
This means that in case you have to use the new output fields right now, but don't have access to the new protocol parameter coins_per_utxo_byte just yet, you can still use the new API with your old protocol parameter, using DataCost.new_coins_per_word(coins_per_utxo_word).
TransactionBuilder changes
In the TransactionBuilderConfigBuilder the function .coins_per_utxo_word(BigNum) is deprecated. New function .coins_per_utxo_byte(BigNum) is available. Which again means that the old function can be used for now, until you have the time to update.
NOTE: Both DataCost.new_coins_per_word and .coins_per_utxo_word in the config builder will be removed in one of the future major versions, before the cost per byte protocol parameter gets changed, so you still will need to update your code to use the new parameter, but you have some time for that.
Collateral return #449 #454
The hardfork introduces new functionality to send change from the collateral inputs used in a Plutus transaction. This means that now we will not be required to only ever use pure collateral utxos and lose the entire specified value, in case of a Plutus script fail. Now there's a new API to specify a single collateral return output which can send back some part of the collateral inputs value, including any mentioned assets.
There are two new optional values that can be used together or independently:
- Collateral return (an optional transaction output)
- Total collateral (a number value, specifying the collateral size in lovelaces)
In case the collateral return is not specified - the total collateral (if present) is required to match the total collateral input value. If the collateral return is specified - the total collateral (if present) is then required to match the difference:
sum_value(collateral_inputs) - value(collateral_output) = total_collateral_coin
Which again indicates that the collateral value cannot include any assets so all of them must be included into the collateral return, in case any are present in the collateral inputs.
In case the actual difference does not match the specified total collateral coin precisely - the transaction will be rejected; but if the total collateral coin is not specified at all the difference will not be validated for precision as long as it covers the required minimal collateral value.
New function in the TransactionBody type for this are:
.set_collateral_return(TransactionOutput)and.collateral_return()getter.set_total_collateral(BigNum)and.total_collateral()getter
TransactionBuilder changes
New general functions added to the TransactionBuilder are:
.set_collateral_return(TransactionOutput).set_total_collateral(BigNum)
The values set in these functions are of course correctly considered in the transaction size estimation and are included into the resulting transaction.
But, there are also two new helper function added:
.set_collateral_return_and_total(TransactionOutput)- which will register the passed collateral return and then calculate and set the total collateral value automatically. NOTE: it will fail in case there are some assets in the collateral inputs that are not handled by the specified output..set_total_collateral_and_return(BigNum, Address)- which will register the passed total collateral value and then calculate, construct, and set the collateral return output automatically, and the specified address will be used as the receiver (so probably will be equal to the change address used in the transaction).
This means you don't have to deal with constructing the collateral return output yourself, all you need is to specify the total collateral coin you want to add into the transaction and where to send the change, and the return will be created automatically.
NOTE: both helper functions will raise an error in case there are no collateral inputs added to the builder yet (See .set_collateral).
NOTE: both helper functions may raise a "Not enough coin" error in case the output does not have at least the minimum required ADA coin in it.
NOTE: .set_total_collateral_and_return will NOT add the return output in case the specified total value matches collateral inputs exactly.
NOTE: adding collateral return and collateral total value will change the size of the transaction body, so this must be done before the fee is calculated and change is added.
Reference inputs #461
See CIP31 for more details. The Babbage fork introduces a new transaction field for "reference inputs" that would be visible to Plutus scripts, but would not be spent as a part of that transaction. Basically a way to just link a reference to some UTxO without spending it.
The TransactionBody type has new functions: .set_reference_inputs(TransactionInputs) and .reference_inputs() (note that getter might return nothing as the field is optional).
TransactionBuilder changes
New functions: .add_reference_input(TransactionInput) and .get_reference_inputs(). Note that the "setter" function takes a single input and adds it to the list.
NOTE: the reference inputs don't require any witnessing (signatures or proofs) and their monetary values are completely ignored, their only purpose is to read their inlined plutus data and/or scripts and therefore unlike regular or collateral inputs in the transaction-builder it is not required to specify the values of these inputs or to care about their witnesses - all that's needed are the input references and that's it.