Skip to content

Commit

Permalink
Merge pull request #217 from kcalvinalvin/2024-11-13-remove-udata-com…
Browse files Browse the repository at this point in the history
…pact

wire, netsync: change MsgUtreexoTx serialization
  • Loading branch information
kcalvinalvin authored Nov 14, 2024
2 parents b1b5bd7 + 5eea94c commit 353f565
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 29 deletions.
2 changes: 1 addition & 1 deletion netsync/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,7 @@ out:
msg.reply <- struct{}{}

case *utreexoTxMsg:
sm.handleTxMsg(&msg.utreexoTx.Tx, msg.peer, &msg.utreexoTx.MsgUtreexoTx().UData)
sm.handleTxMsg(&msg.utreexoTx.Tx, msg.peer, msg.utreexoTx.MsgUtreexoTx().UData)
msg.reply <- struct{}{}

case *blockMsg:
Expand Down
15 changes: 9 additions & 6 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1642,8 +1642,9 @@ func (s *server) pushTxMsg(sp *serverPeer, hash *chainhash.Hash, packedPositions
}

utreexoTx = &wire.MsgUtreexoTx{
MsgTx: *tx.MsgTx(),
UData: *ud,
MsgTx: *tx.MsgTx(),
LeafDatas: ud.LeafDatas,
AccProof: ud.AccProof,
}
}
}
Expand Down Expand Up @@ -1671,8 +1672,9 @@ func (s *server) pushTxMsg(sp *serverPeer, hash *chainhash.Hash, packedPositions
}

utreexoTx = &wire.MsgUtreexoTx{
MsgTx: *tx.MsgTx(),
UData: *ud,
MsgTx: *tx.MsgTx(),
LeafDatas: ud.LeafDatas,
AccProof: ud.AccProof,
}
}
} else if s.flatUtreexoProofIndex != nil {
Expand All @@ -1696,8 +1698,9 @@ func (s *server) pushTxMsg(sp *serverPeer, hash *chainhash.Hash, packedPositions
}

utreexoTx = &wire.MsgUtreexoTx{
MsgTx: *tx.MsgTx(),
UData: *ud,
MsgTx: *tx.MsgTx(),
LeafDatas: ud.LeafDatas,
AccProof: ud.AccProof,
}
}
}
Expand Down
26 changes: 22 additions & 4 deletions wire/leaf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package wire

