wire: add proper types for flag field and improve docs

Summary of changes:

- Add a new const TxFlagMarker to indicate the flag prefix byte.
- Add a new TxFlag type to enumerate the flags supported by the
  tx parser.

  This allows us to avoid hardcoded magics, and will make it easier
  to support new flags in future.
- Improve code comments.

Closes #1598.
This commit is contained in:
Anirudha Bose 2020-09-13 16:45:10 +02:00 committed by John C. Vernaleo
parent 5ae1f21cd9
commit ff59bbc14a
2 changed files with 52 additions and 30 deletions

View file

@ -109,14 +109,38 @@ const (
maxWitnessItemSize = 11000
)
// witnessMarkerBytes are a pair of bytes specific to the witness encoding. If
// this sequence is encoutered, then it indicates a transaction has iwtness
// data. The first byte is an always 0x00 marker byte, which allows decoders to
// distinguish a serialized transaction with witnesses from a regular (legacy)
// one. The second byte is the Flag field, which at the moment is always 0x01,
// but may be extended in the future to accommodate auxiliary non-committed
// fields.
var witessMarkerBytes = []byte{0x00, 0x01}
// TxFlagMarker is the first byte of the FLAG field in a bitcoin tx
// message. It allows decoders to distinguish a regular serialized
// transaction from one that would require a different parsing logic.
//
// Position of FLAG in a bitcoin tx message:
// ┌─────────┬────────────────────┬─────────────┬─────┐
// │ VERSION │ FLAG │ TX-IN-COUNT │ ... │
// │ 4 bytes │ 2 bytes (optional) │ varint │ │
// └─────────┴────────────────────┴─────────────┴─────┘
//
// Zooming into the FLAG field:
// ┌── FLAG ─────────────┬────────┐
// │ TxFlagMarker (0x00) │ TxFlag │
// │ 1 byte │ 1 byte │
// └─────────────────────┴────────┘
const TxFlagMarker = 0x00
// TxFlag is the second byte of the FLAG field in a bitcoin tx message.
// It indicates the decoding logic to use in the transaction parser, if
// TxFlagMarker is detected in the tx message.
//
// As of writing this, only the witness flag (0x01) is supported, but may be
// extended in the future to accommodate auxiliary non-committed fields.
type TxFlag = byte
const (
// WitnessFlag is a flag specific to witness encoding. If the TxFlagMarker
// is encountered followed by the WitnessFlag, then it indicates a
// transaction has witness data. This allows decoders to distinguish a
// serialized transaction with witnesses from a legacy one.
WitnessFlag TxFlag = 0x01
)
// scriptFreeList defines a free list of byte slices (up to the maximum number
// defined by the freeListMaxItems constant) that have a cap according to the
@ -420,18 +444,19 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
return err
}
// A count of zero (meaning no TxIn's to the uninitiated) indicates
// this is a transaction with witness data.
var flag [1]byte
if count == 0 && enc == WitnessEncoding {
// Next, we need to read the flag, which is a single byte.
// A count of zero (meaning no TxIn's to the uninitiated) means that the
// value is a TxFlagMarker, and hence indicates the presence of a flag.
var flag [1]TxFlag
if count == TxFlagMarker && enc == WitnessEncoding {
// The count varint was in fact the flag marker byte. Next, we need to
// read the flag value, which is a single byte.
if _, err = io.ReadFull(r, flag[:]); err != nil {
return err
}
// At the moment, the flag MUST be 0x01. In the future other
// flag types may be supported.
if flag[0] != 0x01 {
// At the moment, the flag MUST be WitnessFlag (0x01). In the future
// other flag types may be supported.
if flag[0] != WitnessFlag {
str := fmt.Sprintf("witness tx but flag byte is %x", flag)
return messageError("MsgTx.BtcDecode", str)
}
@ -690,14 +715,11 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error
// defined in BIP0144.
doWitness := enc == WitnessEncoding && msg.HasWitness()
if doWitness {
// After the txn's Version field, we include two additional
// bytes specific to the witness encoding. The first byte is an
// always 0x00 marker byte, which allows decoders to
// distinguish a serialized transaction with witnesses from a
// regular (legacy) one. The second byte is the Flag field,
// which at the moment is always 0x01, but may be extended in
// the future to accommodate auxiliary non-committed fields.
if _, err := w.Write(witessMarkerBytes); err != nil {
// After the transaction's Version field, we include two additional
// bytes specific to the witness encoding. This byte sequence is known
// as a flag. The first byte is a marker byte (TxFlagMarker) and the
// second one is the flag value to indicate presence of witness data.
if _, err := w.Write([]byte{TxFlagMarker, WitnessFlag}); err != nil {
return err
}
}

View file

@ -935,9 +935,9 @@ var multiWitnessTx = &MsgTx{
// tests.
var multiWitnessTxEncoded = []byte{
0x1, 0x0, 0x0, 0x0, // Version
0x0, // Marker byte indicating 0 inputs, or a segwit encoded tx
0x1, // Flag byte
0x1, // Varint for number of inputs
TxFlagMarker, // Marker byte indicating 0 inputs, or a segwit encoded tx
WitnessFlag, // Flag byte
0x1, // Varint for number of inputs
0xa5, 0x33, 0x52, 0xd5, 0x13, 0x57, 0x66, 0xf0,
0x30, 0x76, 0x59, 0x74, 0x18, 0x26, 0x3d, 0xa2,
0xd9, 0xc9, 0x58, 0x31, 0x59, 0x68, 0xfe, 0xa8,
@ -978,9 +978,9 @@ var multiWitnessTxEncoded = []byte{
// being set to 0x01, the flag is 0x00, which should trigger a decoding error.
var multiWitnessTxEncodedNonZeroFlag = []byte{
0x1, 0x0, 0x0, 0x0, // Version
0x0, // Marker byte indicating 0 inputs, or a segwit encoded tx
0x0, // Incorrect flag byte (should be 0x01)
0x1, // Varint for number of inputs
TxFlagMarker, // Marker byte indicating 0 inputs, or a segwit encoded tx
0x0, // Incorrect flag byte (should be 0x01)
0x1, // Varint for number of inputs
0xa5, 0x33, 0x52, 0xd5, 0x13, 0x57, 0x66, 0xf0,
0x30, 0x76, 0x59, 0x74, 0x18, 0x26, 0x3d, 0xa2,
0xd9, 0xc9, 0x58, 0x31, 0x59, 0x68, 0xfe, 0xa8,