Added a subsection:
Versioning The FORMAT As a Feature
There would be value in paying off the technical debt by versioning the FORMAT, so any future upgrades that would prefer to change it would not have to take the whole burden of changing the format.
Old software doesn’t expect the
version field to have anything to do with the format of the TX it’s being fed.
First step would be locking the
version field using consensus, so it could later be used to signal any future consensus rules that would come after the version lock.
Just the version lock wouldn’t break old software so only new, version-aware, software would benefit from that.
It would still help with general preparedness for a future, breaking, change.
From then onward, we could use part of the
version field as an upgrade counter and match it 1-to-1 with applicable consensus specification.
As a consequence:
version value seen before the version lock would relate many-to-many with “prehistorical” consensus specifications, therefore be indeterminate.
However, it would narrow it down to pre-lock era.
- Post-lock, the counter part of the
version field would be 1-to-1 with newer consensus specifications.
We’d have other bits free to allow us to have multiple kinds of TXes exist part of the same consensus specification, which would make the whole
version field relate many-to-1 with consensus specifications.
Alongside the counter, we could use a flag to signal whether an upgrade is breaking or non-breaking, e.g. when we increment the counter for a new HF, if it’s non-breaking then we don’t toggle the flag, and if it is, then we toggle the flag.
Old version-aware software would know the old state of the flag so could know whether it can safely process
counter+1 TXes even if it knows it can’t fully understand them.
In that scenario, upgraded software could know what rules apply to the TX even without knowing the block height, but it still needs to be upgraded so that it could match the
version with applicable consensus rules.
As the consensus upgrade
counter part of the
version field would be the most important and long-lived feature, the 4-byte* uint should be split into 16 bits for the
counter, 1 bit for the breaking flag, and 8 bits for the
type of transaction.
The remainder* would be reserved for future use.
(*) Because the
version field was never locked, and if we want to enable context-free transaction parsing, we’d have to use only the not-seen-prior-to-lock numbers to encode the
newVersion so the new version would have a range smaller than 4 bytes.