diff --git a/wire/message.go b/wire/message.go index 3c2aa9d8..09f4cfd8 100644 --- a/wire/message.go +++ b/wire/message.go @@ -61,6 +61,8 @@ const ( CmdCFHeaders = "cfheaders" CmdCFCheckpt = "cfcheckpt" CmdSendAddrV2 = "sendaddrv2" + CmdUtreexoProof = "uproof" + CmdGetUtreexoProof = "getuproof" ) // MessageEncoding represents the wire message encoding format to be used. @@ -155,6 +157,12 @@ func makeEmptyMessage(command string) (Message, error) { case CmdUtreexoHeader: msg = &MsgUtreexoHeader{} + case CmdUtreexoProof: + msg = &MsgUtreexoProof{} + + case CmdGetUtreexoProof: + msg = &MsgGetUtreexoProof{} + case CmdAlert: msg = &MsgAlert{} diff --git a/wire/msggetutreexoproof.go b/wire/msggetutreexoproof.go new file mode 100644 index 00000000..913df470 --- /dev/null +++ b/wire/msggetutreexoproof.go @@ -0,0 +1,111 @@ +// Copyright (c) 2024 The utreexo developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "io" + + "github.com/utreexo/utreexod/chaincfg/chainhash" +) + +// MsgGetUtreexoProof encodes uint64s in varints to request specifics indexes of a +// utreexoproof from a peer. +type MsgGetUtreexoProof struct { + // BlockHash is the hash of the block we want the utreexo proof for. + BlockHash chainhash.Hash + + // ProofIndexes are the indexes from the utreexo proof hashes that we want. + ProofIndexes []uint64 + + // LeafIndexes are the indexes from the leaf datas we want. + LeafIndexes []uint64 +} + +// 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 *MsgGetUtreexoProof) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error { + _, err := r.Read(msg.BlockHash[:]) + if err != nil { + return err + } + + proofCount, err := ReadVarInt(r, 0) + if err != nil { + return err + } + + msg.ProofIndexes = make([]uint64, proofCount) + for i := range msg.ProofIndexes { + msg.ProofIndexes[i], err = ReadVarInt(r, pver) + if err != nil { + return err + } + } + + leafCount, err := ReadVarInt(r, 0) + if err != nil { + return err + } + + msg.LeafIndexes = make([]uint64, leafCount) + for i := range msg.LeafIndexes { + msg.LeafIndexes[i], err = ReadVarInt(r, pver) + if err != nil { + return err + } + } + + return nil +} + +// 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 *MsgGetUtreexoProof) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error { + _, err := w.Write(msg.BlockHash[:]) + if err != nil { + return err + } + + err = WriteVarInt(w, pver, uint64(len(msg.ProofIndexes))) + if err != nil { + return err + } + + for i := range msg.ProofIndexes { + err = WriteVarInt(w, pver, msg.ProofIndexes[i]) + if err != nil { + return err + } + } + + err = WriteVarInt(w, pver, uint64(len(msg.LeafIndexes))) + if err != nil { + return err + } + + for i := range msg.LeafIndexes { + err = WriteVarInt(w, pver, msg.LeafIndexes[i]) + if err != nil { + return err + } + } + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetUtreexoProof) Command() string { + return CmdGetUtreexoProof +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetUtreexoProof) MaxPayloadLength(pver uint32) uint32 { + return MaxBlockPayload +} diff --git a/wire/msgutreexoproof.go b/wire/msgutreexoproof.go new file mode 100644 index 00000000..6ddd7de9 --- /dev/null +++ b/wire/msgutreexoproof.go @@ -0,0 +1,115 @@ +// Copyright (c) 2024 The utreexo developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package wire + +import ( + "io" + + "github.com/utreexo/utreexo" + "github.com/utreexo/utreexod/chaincfg/chainhash" +) + +// MsgUtreexoProof is a utreexo proof for a given block that includes the rest of the data not +// communicated by the utreexo header. It may or may not include all the data needed to prove +// the given block as a peer is able to ask for only the proof data it needs. +type MsgUtreexoProof struct { + // BlockHash is the hash of the block this utreexo proof proves. + BlockHash chainhash.Hash + + // ProofHashes is the hashes needed to hash up to the utreexo roots. + ProofHashes []utreexo.Hash + + // LeafDatas are the tx validation data for every input. + LeafDatas []LeafData +} + +// 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 *MsgUtreexoProof) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error { + _, err := r.Read(msg.BlockHash[:]) + if err != nil { + return err + } + + proofCount, err := ReadVarInt(r, 0) + if err != nil { + return err + } + + msg.ProofHashes = make([]utreexo.Hash, proofCount) + for i := range msg.ProofHashes { + _, err = io.ReadFull(r, msg.ProofHashes[i][:]) + if err != nil { + return err + } + } + + leafCount, err := ReadVarInt(r, 0) + if err != nil { + return err + } + + msg.LeafDatas = make([]LeafData, leafCount) + for i := range msg.LeafDatas { + err = msg.LeafDatas[i].DeserializeCompact(r) + if err != nil { + return err + } + } + + return nil +} + +// 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 *MsgUtreexoProof) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error { + _, err := w.Write(msg.BlockHash[:]) + if err != nil { + return err + } + + err = WriteVarInt(w, 0, uint64(len(msg.ProofHashes))) + if err != nil { + return err + } + + for _, h := range msg.ProofHashes { + _, err = w.Write(h[:]) + if err != nil { + return err + } + } + + // Write the size of the leaf datas. + err = WriteVarInt(w, 0, uint64(len(msg.LeafDatas))) + if err != nil { + return err + } + + // Write the actual leaf datas. + for _, ld := range msg.LeafDatas { + err = ld.SerializeCompact(w) + if err != nil { + return err + } + } + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgUtreexoProof) Command() string { + return CmdUtreexoProof +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgUtreexoProof) MaxPayloadLength(pver uint32) uint32 { + return MaxBlockPayload +}