@blinklabs/dingo 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/.dockerignore +5 -0
  2. package/.github/CODEOWNERS +5 -0
  3. package/.github/assets/dingo-ate-my-blockchain.png +0 -0
  4. package/.github/assets/dingo-illustration.png +0 -0
  5. package/.github/assets/dingo-logo-with-text-horizontal.png +0 -0
  6. package/.github/assets/dingo-logo-with-text.png +0 -0
  7. package/.github/dependabot.yml +19 -0
  8. package/.github/dingo-20241210.png +0 -0
  9. package/.github/dingo.md +56 -0
  10. package/.github/workflows/ci-docker.yml +36 -0
  11. package/.github/workflows/conventional-commits.yml +17 -0
  12. package/.github/workflows/go-test.yml +29 -0
  13. package/.github/workflows/golangci-lint.yml +23 -0
  14. package/.github/workflows/publish.yml +207 -0
  15. package/.golangci.yml +71 -0
  16. package/Dockerfile +25 -0
  17. package/LICENSE +201 -0
  18. package/Makefile +53 -0
  19. package/README.md +150 -0
  20. package/blockfetch.go +144 -0
  21. package/chain/chain.go +504 -0
  22. package/chain/chain_test.go +468 -0
  23. package/chain/errors.go +80 -0
  24. package/chain/event.go +33 -0
  25. package/chain/iter.go +64 -0
  26. package/chainsync/chainsync.go +97 -0
  27. package/chainsync.go +223 -0
  28. package/cmd/dingo/load.go +52 -0
  29. package/cmd/dingo/main.go +118 -0
  30. package/cmd/dingo/serve.go +49 -0
  31. package/config/cardano/node.go +192 -0
  32. package/config/cardano/node_test.go +85 -0
  33. package/config/cardano/preview/README.md +4 -0
  34. package/config/cardano/preview/alonzo-genesis.json +196 -0
  35. package/config/cardano/preview/byron-genesis.json +117 -0
  36. package/config/cardano/preview/config.json +114 -0
  37. package/config/cardano/preview/conway-genesis.json +297 -0
  38. package/config/cardano/preview/shelley-genesis.json +68 -0
  39. package/config.go +245 -0
  40. package/connmanager/connection_manager.go +105 -0
  41. package/connmanager/connection_manager_test.go +185 -0
  42. package/connmanager/event.go +37 -0
  43. package/connmanager/listener.go +140 -0
  44. package/connmanager/outbound.go +93 -0
  45. package/connmanager/socket.go +55 -0
  46. package/connmanager/unix.go +78 -0
  47. package/custom-p2p-topology.json +24 -0
  48. package/custom-p2p-topology.json.backup +24 -0
  49. package/custom-p2p-topology.json.mainnet +37 -0
  50. package/database/account.go +138 -0
  51. package/database/block.go +362 -0
  52. package/database/certs.go +53 -0
  53. package/database/commit_timestamp.go +77 -0
  54. package/database/database.go +118 -0
  55. package/database/database_test.go +62 -0
  56. package/database/drep.go +27 -0
  57. package/database/epoch.go +121 -0
  58. package/database/immutable/chunk.go +182 -0
  59. package/database/immutable/immutable.go +350 -0
  60. package/database/immutable/immutable_test.go +59 -0
  61. package/database/immutable/primary.go +106 -0
  62. package/database/immutable/secondary.go +103 -0
  63. package/database/immutable/testdata/08893.chunk +0 -0
  64. package/database/immutable/testdata/08893.primary +0 -0
  65. package/database/immutable/testdata/08893.secondary +0 -0
  66. package/database/immutable/testdata/08894.chunk +0 -0
  67. package/database/immutable/testdata/08894.primary +0 -0
  68. package/database/immutable/testdata/08894.secondary +0 -0
  69. package/database/immutable/testdata/README.md +4 -0
  70. package/database/plugin/blob/badger/commit_timestamp.go +50 -0
  71. package/database/plugin/blob/badger/database.go +152 -0
  72. package/database/plugin/blob/badger/logger.go +63 -0
  73. package/database/plugin/blob/badger/metrics.go +98 -0
  74. package/database/plugin/blob/blob.go +19 -0
  75. package/database/plugin/blob/store.go +40 -0
  76. package/database/plugin/log.go +27 -0
  77. package/database/plugin/metadata/metadata.go +19 -0
  78. package/database/plugin/metadata/sqlite/account.go +224 -0
  79. package/database/plugin/metadata/sqlite/certs.go +58 -0
  80. package/database/plugin/metadata/sqlite/commit_timestamp.go +68 -0
  81. package/database/plugin/metadata/sqlite/database.go +218 -0
  82. package/database/plugin/metadata/sqlite/epoch.go +120 -0
  83. package/database/plugin/metadata/sqlite/models/account.go +81 -0
  84. package/database/plugin/metadata/sqlite/models/auth_committee_hot.go +26 -0
  85. package/database/plugin/metadata/sqlite/models/deregistration_drep.go +26 -0
  86. package/database/plugin/metadata/sqlite/models/drep.go +27 -0
  87. package/database/plugin/metadata/sqlite/models/epoch.go +31 -0
  88. package/database/plugin/metadata/sqlite/models/models.go +45 -0
  89. package/database/plugin/metadata/sqlite/models/pool.go +97 -0
  90. package/database/plugin/metadata/sqlite/models/pparam_update.go +27 -0
  91. package/database/plugin/metadata/sqlite/models/pparams.go +27 -0
  92. package/database/plugin/metadata/sqlite/models/registration_drep.go +28 -0
  93. package/database/plugin/metadata/sqlite/models/resign_committee_cold.go +27 -0
  94. package/database/plugin/metadata/sqlite/models/stake_registration_delegation.go +27 -0
  95. package/database/plugin/metadata/sqlite/models/stake_vote_delegation.go +27 -0
  96. package/database/plugin/metadata/sqlite/models/stake_vote_registration_delegation.go +27 -0
  97. package/database/plugin/metadata/sqlite/models/tip.go +26 -0
  98. package/database/plugin/metadata/sqlite/models/update_drep.go +27 -0
  99. package/database/plugin/metadata/sqlite/models/utxo.go +30 -0
  100. package/database/plugin/metadata/sqlite/models/vote_delegation.go +26 -0
  101. package/database/plugin/metadata/sqlite/models/vote_registration_delegation.go +26 -0
  102. package/database/plugin/metadata/sqlite/pool.go +240 -0
  103. package/database/plugin/metadata/sqlite/pparams.go +110 -0
  104. package/database/plugin/metadata/sqlite/tip.go +83 -0
  105. package/database/plugin/metadata/sqlite/utxo.go +292 -0
  106. package/database/plugin/metadata/store.go +168 -0
  107. package/database/plugin/option.go +190 -0
  108. package/database/plugin/plugin.go +20 -0
  109. package/database/plugin/register.go +118 -0
  110. package/database/pparams.go +145 -0
  111. package/database/tip.go +45 -0
  112. package/database/txn.go +147 -0
  113. package/database/types/types.go +74 -0
  114. package/database/types/types_test.go +83 -0
  115. package/database/utxo.go +263 -0
  116. package/dist/artifacts.json +1 -0
  117. package/dist/checksums.txt +22 -0
  118. package/dist/config.yaml +253 -0
  119. package/dist/dingo-0.5.0-SNAPSHOT-d9431e4.tar.gz +0 -0
  120. package/dist/dingo-0.5.0-SNAPSHOT-d9431e4.tar.gz.sbom.json +1 -0
  121. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_arm64.tar.gz +0 -0
  122. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_arm64.tar.gz.sbom.json +1 -0
  123. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_x86_64.tar.gz +0 -0
  124. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_darwin_x86_64.tar.gz.sbom.json +1 -0
  125. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.apk +0 -0
  126. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.apk.sbom.json +1 -0
  127. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.deb +0 -0
  128. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.deb.sbom.json +1 -0
  129. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.rpm +0 -0
  130. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_amd64.rpm.sbom.json +1 -0
  131. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.apk +0 -0
  132. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.apk.sbom.json +1 -0
  133. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.deb +0 -0
  134. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.deb.sbom.json +1 -0
  135. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.rpm +0 -0
  136. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.rpm.sbom.json +1 -0
  137. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.tar.gz +0 -0
  138. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_arm64.tar.gz.sbom.json +1 -0
  139. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_x86_64.tar.gz +0 -0
  140. package/dist/dingo_0.5.0-SNAPSHOT-d9431e4_linux_x86_64.tar.gz.sbom.json +1 -0
  141. package/dist/dingo_darwin_amd64_v1/dingo +0 -0
  142. package/dist/dingo_darwin_arm64_v8.0/dingo +0 -0
  143. package/dist/dingo_linux_amd64_v1/dingo +0 -0
  144. package/dist/dingo_linux_arm64_v8.0/dingo +0 -0
  145. package/dist/homebrew/dingo.rb +51 -0
  146. package/dist/metadata.json +1 -0
  147. package/event/event.go +141 -0
  148. package/event/event_test.go +115 -0
  149. package/event/metrics.go +44 -0
  150. package/go.mod +98 -0
  151. package/go.sum +358 -0
  152. package/internal/config/config.go +145 -0
  153. package/internal/config/config_test.go +118 -0
  154. package/internal/node/load.go +149 -0
  155. package/internal/node/node.go +176 -0
  156. package/internal/version/version.go +33 -0
  157. package/ledger/certs.go +113 -0
  158. package/ledger/chainsync.go +578 -0
  159. package/ledger/eras/allegra.go +154 -0
  160. package/ledger/eras/alonzo.go +156 -0
  161. package/ledger/eras/babbage.go +154 -0
  162. package/ledger/eras/byron.go +42 -0
  163. package/ledger/eras/conway.go +158 -0
  164. package/ledger/eras/eras.go +44 -0
  165. package/ledger/eras/mary.go +154 -0
  166. package/ledger/eras/shelley.go +164 -0
  167. package/ledger/error.go +19 -0
  168. package/ledger/event.go +50 -0
  169. package/ledger/metrics.go +53 -0
  170. package/ledger/queries.go +260 -0
  171. package/ledger/slot.go +127 -0
  172. package/ledger/slot_test.go +147 -0
  173. package/ledger/state.go +726 -0
  174. package/ledger/view.go +73 -0
  175. package/localstatequery.go +50 -0
  176. package/localtxmonitor.go +44 -0
  177. package/localtxsubmission.go +52 -0
  178. package/mempool/consumer.go +98 -0
  179. package/mempool/mempool.go +322 -0
  180. package/node.go +320 -0
  181. package/package.json +33 -0
  182. package/peergov/event.go +27 -0
  183. package/peergov/peer.go +67 -0
  184. package/peergov/peergov.go +290 -0
  185. package/peersharing.go +70 -0
  186. package/preview-local-topology.json +23 -0
  187. package/topology/topology.go +69 -0
  188. package/topology/topology_test.go +179 -0
  189. package/tracing.go +65 -0
  190. package/txsubmission.go +233 -0
  191. package/utxorpc/query.go +311 -0
  192. package/utxorpc/submit.go +395 -0
  193. package/utxorpc/sync.go +276 -0
  194. package/utxorpc/utxorpc.go +166 -0
  195. package/utxorpc/watch.go +310 -0
