Substrate has the concept of a
transaction_version and an
EXTRINSIC_FORMAT_VERSION. What are these used for and when are they changed?
transaction_version is a field in the
RuntimeVersion struct, specific to a runtime implementation. A bump to this value happens whenever there's a change to a pallet's runtime index and/or when there's a change to the index of a pallet's dispatchable functions. In a world of runtime upgrades, a practical reason for this is that hardware wallets need to know how to correctly encode calls for a given runtime.
EXTRINSIC_FORMAT_VERSION is a constant in Substrate's primitives used to track upgrades of the format of an extrinsic, a.k.a. its encoding representation. This would typically be changes in the ordering of an extrinsic's byte fields for example. This version number is more of an indicator for all Substrate chains to ensure compatibility with how extrinsics are formatted for a runtime rather than one unique to a specific chain. From the Rust docs:
It ensures that if the representation is changed and the format is not known, the decoding fails.
In other words, changing the extrinsic format value will break the APIs of libraries like Polkadot JS API or Subxt, as they need to know how to correctly format a call (byte-wise). Whereas bumping the transaction version indicates that there's been a change in the call indices in a node's metadata, which libraries need to know to correctly encode/decode calls.