Skip to content

Commit 35fa961

Browse files
authored
Merge pull request #1777 from lightninglabs/wip/supplyverify/pull-sync-verify
supplyverifier: add pull syncer and non-universe node verification
2 parents b25c053 + aa7dff3 commit 35fa961

36 files changed

+2831
-285
lines changed

docs/release-notes/release-notes-0.7.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
- https://github.com/lightninglabs/taproot-assets/pull/1675
7474
- https://github.com/lightninglabs/taproot-assets/pull/1674
7575
- https://github.com/lightninglabs/taproot-assets/pull/1784
76+
- https://github.com/lightninglabs/taproot-assets/pull/1777
7677

7778
- A new [address version 2 was introduced that supports grouped assets and
7879
custom (sender-defined)

itest/supply_commit_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package itest
33
import (
44
"bytes"
55
"context"
6+
"strings"
67
"time"
78

89
"github.com/btcsuite/btcd/btcec/v2"
@@ -586,6 +587,60 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
586587
t.t, rpcAsset.Amount,
587588
uniFetchResp.IgnoreSubtreeRoot.RootNode.RootSum,
588589
)
590+
591+
t.Log("Attempting to fetch supply commit from secondary node")
592+
593+
var peerFetchResp *unirpc.FetchSupplyCommitResponse
594+
require.Eventually(t.t, func() bool {
595+
// nolint: lll
596+
peerFetchResp, err = secondTapd.FetchSupplyCommit(
597+
ctxb, &unirpc.FetchSupplyCommitRequest{
598+
GroupKey: &unirpc.FetchSupplyCommitRequest_GroupKeyBytes{
599+
GroupKeyBytes: groupKeyBytes,
600+
},
601+
Locator: &unirpc.FetchSupplyCommitRequest_VeryFirst{
602+
VeryFirst: true,
603+
},
604+
},
605+
)
606+
if err != nil &&
607+
strings.Contains(err.Error(), "commitment not found") {
608+
609+
return false
610+
}
611+
require.NoError(t.t, err)
612+
613+
// If the fetch response has no block height or hash,
614+
// it means that the supply commitment transaction has not
615+
// been mined yet, so we should retry.
616+
if peerFetchResp.ChainData.BlockHeight == 0 ||
617+
len(peerFetchResp.ChainData.BlockHash) == 0 {
618+
619+
return false
620+
}
621+
622+
// Once the ignore tree includes the ignored asset outpoint, we
623+
// know that the supply commitment has been updated.
624+
if peerFetchResp.IgnoreSubtreeRoot == nil {
625+
return false
626+
}
627+
628+
return true
629+
}, defaultWaitTimeout, time.Second)
630+
631+
require.NotNil(t.t, peerFetchResp)
632+
require.Len(t.t, peerFetchResp.IssuanceLeaves, 1)
633+
require.Len(t.t, peerFetchResp.BurnLeaves, 0)
634+
require.Len(t.t, peerFetchResp.IgnoreLeaves, 2)
635+
636+
require.EqualValues(
637+
t.t, rpcAsset.Amount,
638+
peerFetchResp.IssuanceLeaves[0].LeafNode.RootSum,
639+
)
640+
require.EqualValues(
641+
t.t, rpcAsset.Amount,
642+
peerFetchResp.IgnoreSubtreeRoot.RootNode.RootSum,
643+
)
589644
}
590645

591646
// AssertInclusionProof checks that the inclusion proof for a given leaf key

mssmt/node.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"crypto/sha256"
55
"encoding/binary"
66
"encoding/hex"
7+
"fmt"
78
)
89

910
const (
@@ -23,6 +24,20 @@ var (
2324
// NodeHash represents the key of a MS-SMT node.
2425
type NodeHash [hashSize]byte
2526

27+
// NewNodeHashFromBytes creates a new NodeHash from a byte slice.
28+
func NewNodeHashFromBytes(b []byte) (NodeHash, error) {
29+
var zero NodeHash
30+
31+
if len(b) != hashSize {
32+
return zero, fmt.Errorf("invalid hash size: %d", len(b))
33+
}
34+
35+
var h NodeHash
36+
copy(h[:], b)
37+
38+
return h, nil
39+
}
40+
2641
// String returns a NodeHash as a hex-encoded string.
2742
func (k NodeHash) String() string {
2843
return hex.EncodeToString(k[:])

mssmt/proof.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mssmt
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67

@@ -41,6 +42,38 @@ func NewProof(nodes []Node) *Proof {
4142
}
4243
}
4344

45+
// NewProofFromCompressedBytes initializes a new merkle proof from its
46+
// compressed byte representation.
47+
func NewProofFromCompressedBytes(compressedProofBytes []byte) (Proof, error) {
48+
var zero Proof
49+
50+
if len(compressedProofBytes) == 0 {
51+
return zero, fmt.Errorf("compressed proof bytes are empty")
52+
}
53+
54+
var compressedProof CompressedProof
55+
reader := bytes.NewReader(compressedProofBytes)
56+
if err := compressedProof.Decode(reader); err != nil {
57+
return zero, fmt.Errorf("decode compressed proof: %w", err)
58+
}
59+
60+
// Fail if extra data follows a valid proof encoding.
61+
if remaining := reader.Len(); remaining != 0 {
62+
return zero, fmt.Errorf("trailing data after compressed "+
63+
"proof: %d bytes", remaining)
64+
}
65+
66+
p, err := compressedProof.Decompress()
67+
if err != nil {
68+
return zero, fmt.Errorf("decompress proof: %w", err)
69+
}
70+
if p == nil {
71+
return zero, fmt.Errorf("decompressor returned nil proof")
72+
}
73+
74+
return *p, nil
75+
}
76+
4477
// Root returns the root node obtained by walking up the tree.
4578
func (p Proof) Root(key [32]byte, leaf Node) *BranchNode {
4679
// Note that we don't need to check the error here since the only point

0 commit comments

Comments
 (0)