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:
- Any
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.