Skip to content

Commit 805063c

Browse files
committed
taprootassets: add RpcSupplySync to bridge RPC and verifier syncer
Introduce RpcSupplySync as an intermediary between the supply commit leaf fetch RPC endpoints and the supply verifier syncer.
1 parent 003f739 commit 805063c

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed

supplysync_rpc.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package taprootassets
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
8+
"github.com/lightninglabs/taproot-assets/asset"
9+
"github.com/lightninglabs/taproot-assets/fn"
10+
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
11+
"github.com/lightninglabs/taproot-assets/universe"
12+
"github.com/lightninglabs/taproot-assets/universe/supplycommit"
13+
"github.com/lightninglabs/taproot-assets/universe/supplyverifier"
14+
)
15+
16+
// RpcSupplySync is an implementation of the universe.SupplySyncer interface
17+
// that uses an RPC connection to target a remote universe server.
18+
type RpcSupplySync struct {
19+
conn *universeClientConn
20+
}
21+
22+
// NewRpcSupplySync creates a new RpcSupplySync instance that dials out to
23+
// the target remote universe server address.
24+
func NewRpcSupplySync(
25+
serverAddr universe.ServerAddr) (supplyverifier.SupplyLeafFetcher,
26+
error) {
27+
28+
conn, err := ConnectUniverse(serverAddr)
29+
if err != nil {
30+
return nil, fmt.Errorf("unable to connect to universe RPC "+
31+
"server: %w", err)
32+
}
33+
34+
return &RpcSupplySync{
35+
conn: conn,
36+
}, nil
37+
}
38+
39+
// Ensure RpcSupplySync is of type SupplyLeafFetcher.
40+
var _ supplyverifier.SupplyLeafFetcherFactory = NewRpcSupplySync
41+
42+
// FetchSupplyLeaves fetches the supply leaves for a specific asset group
43+
// within a specified block height range.
44+
func (r *RpcSupplySync) FetchSupplyLeaves(ctx context.Context,
45+
assetSpec asset.Specifier, startBlockHeight,
46+
endBlockHeight fn.Option[uint32]) (supplycommit.SupplyLeaves,
47+
error) {
48+
49+
var zero supplycommit.SupplyLeaves
50+
51+
groupKey, err := assetSpec.UnwrapGroupKeyOrErr()
52+
if err != nil {
53+
return zero, fmt.Errorf("unable to unwrap group key: %w", err)
54+
}
55+
56+
req := &unirpc.FetchSupplyLeavesRequest{
57+
GroupKey: &unirpc.FetchSupplyLeavesRequest_GroupKeyBytes{
58+
GroupKeyBytes: groupKey.SerializeCompressed(),
59+
},
60+
BlockHeightStart: startBlockHeight.UnwrapOr(0),
61+
BlockHeightEnd: endBlockHeight.UnwrapOr(0),
62+
}
63+
64+
resp, err := r.conn.FetchSupplyLeaves(ctx, req)
65+
if err != nil {
66+
return zero, fmt.Errorf("unable to fetch supply leaves: %w",
67+
err)
68+
}
69+
70+
// Convert the RPC response into a SupplyLeaves instance.
71+
supplyLeaves := supplycommit.SupplyLeaves{
72+
IssuanceLeafEntries: make(
73+
[]supplycommit.NewMintEvent, 0,
74+
len(resp.IssuanceLeaves),
75+
),
76+
BurnLeafEntries: make(
77+
[]supplycommit.NewBurnEvent, 0, len(resp.BurnLeaves),
78+
),
79+
IgnoreLeafEntries: make(
80+
[]supplycommit.NewIgnoreEvent, 0,
81+
len(resp.IgnoreLeaves),
82+
),
83+
}
84+
85+
for _, rpcLeaf := range resp.IssuanceLeaves {
86+
mintEvent, err := unmarshalMintEvent(rpcLeaf)
87+
if err != nil {
88+
return zero, fmt.Errorf("unable to unmarshal mint "+
89+
"event: %w", err)
90+
}
91+
92+
supplyLeaves.IssuanceLeafEntries = append(
93+
supplyLeaves.IssuanceLeafEntries, *mintEvent,
94+
)
95+
}
96+
97+
for _, rpcLeaf := range resp.BurnLeaves {
98+
burnEvent, err := unmarshalBurnEvent(rpcLeaf)
99+
if err != nil {
100+
return zero, fmt.Errorf("unable to unmarshal burn "+
101+
"event: %w", err)
102+
}
103+
104+
supplyLeaves.BurnLeafEntries = append(
105+
supplyLeaves.BurnLeafEntries, *burnEvent,
106+
)
107+
}
108+
109+
for _, rpcLeaf := range resp.IgnoreLeaves {
110+
ignoreEvent, err := unmarshalIgnoreEvent(rpcLeaf)
111+
if err != nil {
112+
return zero, fmt.Errorf("unable to unmarshal ignore "+
113+
"event: %w", err)
114+
}
115+
116+
supplyLeaves.IgnoreLeafEntries = append(
117+
supplyLeaves.IgnoreLeafEntries, *ignoreEvent,
118+
)
119+
}
120+
121+
return supplyLeaves, nil
122+
}
123+
124+
// Close closes the RPC connection to the universe server.
125+
func (r *RpcSupplySync) Close() error {
126+
if r.conn != nil && r.conn.ClientConn != nil {
127+
return r.conn.ClientConn.Close()
128+
}
129+
return nil
130+
}
131+
132+
// unmarshalMintEvent converts an RPC SupplyLeafEntry into a NewMintEvent.
133+
func unmarshalMintEvent(
134+
rpcLeaf *unirpc.SupplyLeafEntry) (*supplycommit.NewMintEvent, error) {
135+
136+
if len(rpcLeaf.RawLeaf) == 0 {
137+
return nil, fmt.Errorf("missing RawLeaf data for mint event")
138+
}
139+
140+
var mintEvent supplycommit.NewMintEvent
141+
err := mintEvent.Decode(bytes.NewReader(rpcLeaf.RawLeaf))
142+
if err != nil {
143+
return nil, fmt.Errorf("unable to decode mint event: %w", err)
144+
}
145+
146+
return &mintEvent, nil
147+
}
148+
149+
// unmarshalBurnEvent converts an RPC SupplyLeafEntry into a NewBurnEvent.
150+
func unmarshalBurnEvent(
151+
rpcLeaf *unirpc.SupplyLeafEntry) (*supplycommit.NewBurnEvent, error) {
152+
153+
if len(rpcLeaf.RawLeaf) == 0 {
154+
return nil, fmt.Errorf("missing RawLeaf data for burn event")
155+
}
156+
157+
var burnEvent supplycommit.NewBurnEvent
158+
err := burnEvent.Decode(bytes.NewReader(rpcLeaf.RawLeaf))
159+
if err != nil {
160+
return nil, fmt.Errorf("unable to decode burn event: %w", err)
161+
}
162+
163+
return &burnEvent, nil
164+
}
165+
166+
// unmarshalIgnoreEvent converts an RPC SupplyLeafEntry into a NewIgnoreEvent.
167+
func unmarshalIgnoreEvent(
168+
rpcLeaf *unirpc.SupplyLeafEntry) (*supplycommit.NewIgnoreEvent, error) {
169+
170+
if len(rpcLeaf.RawLeaf) == 0 {
171+
return nil, fmt.Errorf("missing RawLeaf data for ignore event")
172+
}
173+
174+
var signedIgnoreTuple universe.SignedIgnoreTuple
175+
err := signedIgnoreTuple.Decode(bytes.NewReader(rpcLeaf.RawLeaf))
176+
if err != nil {
177+
return nil, fmt.Errorf("unable to decode signed ignore "+
178+
"tuple: %w", err)
179+
}
180+
181+
return &supplycommit.NewIgnoreEvent{
182+
SignedIgnoreTuple: signedIgnoreTuple,
183+
}, nil
184+
}

0 commit comments

Comments
 (0)