From a76f89eecf787c88f9e6426398a079f1b2e1d220 Mon Sep 17 00:00:00 2001 From: Calvin Kim Date: Wed, 23 Oct 2024 16:28:05 +0900 Subject: [PATCH] wire: add msgutreexotx Utreexo tx is a transaction message with utreexo proof attached. Favoring this over the current method which is to have a separate utreexo encoding for the transaction message. --- wire/message.go | 4 ++ wire/message_test.go | 2 + wire/msgutreexotx.go | 114 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 wire/msgutreexotx.go diff --git a/wire/message.go b/wire/message.go index d64477688..5aa4309c1 100644 --- a/wire/message.go +++ b/wire/message.go @@ -38,6 +38,7 @@ const ( CmdNotFound = "notfound" CmdBlock = "block" CmdTx = "tx" + CmdUtreexoTx = "utreexotx" CmdGetHeaders = "getheaders" CmdHeaders = "headers" CmdPing = "ping" @@ -131,6 +132,9 @@ func makeEmptyMessage(command string) (Message, error) { case CmdTx: msg = &MsgTx{} + case CmdUtreexoTx: + msg = &MsgUtreexoTx{} + case CmdPing: msg = &MsgPing{} diff --git a/wire/message_test.go b/wire/message_test.go index 7965e5614..1f04703aa 100644 --- a/wire/message_test.go +++ b/wire/message_test.go @@ -57,6 +57,7 @@ func TestMessage(t *testing.T) { msgGetData := NewMsgGetData() msgNotFound := NewMsgNotFound() msgTx := NewMsgTx(1) + msgUtreexoTx := NewMsgUtreexoTx(1) msgPing := NewMsgPing(123123) msgPong := NewMsgPong(123123) msgGetHeaders := NewMsgGetHeaders() @@ -94,6 +95,7 @@ func TestMessage(t *testing.T) { {msgGetData, msgGetData, pver, MainNet, 25}, {msgNotFound, msgNotFound, pver, MainNet, 25}, {msgTx, msgTx, pver, MainNet, 34}, + {msgUtreexoTx, msgUtreexoTx, pver, MainNet, 37}, {msgPing, msgPing, pver, MainNet, 32}, {msgPong, msgPong, pver, MainNet, 32}, {msgGetHeaders, msgGetHeaders, pver, MainNet, 61}, diff --git a/wire/msgutreexotx.go b/wire/msgutreexotx.go new file mode 100644 index 000000000..7852ba5b4 --- /dev/null +++ b/wire/msgutreexotx.go @@ -0,0 +1,114 @@ +// Copyright (c) 2024 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "io" +) + +// MsgUtreexoTx implements the Message interface and represents a bitcoin utreexo +// tx message. It is used to deliver transaction information in response to a getdata +// message (MsgGetData) for a given transaction with the utreexo proof to verify the +// transaction. +// +// Use the AddTxIn and AddTxOut functions to build up the list of transaction +// inputs and outputs. +type MsgUtreexoTx struct { + // MsgTx is the underlying Bitcoin transaction message. + MsgTx + + // UData is the underlying utreexo data. + UData +} + +// Copy creates a deep copy of a transaction so that the original does not get +// modified when the copy is manipulated. +func (msg *MsgUtreexoTx) Copy() *MsgUtreexoTx { + msgTx := msg.MsgTx.Copy() + newTx := MsgUtreexoTx{ + MsgTx: *msgTx, + UData: *msg.UData.Copy(), + } + + return &newTx +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +// See Deserialize for decoding transactions stored to disk, such as in a +// database, as opposed to decoding transactions from the wire. +func (msg *MsgUtreexoTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error { + // Decode the MsgTx. + var msgTx MsgTx + err := msgTx.BtcDecode(r, pver, enc) + if err != nil { + return err + } + msg.MsgTx = msgTx + + // Decode the utreexo data. + ud := new(UData) + ud.LeafDatas = nil + err = ud.Deserialize(r) + if err != nil { + return err + } + msg.UData = *ud + + return nil +} + +// Deserialize decodes a transaction from r into the receiver using a format +// that is suitable for long-term storage such as a database while respecting +// the Version field in the transaction. This function differs from BtcDecode +// in that BtcDecode decodes from the bitcoin wire protocol as it was sent +// across the network. The wire encoding can technically differ depending on +// the protocol version and doesn't even really need to match the format of a +// stored transaction at all. As of the time this comment was written, the +// encoded transaction is the same in both instances, but there is a distinct +// difference and separating the two allows the API to be flexible enough to +// deal with changes. +func (msg *MsgUtreexoTx) Deserialize(r io.Reader) error { + // At the current time, there is no difference between the wire encoding + // at protocol version 0 and the stable long-term storage format. As + // a result, make use of BtcDecode. + return msg.BtcDecode(r, 0, WitnessEncoding) +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +// See Serialize for encoding transactions to be stored to disk, such as in a +// database, as opposed to encoding transactions for the wire. +func (msg *MsgUtreexoTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error { + // Encode the msgTx. + err := msg.MsgTx.BtcEncode(w, pver, enc) + if err != nil { + return err + } + + // Encode the utreexo data. + return msg.UData.Serialize(w) +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgUtreexoTx) Command() string { + return CmdUtreexoTx +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgUtreexoTx) MaxPayloadLength(pver uint32) uint32 { + return MaxBlockPayload +} + +// NewMsgUtreexoTx returns a new bitcoin utreexotx message that conforms to the +// Message interface. The return instance has a default tx message and the udata +// is initialized to the default values. +func NewMsgUtreexoTx(version int32) *MsgUtreexoTx { + return &MsgUtreexoTx{ + MsgTx: *NewMsgTx(1), + } +}