import (
"bytes"
"crypto/sha512"
"encoding/hex"
"encoding/json"
Expand All @@ -29,16 +30,22 @@ var (
// empty is useful when comparing against BlockHash to see if it hasn't been
// initialized.
empty chainhash.Hash

// emptyLd is useful when comparing against LeafData to see if it hasn't been
// initialized.
emptyLd LeafData
)

// LeafData is all the data that goes into a leaf in the utreexo accumulator.
// The data here serve two roles: commitments and data needed for verification.
//
// Commitment: BlockHash is included in the LeafData to commit to a block.
// Verification: OutPoint is the OutPoint for the utxo being referenced.
// Commitment:
// - BlockHash is included in the LeafData to commit to a block.
//
// Height, IsCoinbase, Amount, and PkScript is the data needed for
// tx verification (script, signatures, etc).
// Verification:
// - OutPoint is the OutPoint for the utxo being referenced.
// - Height, IsCoinbase, Amount, and PkScript is the data needed for
// tx verification (script, signatures, etc).
type LeafData struct {
BlockHash chainhash.Hash
OutPoint OutPoint
Expand All @@ -49,6 +56,17 @@ type LeafData struct {
PkScript []byte
}

// Equal returns if the passed in LeafData is equal to this one.
func (l *LeafData) Equal(other LeafData) bool {
return l.BlockHash == other.BlockHash &&
l.OutPoint == other.OutPoint &&
l.Height == other.Height &&
l.IsCoinBase == other.IsCoinBase &&
l.Amount == other.Amount &&
l.ReconstructablePkType == other.ReconstructablePkType &&
bytes.Equal(l.PkScript, other.PkScript)
}

// Copy creates a deep copy of the leafdata so the original does not get modified
// when the copy is manipulated.
func (l *LeafData) Copy() *LeafData {
Expand Down
2 changes: 1 addition & 1 deletion wire/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +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},
{msgUtreexoTx, msgUtreexoTx, pver, MainNet, 36},
{msgPing, msgPing, pver, MainNet, 32},
{msgPong, msgPong, pver, MainNet, 32},
{msgGetHeaders, msgGetHeaders, pver, MainNet, 61},
Expand Down
94 changes: 77 additions & 17 deletions wire/msgutreexotx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package wire

import (
"io"

"github.com/utreexo/utreexo"
)

// MsgUtreexoTx implements the Message interface and represents a bitcoin utreexo
Expand All @@ -19,17 +21,36 @@ type MsgUtreexoTx struct {
// MsgTx is the underlying Bitcoin transaction message.
MsgTx

// UData is the underlying utreexo data.
UData
// AccProof is the utreexo accumulator proof for all the inputs.
AccProof utreexo.Proof

// LeafDatas are the tx validation data for every input.
LeafDatas []LeafData
}

// 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()

// Copy proof
proofCopy := utreexo.Proof{
Targets: make([]uint64, len(msg.AccProof.Targets)),
Proof: make([]utreexo.Hash, len(msg.AccProof.Proof)),
}
copy(proofCopy.Targets, msg.AccProof.Targets)
copy(proofCopy.Proof, msg.AccProof.Proof)

// Copy leaf datas.
LeafDatas := make([]LeafData, len(msg.LeafDatas))
for i := range LeafDatas {
LeafDatas[i] = *msg.LeafDatas[i].Copy()
}

newTx := MsgUtreexoTx{
MsgTx: *msgTx,
UData: *msg.UData.Copy(),
MsgTx: *msgTx,
AccProof: proofCopy,
LeafDatas: LeafDatas,
}

return &newTx
Expand All @@ -40,31 +61,49 @@ func (msg *MsgUtreexoTx) Copy() *MsgUtreexoTx {
// 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 batchproof.
proof, err := BatchProofDeserialize(r)
if err != nil {
return err
}
msg.AccProof = *proof

// Decode the MsgTx.
var msgTx MsgTx
err := msgTx.BtcDecode(r, pver, enc)
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
// Return early if it's 0. Makes sure msg.LeafDatas is nil which is important for
// reflect.DeepEqual in the tests.
if len(msg.MsgTx.TxIn) == 0 {
return nil
}

msg.LeafDatas = make([]LeafData, len(msg.MsgTx.TxIn))
for i, txIn := range msgTx.TxIn {
isUnconfirmed := txIn.PreviousOutPoint.Index&1 == 1
txIn.PreviousOutPoint.Index >>= 1

if isUnconfirmed {
continue
}

err = msg.LeafDatas[i].DeserializeCompact(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
// 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
Expand All @@ -82,14 +121,35 @@ func (msg *MsgUtreexoTx) Deserialize(r io.Reader) error {
// 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 {
// Write batch proof.
err := BatchProofSerialize(w, &msg.AccProof)
if err != nil {
return err
}

// Go through the TxIns and mark the ones that are not confirmed with a 1 in the LSB.
for i := range msg.TxIn {
msg.TxIn[i].PreviousOutPoint.Index <<= 1
if msg.UData.LeafDatas[i].Equal(emptyLd) {
msg.TxIn[i].PreviousOutPoint.Index |= 1
}
}

// Encode the msgTx.
err := msg.MsgTx.BtcEncode(w, pver, enc)
err = msg.MsgTx.BtcEncode(w, pver, enc)
if err != nil {
return err
}

// Encode the utreexo data.
return msg.UData.Serialize(w)
// 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
Expand Down

0 comments on commit 353f565

Please sign in to comment.