@@ -0,0 +1,166 @@
1
+ // Copyright 2025 Blink Labs Software
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ package utxorpc
16
+
17
+ import (
18
+ "fmt"
19
+ "io"
20
+ "log/slog"
21
+ "net/http"
22
+ "time"
23
+
24
+ "connectrpc.com/connect"
25
+ "connectrpc.com/grpchealth"
26
+ "connectrpc.com/grpcreflect"
27
+ "github.com/blinklabs-io/dingo/event"
28
+ "github.com/blinklabs-io/dingo/ledger"
29
+ "github.com/blinklabs-io/dingo/mempool"
30
+ "github.com/utxorpc/go-codegen/utxorpc/v1alpha/query/queryconnect"
31
+ "github.com/utxorpc/go-codegen/utxorpc/v1alpha/submit/submitconnect"
32
+ "github.com/utxorpc/go-codegen/utxorpc/v1alpha/sync/syncconnect"
33
+ "github.com/utxorpc/go-codegen/utxorpc/v1alpha/watch/watchconnect"
34
+ "golang.org/x/net/http2"
35
+ "golang.org/x/net/http2/h2c"
36
+ )
37
+
38
+ type Utxorpc struct {
39
+ config UtxorpcConfig
40
+ }
41
+
42
+ type UtxorpcConfig struct {
43
+ Logger *slog.Logger
44
+ EventBus *event.EventBus
45
+ LedgerState *ledger.LedgerState
46
+ Mempool *mempool.Mempool
47
+ Host string
48
+ Port uint
49
+ TlsCertFilePath string
50
+ TlsKeyFilePath string
51
+ }
52
+
53
+ func NewUtxorpc(cfg UtxorpcConfig) *Utxorpc {
54
+ if cfg.Logger == nil {
55
+ cfg.Logger = slog.New(slog.NewJSONHandler(io.Discard, nil))
56
+ }
57
+ cfg.Logger = cfg.Logger.With("component", "utxorpc")
58
+ if cfg.Host == "" {
59
+ cfg.Host = "0.0.0.0"
60
+ }
61
+ if cfg.Port == 0 {
62
+ cfg.Port = 9090
63
+ }
64
+ return &Utxorpc{
65
+ config: cfg,
66
+ }
67
+ }
68
+
69
+ func (u *Utxorpc) Start() error {
70
+ mux := http.NewServeMux()
71
+ compress1KB := connect.WithCompressMinBytes(1024)
72
+ queryPath, queryHandler := queryconnect.NewQueryServiceHandler(
73
+ &queryServiceServer{utxorpc: u},
74
+ compress1KB,
75
+ )
76
+ submitPath, submitHandler := submitconnect.NewSubmitServiceHandler(
77
+ &submitServiceServer{utxorpc: u},
78
+ compress1KB,
79
+ )
80
+ syncPath, syncHandler := syncconnect.NewSyncServiceHandler(
81
+ &syncServiceServer{utxorpc: u},
82
+ compress1KB,
83
+ )
84
+ watchPath, watchHandler := watchconnect.NewWatchServiceHandler(
85
+ &watchServiceServer{utxorpc: u},
86
+ compress1KB,
87
+ )
88
+ mux.Handle(queryPath, queryHandler)
89
+ mux.Handle(submitPath, submitHandler)
90
+ mux.Handle(syncPath, syncHandler)
91
+ mux.Handle(watchPath, watchHandler)
92
+ mux.Handle(
93
+ grpchealth.NewHandler(
94
+ grpchealth.NewStaticChecker(
95
+ queryconnect.QueryServiceName,
96
+ submitconnect.SubmitServiceName,
97
+ syncconnect.SyncServiceName,
98
+ watchconnect.WatchServiceName,
99
+ ),
100
+ compress1KB,
101
+ ),
102
+ )
103
+ mux.Handle(
104
+ grpcreflect.NewHandlerV1(
105
+ grpcreflect.NewStaticReflector(
106
+ queryconnect.QueryServiceName,
107
+ submitconnect.SubmitServiceName,
108
+ syncconnect.SyncServiceName,
109
+ watchconnect.WatchServiceName,
110
+ ),
111
+ compress1KB,
112
+ ),
113
+ )
114
+ mux.Handle(
115
+ grpcreflect.NewHandlerV1Alpha(
116
+ grpcreflect.NewStaticReflector(
117
+ queryconnect.QueryServiceName,
118
+ submitconnect.SubmitServiceName,
119
+ syncconnect.SyncServiceName,
120
+ watchconnect.WatchServiceName,
121
+ ),
122
+ compress1KB,
123
+ ),
124
+ )
125
+ if u.config.TlsCertFilePath != "" && u.config.TlsKeyFilePath != "" {
126
+ u.config.Logger.Info(
127
+ fmt.Sprintf(
128
+ "starting gRPC TLS listener on %s:%d",
129
+ u.config.Host,
130
+ u.config.Port,
131
+ ),
132
+ )
133
+ utxorpc := &http.Server{
134
+ Addr: fmt.Sprintf(
135
+ "%s:%d",
136
+ u.config.Host,
137
+ u.config.Port,
138
+ ),
139
+ Handler: mux,
140
+ ReadHeaderTimeout: 60 * time.Second,
141
+ }
142
+ return utxorpc.ListenAndServeTLS(
143
+ u.config.TlsCertFilePath,
144
+ u.config.TlsKeyFilePath,
145
+ )
146
+ } else {
147
+ u.config.Logger.Info(
148
+ fmt.Sprintf(
149
+ "starting gRPC listener on %s:%d",
150
+ u.config.Host,
151
+ u.config.Port,
152
+ ),
153
+ )
154
+ utxorpc := &http.Server{
155
+ Addr: fmt.Sprintf(
156
+ "%s:%d",
157
+ u.config.Host,
158
+ u.config.Port,
159
+ ),
160
+ // Use h2c so we can serve HTTP/2 without TLS
161
+ Handler: h2c.NewHandler(mux, &http2.Server{}),
162
+ ReadHeaderTimeout: 60 * time.Second,
163
+ }
164
+ return utxorpc.ListenAndServe()
165
+ }
166
+ }
@@ -0,0 +1,310 @@
1
+ // Copyright 2025 Blink Labs Software
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ package utxorpc
16
+
17
+ import (
18
+ "bytes"
19
+ "context"
20
+ "errors"
21
+ "fmt"
22
+
23
+ "connectrpc.com/connect"
24
+ "github.com/blinklabs-io/gouroboros/ledger"
25
+ ocommon "github.com/blinklabs-io/gouroboros/protocol/common"
26
+ cardano "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano"
27
+ watch "github.com/utxorpc/go-codegen/utxorpc/v1alpha/watch"
28
+ "github.com/utxorpc/go-codegen/utxorpc/v1alpha/watch/watchconnect"
29
+ )
30
+
31
+ // watchServiceServer implements the WatchService API
32
+ type watchServiceServer struct {
33
+ watchconnect.UnimplementedWatchServiceHandler
34
+ utxorpc *Utxorpc
35
+ }
36
+
37
+ // WatchTx
38
+ func (s *watchServiceServer) WatchTx(
39
+ ctx context.Context,
40
+ req *connect.Request[watch.WatchTxRequest],
41
+ stream *connect.ServerStream[watch.WatchTxResponse],
42
+ ) error {
43
+ predicate := req.Msg.GetPredicate() // Predicate
44
+ fieldMask := req.Msg.GetFieldMask()
45
+ intersect := req.Msg.GetIntersect() // []*BlockRef
46
+
47
+ s.utxorpc.config.Logger.Info(
48
+ fmt.Sprintf(
49
+ "Got a WatchTx request with predicate %v and fieldMask %v and intersect %v",
50
+ predicate,
51
+ fieldMask,
52
+ intersect,
53
+ ),
54
+ )
55
+
56
+ // Get our points
57
+ var points []ocommon.Point
58
+ if len(intersect) > 0 {
59
+ for _, blockRef := range intersect {
60
+ blockIdx := blockRef.GetIndex()
61
+ blockHash := blockRef.GetHash()
62
+ slot := blockIdx
63
+ point := ocommon.NewPoint(slot, blockHash)
64
+ points = append(points, point)
65
+ }
66
+ } else {
67
+ point := s.utxorpc.config.LedgerState.Tip().Point
68
+ points = append(points, point)
69
+ }
70
+
71
+ // Get our starting point matching our chain
72
+ point, err := s.utxorpc.config.LedgerState.GetIntersectPoint(points)
73
+ if err != nil {
74
+ s.utxorpc.config.Logger.Error(
75
+ "failed to get points",
76
+ "error", err,
77
+ )
78
+ return err
79
+ }
80
+ if point == nil {
81
+ s.utxorpc.config.Logger.Error(
82
+ "nil point returned",
83
+ )
84
+ return errors.New("nil point returned")
85
+ }
86
+
87
+ // Create our chain iterator
88
+ chainIter, err := s.utxorpc.config.LedgerState.GetChainFromPoint(
89
+ *point,
90
+ false,
91
+ )
92
+ if err != nil {
93
+ s.utxorpc.config.Logger.Error(
94
+ "failed to get chain iterator",
95
+ "error", err,
96
+ )
97
+ return err
98
+ }
99
+
100
+ for {
101
+ // Check for available block
102
+ next, err := chainIter.Next(true)
103
+ if err != nil {
104
+ s.utxorpc.config.Logger.Error(
105
+ "failed to iterate chain",
106
+ "error", err,
107
+ )
108
+ return err
109
+ }
110
+ if next != nil {
111
+ // Get ledger.Block from bytes
112
+ blockBytes := next.Block.Cbor[:]
113
+ blockType, err := ledger.DetermineBlockType(blockBytes)
114
+ if err != nil {
115
+ s.utxorpc.config.Logger.Error(
116
+ "failed to get block type",
117
+ "error", err,
118
+ )
119
+ return err
120
+ }
121
+ block, err := ledger.NewBlockFromCbor(blockType, blockBytes)
122
+ if err != nil {
123
+ s.utxorpc.config.Logger.Error(
124
+ "failed to get block",
125
+ "error", err,
126
+ )
127
+ return err
128
+ }
129
+
130
+ // Loop through transactions
131
+ for _, tx := range block.Transactions() {
132
+ var act watch.AnyChainTx
133
+ actc := watch.AnyChainTx_Cardano{
134
+ Cardano: tx.Utxorpc(),
135
+ }
136
+ act.Chain = &actc
137
+ resp := &watch.WatchTxResponse{
138
+ Action: &watch.WatchTxResponse_Apply{
139
+ Apply: &act,
140
+ },
141
+ }
142
+ if predicate == nil {
143
+ err := stream.Send(resp)
144
+ if err != nil {
145
+ return err
146
+ }
147
+ } else {
148
+ found := false
149
+ assetFound := false
150
+
151
+ // Check Predicate
152
+ addressPattern := predicate.GetMatch().GetCardano().GetHasAddress()
153
+ mintAssetPattern := predicate.GetMatch().GetCardano().GetMintsAsset()
154
+ moveAssetPattern := predicate.GetMatch().GetCardano().GetMovesAsset()
155
+
156
+ var addresses []ledger.Address
157
+ if addressPattern != nil {
158
+ // Handle Exact Address
159
+ exactAddressBytes := addressPattern.GetExactAddress()
160
+ if exactAddressBytes != nil {
161
+ var addr ledger.Address
162
+ err := addr.UnmarshalCBOR(exactAddressBytes)
163
+ if err != nil {
164
+ return fmt.Errorf(
165
+ "failed to decode exact address: %w",
166
+ err,
167
+ )
168
+ }
169
+ addresses = append(addresses, addr)
170
+ }
171
+
172
+ // Handle Payment Part
173
+ paymentPart := addressPattern.GetPaymentPart()
174
+ if paymentPart != nil {
175
+ s.utxorpc.config.Logger.Info("PaymentPart is present, decoding...")
176
+ var paymentAddr ledger.Address
177
+ err := paymentAddr.UnmarshalCBOR(paymentPart)
178
+ if err != nil {
179
+ return fmt.Errorf("failed to decode payment part: %w", err)
180
+ }
181
+ addresses = append(addresses, paymentAddr)
182
+ }
183
+
184
+ // Handle Delegation Part
185
+ delegationPart := addressPattern.GetDelegationPart()
186
+ if delegationPart != nil {
187
+ s.utxorpc.config.Logger.Info(
188
+ "DelegationPart is present, decoding...",
189
+ )
190
+ var delegationAddr ledger.Address
191
+ err := delegationAddr.UnmarshalCBOR(delegationPart)
192
+ if err != nil {
193
+ return fmt.Errorf(
194
+ "failed to decode delegation part: %w",
195
+ err,
196
+ )
197
+ }
198
+ addresses = append(addresses, delegationAddr)
199
+ }
200
+ }
201
+
202
+ var assetPatterns []*cardano.AssetPattern
203
+ if mintAssetPattern != nil {
204
+ assetPatterns = append(assetPatterns, mintAssetPattern)
205
+ }
206
+ if moveAssetPattern != nil {
207
+ assetPatterns = append(assetPatterns, moveAssetPattern)
208
+ }
209
+
210
+ // Convert everything to utxos (ledger.TransactionOutput) for matching
211
+ var utxos []ledger.TransactionOutput
212
+ utxos = append(tx.Outputs(), tx.CollateralReturn())
213
+ var inputs []ledger.TransactionInput
214
+ inputs = append(tx.Inputs(), tx.ReferenceInputs()...)
215
+ inputs = append(inputs, tx.Collateral()...)
216
+ for _, input := range inputs {
217
+ utxo, err := s.utxorpc.config.LedgerState.UtxoByRef(
218
+ input.Id().Bytes(),
219
+ input.Index(),
220
+ )
221
+ if err != nil {
222
+ return fmt.Errorf(
223
+ "failed to look up input: %w",
224
+ err,
225
+ )
226
+ }
227
+ ret, err := utxo.Decode() // ledger.TransactionOutput
228
+ if err != nil {
229
+ return err
230
+ }
231
+ if ret == nil {
232
+ return errors.New("decode returned empty utxo")
233
+ }
234
+ utxos = append(utxos, ret)
235
+ }
236
+
237
+ // Check UTxOs for addresses
238
+ for _, address := range addresses {
239
+ if found {
240
+ break
241
+ }
242
+ if assetFound {
243
+ found = true
244
+ break
245
+ }
246
+ for _, utxo := range utxos {
247
+ if found {
248
+ break
249
+ }
250
+ if assetFound {
251
+ found = true
252
+ break
253
+ }
254
+ if utxo.Address().String() == address.String() {
255
+ if found {
256
+ break
257
+ }
258
+ if assetFound {
259
+ found = true
260
+ break
261
+ }
262
+ // We matched address, check assetPatterns
263
+ for _, assetPattern := range assetPatterns {
264
+ // Address found, no assetPattern
265
+ if assetPattern == nil {
266
+ found = true
267
+ break
268
+ }
269
+ // Filter on assetPattern
270
+ for _, policyId := range utxo.Assets().Policies() {
271
+ if assetFound {
272
+ found = true
273
+ break
274
+ }
275
+ if bytes.Equal(
276
+ policyId.Bytes(),
277
+ assetPattern.GetPolicyId(),
278
+ ) {
279
+ for _, asset := range utxo.Assets().Assets(policyId) {
280
+ if bytes.Equal(asset, assetPattern.GetAssetName()) {
281
+ found = true
282
+ assetFound = true
283
+ break
284
+ }
285
+ }
286
+ }
287
+ }
288
+ }
289
+ if found {
290
+ break
291
+ }
292
+ // Asset not found; skip this UTxO
293
+ if !assetFound {
294
+ continue
295
+ }
296
+ found = true
297
+ }
298
+ }
299
+ }
300
+ if found {
301
+ err := stream.Send(resp)
302
+ if err != nil {
303
+ return err
304
+ }
305
+ }
306
+ }
307
+ }
308
+ }
309
+ }
310
+ }