├── .github
├── scripts
│ ├── install-bitcoind.sh
│ └── install-cln.sh
└── workflows
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── estimatefees.go
├── getblock.go
├── gettip.go
├── gettransaction.go
├── go.mod
├── go.sum
├── integration_test.py
├── main.go
├── main_test.go
├── requirements.in
└── sendtransaction.go
/.github/scripts/install-bitcoind.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -xeu
4 |
5 | DIRNAME="bitcoin-${BITCOIN_CORE_VERSION}"
6 | FILENAME="${DIRNAME}-x86_64-linux-gnu.tar.gz"
7 |
8 | cd "${HOME}"
9 | wget -q "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_CORE_VERSION}/${FILENAME}"
10 | tar -xf "${FILENAME}"
11 | sudo mv "${DIRNAME}"/bin/* "/usr/local/bin"
12 | rm -rf "${FILENAME}" "${DIRNAME}"
13 |
--------------------------------------------------------------------------------
/.github/scripts/install-cln.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -xeu
4 |
5 | DIRNAME="usr"
6 | FILENAME="clightning-v${CORE_LIGHTNING_VERSION}-Ubuntu-24.04.tar.xz"
7 |
8 | cd "${HOME}"
9 | wget -q "https://github.com/ElementsProject/lightning/releases/download/v${CORE_LIGHTNING_VERSION}/${FILENAME}"
10 | tar -xf "${FILENAME}"
11 | sudo cp -r "${DIRNAME}"/bin /usr/local
12 | sudo cp -r "${DIRNAME}"/libexec /usr/local/libexec
13 | rm -rf "${FILENAME}" "${DIRNAME}"
14 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: build for all platforms
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | permissions:
9 | contents: write
10 |
11 | jobs:
12 | make-release:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/create-release@v1
16 | env:
17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18 | with:
19 | tag_name: ${{ github.ref }}
20 | release_name: ${{ github.ref }}
21 | build-all-for-all:
22 | runs-on: ubuntu-latest
23 | needs:
24 | - make-release
25 | strategy:
26 | matrix:
27 | goos: [linux, freebsd, openbsd]
28 | goarch: [amd64, arm64]
29 | env:
30 | CGO_ENABLED: 0
31 | steps:
32 | - uses: actions/checkout@v4
33 | - uses: wangyoucao577/go-release-action@v1
34 | with:
35 | github_token: ${{ secrets.GITHUB_TOKEN }}
36 | goos: ${{ matrix.goos }}
37 | goarch: ${{ matrix.goarch }}
38 | goversion: "1.22"
39 | build_flags: -trimpath
40 | ldflags: -s -w
41 | overwrite: true
42 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: continuous integration
2 |
3 | on: push
4 |
5 | env:
6 | CORE_LIGHTNING_VERSION: '24.08.2'
7 | GO_VERSION: '1.23'
8 | PYTHON_VERSION: '3.13'
9 |
10 | jobs:
11 | isolation-tests:
12 | runs-on: ubuntu-24.04
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: actions/setup-go@v5
16 | with:
17 | go-version: ${{ env.GO_VERSION }}
18 | - run: make trustedcoin
19 | - run: go test -v
20 |
21 | integration-tests:
22 | name: Integration tests on Bitcoin Core ${{ matrix.bitcoin-core-version }}
23 | runs-on: ubuntu-24.04
24 | env:
25 | BITCOIN_CORE_VERSION: ${{ matrix.bitcoin-core-version }}
26 | VALGRIND: 0
27 | strategy:
28 | fail-fast: false
29 | matrix:
30 | bitcoin-core-version:
31 | - '25.2'
32 | - '26.2'
33 | - '27.2'
34 | - '28.0'
35 | steps:
36 | - uses: actions/checkout@v4
37 | - uses: actions/setup-go@v5
38 | with:
39 | go-version: ${{ env.GO_VERSION }}
40 | - uses: actions/setup-python@v5
41 | with:
42 | python-version: ${{ env.PYTHON_VERSION }}
43 | - run: make trustedcoin
44 | - run: .github/scripts/install-bitcoind.sh
45 | - run: .github/scripts/install-cln.sh
46 | - run: |
47 | python -m venv venv
48 | echo "venv/bin" >> $GITHUB_PATH
49 | source venv/bin/activate
50 | pip install pip-tools
51 | pip-compile --strip-extras
52 | pip-sync
53 | - run: pytest
54 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | dist/
3 | requirements.txt
4 | trustedcoin
5 | venv/
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 nbd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | trustedcoin: $(shell find . -name "*.go")
2 | CC=$$(which musl-gcc) CGO_ENABLED=0 go build -trimpath -ldflags='-d -s -w' -o ./trustedcoin
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## The `trustedcoin` plugin
4 |
5 | [](https://github.com/nbd-wtf/trustedcoin/actions/workflows/test.yml)
6 |
7 | A plugin that uses block explorers (`blockstream.info`, `mempool.space`, `mempool.emzy.de`, `blockchair.com`, `blockchain.info` -- [suggest others](https://github.com/fiatjaf/trustedcoin/issues)) as backends instead of your own Bitcoin node.
8 |
9 | This isn't what you should be doing, but sometimes you may need it.
10 |
11 | (Remember this will download all blocks CLN needs from one of these providers.)
12 |
13 | ## How to install
14 |
15 | This is distributed as a single binary for your delight (or you can compile it yourself with `go get`, or ask me for binaries for other systems if you need them).
16 |
17 | [Download it](https://github.com/fiatjaf/trustedcoin/releases), call `chmod +x ` and put it in `~/.lightning/plugins` (create that directory if it doesn't exist).
18 |
19 | You only need the binary you can get in [the releases page](https://github.com/fiatjaf/trustedcoin/releases), nothing else.
20 |
21 | Then add the following line to your `~/.lightning/config` file:
22 |
23 | ```
24 | disable-plugin=bcli
25 | ```
26 |
27 | This disables the default Bitcoin backend plugin so `trustedcoin` can take its place.
28 |
29 | If you're running on `testnet`, `signet` or `liquid` trustedcoin will also work automatically.
30 |
31 | ## Using `bitcoind`
32 |
33 | If you have `bitcoind` available and start `lightningd` with the settings `bitcoin-rpcuser`, `bitcoin-rpcpassword`, and optionally `bitcoin-rpcconnect` (defaults to 127.0.0.1) and `bitcoin-rpcport` (defaults to 8332 on mainnet etc.), then `trustedcoin` will try to use that and fall back to the explorers when it is not available -- so now you can have a node running at home and it will not be the end of the world for your CLN node when there is a power outage.
34 |
35 | ### Extra: how to bootstrap a Lightning node from scratch, without Bitcoin Core, on Ubuntu amd64
36 |
37 | ```
38 | add-apt-repository ppa:lightningnetwork/ppa
39 | apt update
40 | apt install lightningd
41 | mkdir -p ~/.lightning/plugins
42 | echo 'disable-plugin=bcli' >> .lightning/config
43 | cd ~/.lightning/plugins
44 | wget https://github.com/nbd-wtf/trustedcoin/releases/download/v0.8.5/trustedcoin-v0.8.5-linux-amd64.tar.gz
45 | tar -xvf trustedcoin-v0.8.5-linux-amd64.tar.gz
46 | cd
47 | lightningd
48 | ```
49 |
--------------------------------------------------------------------------------
/estimatefees.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "net/http"
7 |
8 | "github.com/btcsuite/btcd/btcjson"
9 | )
10 |
11 | type EstimatedFees struct {
12 | FeeRateFloor int `json:"feerate_floor"`
13 | FeeRates []FeeRate `json:"feerates"`
14 | }
15 |
16 | type FeeRate struct {
17 | Blocks int `json:"blocks"`
18 | FeeRate int `json:"feerate"`
19 | }
20 |
21 | func getFeeRates(network string) (*EstimatedFees, error) {
22 | if network == "regtest" {
23 | return &EstimatedFees{
24 | FeeRateFloor: 1000,
25 | FeeRates: []FeeRate{
26 | {Blocks: 2, FeeRate: 1000},
27 | {Blocks: 6, FeeRate: 1000},
28 | {Blocks: 12, FeeRate: 1000},
29 | {Blocks: 100, FeeRate: 1000},
30 | },
31 | }, nil
32 | }
33 |
34 | // try bitcoind first
35 | if bitcoind != nil {
36 | in2, err2 := bitcoind.EstimateSmartFee(2, &btcjson.EstimateModeConservative)
37 | in6, err6 := bitcoind.EstimateSmartFee(6, &btcjson.EstimateModeEconomical)
38 | in12, err12 := bitcoind.EstimateSmartFee(12, &btcjson.EstimateModeEconomical)
39 | in100, err100 := bitcoind.EstimateSmartFee(100, &btcjson.EstimateModeEconomical)
40 | if err2 == nil && err6 == nil && err12 == nil && err100 == nil &&
41 | in2.FeeRate != nil && in6.FeeRate != nil && in12.FeeRate != nil && in100.FeeRate != nil {
42 |
43 | satPerKbP := func(r *btcjson.EstimateSmartFeeResult) int {
44 | return int(*r.FeeRate * float64(100000000))
45 | }
46 |
47 | return &EstimatedFees{
48 | FeeRateFloor: satPerKbP(in100),
49 | FeeRates: []FeeRate{
50 | {Blocks: 2, FeeRate: satPerKbP(in2)},
51 | {Blocks: 6, FeeRate: satPerKbP(in6)},
52 | {Blocks: 12, FeeRate: satPerKbP(in12)},
53 | {Blocks: 100, FeeRate: satPerKbP(in100)},
54 | },
55 | }, nil
56 | }
57 | }
58 |
59 | // then try explorers
60 | // (just copy sauron here)
61 | feerates, err := getFeeRatesFromEsplora()
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | // actually let's be a little more patient here than sauron is
67 | slow := int(feerates["504"] * 1000)
68 | normal := int(feerates["10"] * 1000)
69 | urgent := int(feerates["5"] * 1000)
70 | veryUrgent := int(feerates["2"] * 1000)
71 |
72 | return &EstimatedFees{
73 | FeeRateFloor: slow,
74 | FeeRates: []FeeRate{
75 | {Blocks: 2, FeeRate: veryUrgent},
76 | {Blocks: 5, FeeRate: urgent},
77 | {Blocks: 10, FeeRate: normal},
78 | {Blocks: 504, FeeRate: slow},
79 | },
80 | }, nil
81 | }
82 |
83 | func getFeeRatesFromEsplora() (feerates map[string]float64, err error) {
84 | for _, endpoint := range esploras(network) {
85 | w, errW := http.Get(endpoint + "/fee-estimates")
86 | if errW != nil {
87 | err = errW
88 | continue
89 | }
90 | defer w.Body.Close()
91 |
92 | if w.StatusCode >= 300 {
93 | continue
94 | }
95 |
96 | if err := json.NewDecoder(w.Body).Decode(&feerates); err != nil {
97 | continue
98 | } else {
99 | return feerates, nil
100 | }
101 | }
102 |
103 | return nil, errors.New("none of the esploras returned usable responses")
104 | }
105 |
--------------------------------------------------------------------------------
/getblock.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "encoding/json"
7 | "errors"
8 | "fmt"
9 | "io"
10 | "net/http"
11 | "strings"
12 |
13 | "github.com/btcsuite/btcd/btcutil"
14 | "github.com/btcsuite/btcd/chaincfg/chainhash"
15 | "github.com/btcsuite/btcd/wire"
16 | )
17 |
18 | var heightCache = make(map[int64]string)
19 |
20 | func getBlock(height int64) (block, hash string, err error) {
21 | hash, err = getHash(height)
22 | if err != nil {
23 | return
24 | }
25 | if hash == "" /* block unavailable */ {
26 | return
27 | }
28 |
29 | // try bitcoind first
30 | if bitcoind != nil {
31 | var decodedChainHash chainhash.Hash
32 | if err := chainhash.Decode(&decodedChainHash, hash); err == nil {
33 | if block, err := bitcoind.GetBlock(&decodedChainHash); err == nil {
34 | raw := &bytes.Buffer{}
35 | if err := block.BtcEncode(raw, wire.ProtocolVersion, wire.WitnessEncoding); err == nil {
36 | return hex.EncodeToString(raw.Bytes()), hash, nil
37 | }
38 | }
39 | }
40 | }
41 |
42 | // then try explorers
43 | var blockFetchFunctions []func(string) ([]byte, error)
44 | switch network {
45 | case "bitcoin":
46 | blockFetchFunctions = append(blockFetchFunctions, blockFromBlockchainInfo)
47 | blockFetchFunctions = append(blockFetchFunctions, blockFromBlockchair)
48 | blockFetchFunctions = append(blockFetchFunctions, blockFromEsplora)
49 | case "testnet":
50 | blockFetchFunctions = append(blockFetchFunctions, blockFromEsplora)
51 | blockFetchFunctions = append(blockFetchFunctions, blockFromBlockchair)
52 | case "signet", "liquid":
53 | blockFetchFunctions = append(blockFetchFunctions, blockFromEsplora)
54 | }
55 |
56 | for _, try := range blockFetchFunctions {
57 | block, errW := try(hash)
58 | if errW != nil || block == nil {
59 | err = errW
60 | continue
61 | }
62 |
63 | // verify and hash, but only on mainnet, the others we trust even more blindly
64 | if network == "bitcoin" {
65 | blockparsed, errW := btcutil.NewBlockFromBytes(block)
66 | if errW != nil {
67 | err = errW
68 | continue
69 | }
70 | header := blockparsed.MsgBlock().Header
71 |
72 | blockhash := hex.EncodeToString(reverseHash(blockparsed.Hash()))
73 | if blockhash != hash {
74 | err = fmt.Errorf("fetched block hash %s doesn't match expected %s",
75 | blockhash, hash)
76 | continue
77 | }
78 |
79 | prevHash := hex.EncodeToString(reverseHash(&header.PrevBlock))
80 | if cachedPrevHash, ok := heightCache[height-1]; ok {
81 | if prevHash != cachedPrevHash {
82 | // something is badly wrong with this block
83 | err = fmt.Errorf("block %d (%s): prev block hash %d (%s) doesn't match what we know from previous block %d (%s)", height, blockhash, height-1, prevHash, height-1, cachedPrevHash)
84 | continue
85 | }
86 | }
87 | }
88 |
89 | blockhex := hex.EncodeToString(block)
90 | return blockhex, hash, nil
91 | }
92 |
93 | return
94 | }
95 |
96 | func getHash(height int64) (hash string, err error) {
97 | // try bitcoind first
98 | if bitcoind != nil {
99 | if hash, err := bitcoind.GetBlockHash(height); err == nil {
100 | return hash.String(), nil
101 | }
102 | }
103 |
104 | // then try explorers
105 | for _, endpoint := range esploras(network) {
106 | w, errW := http.Get(fmt.Sprintf(endpoint+"/block-height/%d", height))
107 | if errW != nil {
108 | err = errW
109 | continue
110 | }
111 | defer w.Body.Close()
112 |
113 | if w.StatusCode >= 404 {
114 | continue
115 | }
116 |
117 | data, errW := io.ReadAll(w.Body)
118 | if errW != nil {
119 | err = errW
120 | continue
121 | }
122 |
123 | hash = strings.TrimSpace(string(data))
124 |
125 | if len(hash) > 64 {
126 | err = errors.New("got something that isn't a block hash: " + hash[:64])
127 | continue
128 | }
129 |
130 | return hash, nil
131 | }
132 |
133 | return "", err
134 | }
135 |
136 | func reverseHash(hash *chainhash.Hash) []byte {
137 | r := make([]byte, chainhash.HashSize)
138 | for i, b := range hash {
139 | r[chainhash.HashSize-i-1] = b
140 | }
141 | return r
142 | }
143 |
144 | func blockFromBlockchainInfo(hash string) ([]byte, error) {
145 | w, err := http.Get(fmt.Sprintf("https://blockchain.info/rawblock/%s?format=hex", hash))
146 | if err != nil {
147 | return nil, fmt.Errorf("failed to get raw block %s from blockchain.info: %s", hash, err.Error())
148 | }
149 | defer w.Body.Close()
150 |
151 | block, _ := io.ReadAll(w.Body)
152 | if len(block) < 100 {
153 | // block not available here yet
154 | return nil, nil
155 | }
156 |
157 | blockbytes, err := hex.DecodeString(string(block))
158 | if err != nil {
159 | return nil, fmt.Errorf("block from blockchain.info is invalid hex: %w", err)
160 | }
161 |
162 | return blockbytes, nil
163 | }
164 |
165 | func blockFromBlockchair(hash string) ([]byte, error) {
166 | var url string
167 | switch network {
168 | case "bitcoin":
169 | url = "https://api.blockchair.com/bitcoin/raw/block/"
170 | case "testnet":
171 | url = "https://api.blockchair.com/bitcoin/testnet/raw/block/"
172 | default:
173 | return nil, nil
174 | }
175 | w, err := http.Get(url + hash)
176 | if err != nil {
177 | return nil, fmt.Errorf(
178 | "failed to get raw block %s from blockchair.com: %s", hash, err.Error())
179 | }
180 | defer w.Body.Close()
181 |
182 | var data struct {
183 | Data map[string]struct {
184 | RawBlock string `json:"raw_block"`
185 | } `json:"data"`
186 | }
187 | err = json.NewDecoder(w.Body).Decode(&data)
188 | if err != nil {
189 | return nil, err
190 | }
191 |
192 | if bdata, ok := data.Data[hash]; ok {
193 | blockbytes, err := hex.DecodeString(bdata.RawBlock)
194 | if err != nil {
195 | return nil, fmt.Errorf("block from blockchair is invalid hex: %w", err)
196 | }
197 |
198 | return blockbytes, nil
199 | } else {
200 | // block not available here yet
201 | return nil, nil
202 | }
203 | }
204 |
205 | func blockFromEsplora(hash string) ([]byte, error) {
206 | var err error
207 | var block []byte
208 |
209 | for _, endpoint := range esploras(network) {
210 | w, errW := http.Get(fmt.Sprintf(endpoint+"/block/%s/raw", hash))
211 | if errW != nil {
212 | err = errW
213 | continue
214 | }
215 |
216 | defer w.Body.Close()
217 | block, _ = io.ReadAll(w.Body)
218 |
219 | if len(block) < 200 {
220 | // block not available yet
221 | return nil, nil
222 | }
223 |
224 | break
225 | }
226 |
227 | return block, err
228 | }
229 |
--------------------------------------------------------------------------------
/gettip.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "io"
5 | "net/http"
6 | "strconv"
7 | )
8 |
9 | func getTip() (tip int64, err error) {
10 | // try bitcoind first
11 | if bitcoind != nil {
12 | if info, err := bitcoind.GetBlockChainInfo(); err == nil {
13 | return int64(info.Headers), nil
14 | }
15 | }
16 |
17 | // then try explorers
18 | for _, endpoint := range esploras(network) {
19 | w, errW := http.Get(endpoint + "/blocks/tip/height")
20 | if errW != nil {
21 | err = errW
22 | continue
23 | }
24 | defer w.Body.Close()
25 |
26 | data, errW := io.ReadAll(w.Body)
27 | if errW != nil {
28 | err = errW
29 | continue
30 | }
31 |
32 | tip, errW = strconv.ParseInt(string(data), 10, 64)
33 | if errW != nil {
34 | err = errW
35 | continue
36 | }
37 |
38 | return tip, nil
39 | }
40 |
41 | return 0, err
42 | }
43 |
--------------------------------------------------------------------------------
/gettransaction.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/hex"
5 | "encoding/json"
6 | "net/http"
7 |
8 | "github.com/btcsuite/btcd/chaincfg/chainhash"
9 | )
10 |
11 | type UTXOResponse struct {
12 | Amount *int64 `json:"amount"`
13 | Script *string `json:"script"`
14 | }
15 |
16 | type TxResponse struct {
17 | TXID string `json:"txid"`
18 | Vout []TxVout `json:"vout"`
19 | }
20 |
21 | type TxVout struct {
22 | ScriptPubKey string `json:"scriptPubKey"`
23 | Value int64 `json:"value"`
24 | }
25 |
26 | func getTransaction(txid string) (tx TxResponse, err error) {
27 | // try bitcoind first
28 | if bitcoind != nil {
29 | var decodedChainHash chainhash.Hash
30 | if err := chainhash.Decode(&decodedChainHash, txid); err == nil {
31 | if tx, err := bitcoind.GetRawTransaction(&decodedChainHash); err == nil {
32 | outputs := tx.MsgTx().TxOut
33 | vout := make([]TxVout, len(outputs))
34 | for i, out := range outputs {
35 | vout[i] = TxVout{
36 | ScriptPubKey: hex.EncodeToString(out.PkScript),
37 | Value: out.Value,
38 | }
39 | }
40 |
41 | return TxResponse{
42 | TXID: txid,
43 | Vout: vout,
44 | }, nil
45 | }
46 | }
47 | }
48 |
49 | // then try explorers
50 | for _, endpoint := range esploras(network) {
51 | w, errW := http.Get(endpoint + "/tx/" + txid)
52 | if errW != nil {
53 | err = errW
54 | continue
55 | }
56 | defer w.Body.Close()
57 |
58 | errW = json.NewDecoder(w.Body).Decode(&tx)
59 | if errW != nil {
60 | err = errW
61 | continue
62 | }
63 |
64 | return tx, nil
65 | }
66 |
67 | return
68 | }
69 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/nbd-wtf/trustedcoin
2 |
3 | go 1.23
4 |
5 | require (
6 | github.com/btcsuite/btcd v0.24.3-0.20240921052913-67b8efd3ba53
7 | github.com/btcsuite/btcd/btcutil v1.1.6
8 | github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
9 | github.com/fiatjaf/lightningd-gjson-rpc v1.6.4-0.20241113234716-c08cd810b4d5
10 | )
11 |
12 | require (
13 | github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
14 | github.com/aead/siphash v1.0.1 // indirect
15 | github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
16 | github.com/btcsuite/btcd/btcutil/psbt v1.1.9 // indirect
17 | github.com/btcsuite/btclog v0.0.0-20241017175713-3428138b75c7 // indirect
18 | github.com/btcsuite/btclog/v2 v2.0.0-20241017175713-3428138b75c7 // indirect
19 | github.com/btcsuite/btcwallet v0.16.10-0.20240912233857-ffb143c77cc5 // indirect
20 | github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 // indirect
21 | github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 // indirect
22 | github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5 // indirect
23 | github.com/btcsuite/btcwallet/walletdb v1.4.4 // indirect
24 | github.com/btcsuite/btcwallet/wtxmgr v1.5.4 // indirect
25 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect
26 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect
27 | github.com/btcsuite/winsvc v1.0.0 // indirect
28 | github.com/davecgh/go-spew v1.1.1 // indirect
29 | github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
30 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
31 | github.com/decred/dcrd/lru v1.1.3 // indirect
32 | github.com/go-errors/errors v1.5.1 // indirect
33 | github.com/golang/snappy v0.0.4 // indirect
34 | github.com/jessevdk/go-flags v1.6.1 // indirect
35 | github.com/jrick/logrotate v1.1.2 // indirect
36 | github.com/kkdai/bstream v1.0.0 // indirect
37 | github.com/klauspost/compress v1.17.9 // indirect
38 | github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect
39 | github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd // indirect
40 | github.com/lightninglabs/neutrino/cache v1.1.2 // indirect
41 | github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect
42 | github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20241111141603-4f6b510869ab // indirect
43 | github.com/lightningnetwork/lnd/clock v1.1.1 // indirect
44 | github.com/lightningnetwork/lnd/fn v1.2.5 // indirect
45 | github.com/lightningnetwork/lnd/queue v1.1.1 // indirect
46 | github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect
47 | github.com/lightningnetwork/lnd/tlv v1.2.7 // indirect
48 | github.com/lightningnetwork/lnd/tor v1.1.4 // indirect
49 | github.com/miekg/dns v1.1.62 // indirect
50 | github.com/pmezard/go-difflib v1.0.0 // indirect
51 | github.com/stretchr/objx v0.5.2 // indirect
52 | github.com/stretchr/testify v1.9.0 // indirect
53 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
54 | github.com/tidwall/gjson v1.18.0 // indirect
55 | github.com/tidwall/match v1.1.1 // indirect
56 | github.com/tidwall/pretty v1.2.1 // indirect
57 | golang.org/x/crypto v0.29.0 // indirect
58 | golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
59 | golang.org/x/mod v0.22.0 // indirect
60 | golang.org/x/net v0.31.0 // indirect
61 | golang.org/x/sync v0.9.0 // indirect
62 | golang.org/x/sys v0.27.0 // indirect
63 | golang.org/x/term v0.26.0 // indirect
64 | golang.org/x/tools v0.27.0 // indirect
65 | gopkg.in/yaml.v3 v3.0.1 // indirect
66 | )
67 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
2 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
3 | github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
4 | github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
5 | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
6 | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
7 | github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
8 | github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
9 | github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
10 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
11 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
12 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
13 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
14 | github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
15 | github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
16 | github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg=
17 | github.com/btcsuite/btcd v0.24.3-0.20240921052913-67b8efd3ba53 h1:XOZ/wRGHkKv0AqxfDks5IkzaQ1Ge6fq322ZOOG5VIkU=
18 | github.com/btcsuite/btcd v0.24.3-0.20240921052913-67b8efd3ba53/go.mod h1:zHK7t7sw8XbsCkD64WePHE3r3k9/XoGAcf6mXV14c64=
19 | github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
20 | github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
21 | github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
22 | github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
23 | github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
24 | github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
25 | github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=
26 | github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=
27 | github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE=
28 | github.com/btcsuite/btcd/btcutil/psbt v1.1.9 h1:UmfOIiWMZcVMOLaN+lxbbLSuoINGS1WmK1TZNI0b4yk=
29 | github.com/btcsuite/btcd/btcutil/psbt v1.1.9/go.mod h1:ehBEvU91lxSlXtA+zZz3iFYx7Yq9eqnKx4/kSrnsvMY=
30 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
31 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
32 | github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
33 | github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
34 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
35 | github.com/btcsuite/btclog v0.0.0-20241017175713-3428138b75c7 h1:Sy/7AwD/XuTsfXHMvcmjF8ZvAX0qR2TMcDbBANuMTR4=
36 | github.com/btcsuite/btclog v0.0.0-20241017175713-3428138b75c7/go.mod h1:w7xnGOhwT3lmrS4H3b/D1XAXxvh+tbhUm8xeHN2y3TQ=
37 | github.com/btcsuite/btclog/v2 v2.0.0-20241017175713-3428138b75c7 h1:3Ct3zN3VCEKVm5nceWBBEKczc+jvTfVyOEG71ob2Yuc=
38 | github.com/btcsuite/btclog/v2 v2.0.0-20241017175713-3428138b75c7/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE=
39 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
40 | github.com/btcsuite/btcwallet v0.16.10-0.20240912233857-ffb143c77cc5 h1:zYy233eUBvkF3lq2MUkybEhxhDsrRDSgiToIKN57mtk=
41 | github.com/btcsuite/btcwallet v0.16.10-0.20240912233857-ffb143c77cc5/go.mod h1:1HJXYbjJzgumlnxOC2+ViR1U+gnHWoOn7WeK5OfY1eU=
42 | github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk=
43 | github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU=
44 | github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk=
45 | github.com/btcsuite/btcwallet/wallet/txrules v1.2.2/go.mod h1:4v+grppsDpVn91SJv+mZT7B8hEV4nSmpREM4I8Uohws=
46 | github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5 h1:93o5Xz9dYepBP4RMFUc9RGIFXwqP2volSWRkYJFrNtI=
47 | github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5/go.mod h1:lQ+e9HxZ85QP7r3kdxItkiMSloSLg1PEGis5o5CXUQw=
48 | github.com/btcsuite/btcwallet/walletdb v1.4.4 h1:BDel6iT/ltYSIYKs0YbjwnEDi7xR3yzABIsQxN2F1L8=
49 | github.com/btcsuite/btcwallet/walletdb v1.4.4/go.mod h1:jk/hvpLFINF0C1kfTn0bfx2GbnFT+Nvnj6eblZALfjs=
50 | github.com/btcsuite/btcwallet/wtxmgr v1.5.4 h1:hJjHy1h/dJwSfD9uDsCwcH21D1iOrus6OrI5gR9E/O0=
51 | github.com/btcsuite/btcwallet/wtxmgr v1.5.4/go.mod h1:lAv0b1Vj9Ig5U8QFm0yiJ9WqPl8yGO/6l7JxdHY1PKE=
52 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
53 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
54 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
55 | github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
56 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
57 | github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
58 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
59 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
60 | github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
61 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
62 | github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
63 | github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
64 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
65 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
66 | github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
67 | github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
68 | github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
69 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
70 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
71 | github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
72 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
73 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
74 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
75 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
76 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
77 | github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
78 | github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
79 | github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
80 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
81 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
82 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
83 | github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
84 | github.com/decred/dcrd/lru v1.1.3 h1:w9EAbvGLyzm6jTjF83UKuqZEiUtJmvRhQDOCEIvSuE0=
85 | github.com/decred/dcrd/lru v1.1.3/go.mod h1:Tw0i0pJyiLEx/oZdHLe1Wdv/Y7EGzAX+sYftnmxBR4o=
86 | github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
87 | github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
88 | github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
89 | github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
90 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
91 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
92 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
93 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
94 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
95 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
96 | github.com/fergusstrange/embedded-postgres v1.25.0 h1:sa+k2Ycrtz40eCRPOzI7Ry7TtkWXXJ+YRsxpKMDhxK0=
97 | github.com/fergusstrange/embedded-postgres v1.25.0/go.mod h1:t/MLs0h9ukYM6FSt99R7InCHs1nW0ordoVCcnzmpTYw=
98 | github.com/fiatjaf/lightningd-gjson-rpc v1.6.4-0.20241113234716-c08cd810b4d5 h1:RBQU9PWeOjdEvhQOoNMPu1vaBgfC9s0OtWwuiAwxxKc=
99 | github.com/fiatjaf/lightningd-gjson-rpc v1.6.4-0.20241113234716-c08cd810b4d5/go.mod h1:hTjcNL4j59yWMpMgULx3U0tAdLlHeki0lhppJHXfdk4=
100 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
101 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
102 | github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
103 | github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
104 | github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
105 | github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
106 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
107 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
108 | github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
109 | github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
110 | github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU=
111 | github.com/golang-migrate/migrate/v4 v4.17.0/go.mod h1:+Cp2mtLP4/aXDTKb9wmXYitdrNx2HGs45rbWAo6OsKM=
112 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
113 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
114 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
115 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
116 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
117 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
118 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
119 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
120 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
121 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
122 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
123 | github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
124 | github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
125 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
126 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
127 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
128 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
129 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
130 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
131 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
132 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
133 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
134 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
135 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
136 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
137 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
138 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
139 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
140 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
141 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
142 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
143 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
144 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
145 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
146 | github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
147 | github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
148 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
149 | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
150 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
151 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
152 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
153 | github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
154 | github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
155 | github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 h1:Dj0L5fhJ9F82ZJyVOmBx6msDp/kfd1t9GRfny/mfJA0=
156 | github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
157 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
158 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
159 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
160 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
161 | github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
162 | github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
163 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
164 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
165 | github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
166 | github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
167 | github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
168 | github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
169 | github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
170 | github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
171 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
172 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
173 | github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
174 | github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
175 | github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
176 | github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
177 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
178 | github.com/jrick/logrotate v1.1.2 h1:6ePk462NCX7TfKtNp5JJ7MbA2YIslkpfgP03TlTYMN0=
179 | github.com/jrick/logrotate v1.1.2/go.mod h1:f9tdWggSVK3iqavGpyvegq5IhNois7KXmasU6/N96OQ=
180 | github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
181 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
182 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
183 | github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8=
184 | github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA=
185 | github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
186 | github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
187 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
188 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
189 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
190 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
191 | github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
192 | github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
193 | github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
194 | github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
195 | github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s=
196 | github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
197 | github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
198 | github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo=
199 | github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
200 | github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
201 | github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20241111141603-4f6b510869ab h1:OYyJ+qU6RW4GpEbZYadaZfRBPoau+UcT8ZQ8iIunwD4=
202 | github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20241111141603-4f6b510869ab/go.mod h1:okaET/wXsb/RMUZi/mG8pV2oSC0g8YtmVZo1cb7JMwI=
203 | github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
204 | github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ=
205 | github.com/lightningnetwork/lnd/fn v1.2.5 h1:pGMz0BDUxrhvOtShD4FIysdVy+ulfFAnFvTKjZO5Pp8=
206 | github.com/lightningnetwork/lnd/fn v1.2.5/go.mod h1:SyFohpVrARPKH3XVAJZlXdVe+IwMYc4OMAvrDY32kw0=
207 | github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI=
208 | github.com/lightningnetwork/lnd/healthcheck v1.2.6/go.mod h1:Mu02um4CWY/zdTOvFje7WJgJcHyX2zq/FG3MhOAiGaQ=
209 | github.com/lightningnetwork/lnd/kvdb v1.4.11 h1:fk1HMVFrsVK3xqU7q+JWHRgBltw/a2qIg1E3zazMb/8=
210 | github.com/lightningnetwork/lnd/kvdb v1.4.11/go.mod h1:a5cMDKMjbJA8dD06ZqqnYkmSh5DhEbbG8C1YHM3NN+k=
211 | github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
212 | github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
213 | github.com/lightningnetwork/lnd/sqldb v1.0.5 h1:ax5vBPf44tN/uD6C5+hBPBjOJ7cRMrUL+sVOdzmLVt4=
214 | github.com/lightningnetwork/lnd/sqldb v1.0.5/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4=
215 | github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
216 | github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
217 | github.com/lightningnetwork/lnd/tlv v1.2.7 h1:Lko3qFw7i1laTbx0byO64AuehkscXbXPRrdfQ1UzRX8=
218 | github.com/lightningnetwork/lnd/tlv v1.2.7/go.mod h1:/CmY4VbItpOldksocmGT4lxiJqRP9oLxwSZOda2kzNQ=
219 | github.com/lightningnetwork/lnd/tor v1.1.4 h1:TUW27EXqoZCcCAQPlD4aaDfh8jMbBS9CghNz50qqwtA=
220 | github.com/lightningnetwork/lnd/tor v1.1.4/go.mod h1:qSRB8llhAK+a6kaTPWOLLXSZc6Hg8ZC0mq1sUQ/8JfI=
221 | github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
222 | github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
223 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
224 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
225 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
226 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
227 | github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
228 | github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
229 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
230 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
231 | github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
232 | github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
233 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
234 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
235 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
236 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
237 | github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
238 | github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
239 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
240 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
241 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
242 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
243 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
244 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
245 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
246 | github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
247 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
248 | github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
249 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
250 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
251 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
252 | github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
253 | github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
254 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
255 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
256 | github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
257 | github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
258 | github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
259 | github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
260 | github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
261 | github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
262 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
263 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
264 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
265 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
266 | github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
267 | github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
268 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
269 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
270 | github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
271 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
272 | github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
273 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
274 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
275 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
276 | github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
277 | github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
278 | github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
279 | github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
280 | github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
281 | github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
282 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
283 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
284 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
285 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
286 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
287 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
288 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
289 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
290 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
291 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
292 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
293 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
294 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
295 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
296 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
297 | github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
298 | github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
299 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
300 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
301 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
302 | github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
303 | github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
304 | github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
305 | github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
306 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
307 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
308 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
309 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
310 | github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
311 | github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
312 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
313 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
314 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
315 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
316 | go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
317 | go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
318 | go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY=
319 | go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA=
320 | go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg=
321 | go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY=
322 | go.etcd.io/etcd/client/v2 v2.305.7 h1:AELPkjNR3/igjbO7CjyF1fPuVPjrblliiKj+Y6xSGOU=
323 | go.etcd.io/etcd/client/v2 v2.305.7/go.mod h1:GQGT5Z3TBuAQGvgPfhR7VPySu/SudxmEkRq9BgzFU6s=
324 | go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4=
325 | go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw=
326 | go.etcd.io/etcd/pkg/v3 v3.5.7 h1:obOzeVwerFwZ9trMWapU/VjDcYUJb5OfgC1zqEGWO/0=
327 | go.etcd.io/etcd/pkg/v3 v3.5.7/go.mod h1:kcOfWt3Ov9zgYdOiJ/o1Y9zFfLhQjylTgL4Lru8opRo=
328 | go.etcd.io/etcd/raft/v3 v3.5.7 h1:aN79qxLmV3SvIq84aNTliYGmjwsW6NqJSnqmI1HLJKc=
329 | go.etcd.io/etcd/raft/v3 v3.5.7/go.mod h1:TflkAb/8Uy6JFBxcRaH2Fr6Slm9mCPVdI2efzxY96yU=
330 | go.etcd.io/etcd/server/v3 v3.5.7 h1:BTBD8IJUV7YFgsczZMHhMTS67XuA4KpRquL0MFOJGRk=
331 | go.etcd.io/etcd/server/v3 v3.5.7/go.mod h1:gxBgT84issUVBRpZ3XkW1T55NjOb4vZZRI4wVvNhf4A=
332 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
333 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
334 | go.opentelemetry.io/otel v1.0.1 h1:4XKyXmfqJLOQ7feyV5DB6gsBFZ0ltB8vLtp6pj4JIcc=
335 | go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
336 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1 h1:ofMbch7i29qIUf7VtF+r0HRF6ac0SBaPSziSsKp7wkk=
337 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
338 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1 h1:CFMFNoz+CGprjFAFy+RJFrfEe4GBia3RRm2a4fREvCA=
339 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
340 | go.opentelemetry.io/otel/sdk v1.0.1 h1:wXxFEWGo7XfXupPwVJvTBOaPBC9FEg0wB8hMNrKk+cA=
341 | go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
342 | go.opentelemetry.io/otel/trace v1.0.1 h1:StTeIH6Q3G4r0Fiw34LTokUFESZgIDUr0qIJ7mKmAfw=
343 | go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
344 | go.opentelemetry.io/proto/otlp v0.9.0 h1:C0g6TWmQYvjKRnljRULLWUVJGy8Uvu0NEL/5frY2/t4=
345 | go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
346 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
347 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
348 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
349 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
350 | go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
351 | go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
352 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
353 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
354 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
355 | golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
356 | golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
357 | golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
358 | golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
359 | golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
360 | golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
361 | golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
362 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
363 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
364 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
365 | golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
366 | golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
367 | golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
368 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
369 | golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
370 | golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
371 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
372 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
373 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
374 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
375 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
376 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
377 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
378 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
379 | golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
380 | golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
381 | golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
382 | golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
383 | golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
384 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
385 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
386 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
387 | golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
388 | golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
389 | golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
390 | golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
391 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
392 | golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
393 | golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
394 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
395 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
396 | google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
397 | google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
398 | google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
399 | google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
400 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik=
401 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
402 | google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
403 | google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
404 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
405 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
406 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
407 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
408 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
409 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
410 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
411 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
412 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
413 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
414 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
415 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
416 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
417 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
418 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
419 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
420 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
421 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
422 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
423 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
424 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
425 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
426 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
427 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
428 | modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
429 | modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
430 | modernc.org/libc v1.49.3 h1:j2MRCRdwJI2ls/sGbeSk0t2bypOG/uvPZUsGQFDulqg=
431 | modernc.org/libc v1.49.3/go.mod h1:yMZuGkn7pXbKfoT/M35gFJOAEdSKdxL0q64sF7KqCDo=
432 | modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
433 | modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
434 | modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
435 | modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
436 | modernc.org/sqlite v1.29.10 h1:3u93dz83myFnMilBGCOLbr+HjklS6+5rJLx4q86RDAg=
437 | modernc.org/sqlite v1.29.10/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
438 | modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
439 | modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
440 | modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
441 | modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
442 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
443 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
444 |
--------------------------------------------------------------------------------
/integration_test.py:
--------------------------------------------------------------------------------
1 | from pyln.client import RpcError
2 | from pyln.testing.fixtures import *
3 |
4 | def test_bcli(node_factory, bitcoind, chainparams):
5 | """
6 | Based on the test_bcli from Core Lightning
7 | """
8 | node = node_factory.get_node(opts={
9 | "disable-plugin": "bcli",
10 | "plugin": os.path.join(os.getcwd(), 'trustedcoin'),
11 | })
12 |
13 | # We cant stop it dynamically
14 | with pytest.raises(RpcError):
15 | node.rpc.plugin_stop("bcli")
16 |
17 | # Failure case of feerate is tested in test_misc.py
18 | estimates = node.rpc.call("estimatefees")
19 | assert 'feerate_floor' in estimates
20 | assert [f['blocks'] for f in estimates['feerates']] == [2, 6, 12, 100]
21 |
22 | resp = node.rpc.call("getchaininfo", {"last_height": 0})
23 | assert resp["chain"] == chainparams['name']
24 | for field in ["headercount", "blockcount", "ibd"]:
25 | assert field in resp
26 |
27 | # We shouldn't get upset if we ask for an unknown-yet block
28 | resp = node.rpc.call("getrawblockbyheight", {"height": 500})
29 | assert resp["blockhash"] is resp["block"] is None
30 | resp = node.rpc.call("getrawblockbyheight", {"height": 50})
31 | assert resp["blockhash"] is not None and resp["blockhash"] is not None
32 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 |
7 | "github.com/btcsuite/btcd/rpcclient"
8 | "github.com/fiatjaf/lightningd-gjson-rpc/plugin"
9 | )
10 |
11 | const version = "0.8.5"
12 |
13 | var (
14 | network string
15 | esplora = map[string][]string{
16 | "bitcoin": {
17 | "https://mempool.space/api",
18 | "https://blockstream.info/api",
19 | "https://mempool.emzy.de/api",
20 | },
21 | "testnet": {
22 | "https://mempool.space/testnet/api",
23 | "https://blockstream.info/testnet/api",
24 | },
25 | "signet": {
26 | "https://mempool.space/signet/api",
27 | },
28 | "liquid": {
29 | "https://liquid.network/api",
30 | "https://blockstream.info/liquid/api",
31 | },
32 | }
33 | defaultBitcoindRPCPorts = map[string]string{
34 | "bitcoin": "8332",
35 | "testnet": "18332",
36 | "signet": "38332",
37 | "regtest": "18443",
38 | }
39 | bitcoind *rpcclient.Client
40 | )
41 |
42 | func esploras(network string) (ss []string) {
43 | ss = make([]string, len(esplora[network]))
44 | copy(ss, esplora[network])
45 |
46 | rand.Shuffle(len(ss), func(i, j int) {
47 | ss[i], ss[j] = ss[j], ss[i]
48 | })
49 |
50 | return ss
51 | }
52 |
53 | func main() {
54 | p := plugin.Plugin{
55 | Name: "trustedcoin",
56 | Version: version,
57 | Options: []plugin.Option{
58 | {Name: "bitcoin-rpcconnect", Type: "string", Description: "Hostname (IP) to bitcoind RPC (optional).", Default: ""},
59 | {Name: "bitcoin-rpcport", Type: "string", Description: "Port to bitcoind RPC (optional).", Default: ""},
60 | {Name: "bitcoin-rpcuser", Type: "string", Description: "Username to bitcoind RPC (optional).", Default: ""},
61 | {Name: "bitcoin-rpcpassword", Type: "string", Description: "Password to bitcoind RPC (optional).", Default: ""},
62 | {Name: "bitcoin-datadir", Type: "string", Description: "-datadir arg for bitcoin-cli. For compatibility with bcli, not actually used.", Default: ""},
63 | },
64 | RPCMethods: []plugin.RPCMethod{
65 | {
66 | Name: "getrawblockbyheight",
67 | Usage: "height",
68 | Description: "Get the bitcoin block at a given height",
69 | LongDescription: "",
70 | Handler: func(p *plugin.Plugin, params plugin.Params) (resp any, errCode int, err error) {
71 | height := params.Get("height").Int()
72 |
73 | blockUnavailable := map[string]any{
74 | "blockhash": nil,
75 | "block": nil,
76 | }
77 |
78 | block, hash, err := getBlock(height)
79 | if err != nil {
80 | p.Logf("getblock error: %s", err.Error())
81 | return blockUnavailable, 0, nil
82 | }
83 | if block == "" {
84 | return blockUnavailable, 0, nil
85 | }
86 |
87 | p.Logf("returning block %d, %s…, %d bytes",
88 | height, string(hash[:26]), len(block)/2)
89 |
90 | return struct {
91 | BlockHash string `json:"blockhash"`
92 | Block string `json:"block"`
93 | }{hash, string(block)}, 0, nil
94 | },
95 | }, {
96 | Name: "getchaininfo",
97 | Usage: "",
98 | Description: "Get the chain id, the header count, the block count and whether this is IBD.",
99 | LongDescription: "",
100 | Handler: func(p *plugin.Plugin, params plugin.Params) (resp any, errCode int, err error) {
101 | tip, err := getTip()
102 | if err != nil {
103 | return nil, 20, fmt.Errorf("failed to get tip: %s", err.Error())
104 | }
105 |
106 | p.Logf("tip: %d", tip)
107 |
108 | var bip70network string
109 | switch network {
110 | case "bitcoin":
111 | bip70network = "main"
112 | case "testnet":
113 | bip70network = "test"
114 | case "signet":
115 | bip70network = "signet"
116 | case "regtest":
117 | bip70network = "regtest"
118 | case "liquid":
119 | bip70network = "liquidv1"
120 | }
121 |
122 | return struct {
123 | Chain string `json:"chain"`
124 | HeaderCount int64 `json:"headercount"`
125 | BlockCount int64 `json:"blockcount"`
126 | IBD bool `json:"ibd"`
127 | }{bip70network, tip, tip, false}, 0, nil
128 | },
129 | }, {
130 | Name: "estimatefees",
131 | Usage: "",
132 | Description: "Get the Bitcoin feerate in sat/kilo-vbyte.",
133 | LongDescription: "",
134 | Handler: func(p *plugin.Plugin, params plugin.Params) (resp any, errCode int, err error) {
135 | estfees, err := getFeeRates(p.Network)
136 | if err != nil {
137 | p.Logf("estimatefees error: %s", err.Error())
138 | estfees = &EstimatedFees{}
139 | }
140 |
141 | return *estfees, 0, nil
142 | },
143 | }, {
144 | Name: "sendrawtransaction",
145 | Usage: "tx",
146 | Description: "Send a raw transaction to the Bitcoin network.",
147 | LongDescription: "",
148 | Handler: func(p *plugin.Plugin, params plugin.Params) (resp any, errCode int, err error) {
149 | hex := params.Get("tx").String()
150 |
151 | return sendRawTransaction(hex), 0, nil
152 | },
153 | }, {
154 | Name: "getutxout",
155 | Usage: "txid vout",
156 | Description: "Get informations about an output, identified by a {txid} an a {vout}",
157 | LongDescription: "",
158 | Handler: func(p *plugin.Plugin, params plugin.Params) (resp any, errCode int, err error) {
159 | txid := params.Get("txid").String()
160 | vout := params.Get("vout").Int()
161 |
162 | tx, err := getTransaction(txid)
163 | if err != nil {
164 | p.Logf("failed to get tx %s: %s", txid, err.Error())
165 | return UTXOResponse{nil, nil}, 0, nil
166 | }
167 | output := tx.Vout[vout]
168 | return UTXOResponse{&output.Value, &output.ScriptPubKey}, 0, nil
169 | },
170 | },
171 | },
172 | OnInit: func(p *plugin.Plugin) {
173 | network = p.Network
174 |
175 | // we will try to use a local bitcoind
176 | user := p.Args.Get("bitcoin-rpcuser").String()
177 | pass := p.Args.Get("bitcoin-rpcpassword").String()
178 | if user != "" && pass != "" {
179 | hostname := p.Args.Get("bitcoin-rpcconnect").String()
180 | if hostname == "" {
181 | hostname = "127.0.0.1"
182 | }
183 | port := p.Args.Get("bitcoin-rpcport").String()
184 | if port == "" {
185 | port = defaultBitcoindRPCPorts[network]
186 | if port == "" {
187 | port = "8332"
188 | }
189 | }
190 |
191 | p.Logf("bitcoind RPC settings: {user: %s, password: %s, connect: %s, port: %s}", user, pass, hostname, port)
192 |
193 | client, err := rpcclient.New(&rpcclient.ConnConfig{
194 | Host: hostname + ":" + port,
195 | User: user,
196 | Pass: pass,
197 | HTTPPostMode: true,
198 | DisableTLS: true,
199 | }, nil)
200 | if err != nil {
201 | p.Logf("bitcoind RPC backend settings detected but invalid (%s), will only use block explorers.", err)
202 | return
203 | }
204 |
205 | bitcoind = client
206 | if _, err := bitcoind.GetBlockChainInfo(); err == nil {
207 | p.Log("bitcoind RPC working, will use that with highest priority and fall back to block explorers if it fails.")
208 | } else {
209 | p.Log("bitcoind RPC backend settings detected, but failed to connect (%s), will keep trying to use it though.", err)
210 | }
211 | return
212 | }
213 |
214 | p.Log("bitcoind RPC settings not detected (looked for 'bitcoin-rpcuser', 'bitcoin-rpcpassword' and optionally 'bitcoin-rpcconnect' and 'bitcoin-rpcport'), will only use block explorers.")
215 | },
216 | }
217 |
218 | p.Run()
219 | }
220 |
--------------------------------------------------------------------------------
/main_test.go:
--------------------------------------------------------------------------------
1 | package main_test
2 |
3 | import (
4 | "bufio"
5 | "io"
6 | "os/exec"
7 | "strings"
8 | "testing"
9 | )
10 |
11 | const executable = "./trustedcoin"
12 |
13 | const getManifestRequest = `{"jsonrpc":"2.0","id":"getmanifest","method":"getmanifest","params":{}}`
14 | const getManifestExpectedResponse = `{"jsonrpc":"2.0","id":"getmanifest","result":{"options":[{"name":"bitcoin-rpcconnect","type":"string","default":"","description":"Hostname (IP) to bitcoind RPC (optional)."},{"name":"bitcoin-rpcport","type":"string","default":"","description":"Port to bitcoind RPC (optional)."},{"name":"bitcoin-rpcuser","type":"string","default":"","description":"Username to bitcoind RPC (optional)."},{"name":"bitcoin-rpcpassword","type":"string","default":"","description":"Password to bitcoind RPC (optional)."},{"name":"bitcoin-datadir","type":"string","default":"","description":"-datadir arg for bitcoin-cli. For compatibility with bcli, not actually used."}],"rpcmethods":[{"name":"getrawblockbyheight","usage":"height","description":"Get the bitcoin block at a given height","long_description":""},{"name":"getchaininfo","usage":"","description":"Get the chain id, the header count, the block count and whether this is IBD.","long_description":""},{"name":"estimatefees","usage":"","description":"Get the Bitcoin feerate in sat/kilo-vbyte.","long_description":""},{"name":"sendrawtransaction","usage":"tx","description":"Send a raw transaction to the Bitcoin network.","long_description":""},{"name":"getutxout","usage":"txid vout","description":"Get informations about an output, identified by a {txid} an a {vout}","long_description":""}],"subscriptions":[],"hooks":[],"featurebits":{"features":"","channel":"","init":"","invoice":""},"dynamic":false,"notifications":[]}}`
15 |
16 | const initRequest = `{"jsonrpc":"2.0","id":"init","method":"init","params":{"options":{},"configuration":{"network":"bitcoin","lightning-dir":"/tmp","rpc-file":"foo"}}}`
17 | const initExpectedResponse = `{"jsonrpc":"2.0","id":"init"}`
18 |
19 | const shutdownNotification = `{"jsonrpc":"2.0","method":"shutdown","params":{}}`
20 |
21 | func TestInitAndShutdown(t *testing.T) {
22 | cmd, stdin, stdout, stderr := start(t)
23 | stop(t, cmd, stdin, stdout, stderr)
24 | }
25 |
26 | func start(t *testing.T) (*exec.Cmd, io.WriteCloser, io.ReadCloser, io.ReadCloser) {
27 | cmd := exec.Command(executable)
28 | stdin, _ := cmd.StdinPipe()
29 | stdout, _ := cmd.StdoutPipe()
30 | stderr, _ := cmd.StderrPipe()
31 |
32 | err := cmd.Start()
33 | if err != nil {
34 | t.Fatalf("expected trustedcoin to start, got %v", err)
35 | }
36 |
37 | _, _ = io.WriteString(stdin, getManifestRequest)
38 | if response := readline(stdout); response != getManifestExpectedResponse {
39 | t.Fatalf("unexpected manifest response: %s", response)
40 | }
41 |
42 | _, _ = io.WriteString(stdin, initRequest)
43 | if response := readline(stdout); response != initExpectedResponse {
44 | t.Fatalf("unexpected init response: %s", response)
45 | }
46 |
47 | if response := readline(stderr); !strings.Contains(response, "initialized plugin") {
48 | t.Fatalf("unexpected output in stderr: %s", response)
49 | }
50 |
51 | return cmd, stdin, stdout, stderr
52 | }
53 |
54 | func stop(t *testing.T, cmd *exec.Cmd, stdin io.WriteCloser, stdout, stderr io.ReadCloser) {
55 | _, _ = io.WriteString(stdin, shutdownNotification)
56 | _ = stdin.Close()
57 | _ = stdout.Close()
58 | _ = stderr.Close()
59 |
60 | if err := cmd.Wait(); err != nil {
61 | t.Fatalf("expected process to exit cleanly, got %v", err)
62 | }
63 | }
64 |
65 | func readline(r io.Reader) string {
66 | line, _ := bufio.NewReader(r).ReadString('\n')
67 |
68 | return strings.TrimSuffix(line, "\n")
69 | }
70 |
--------------------------------------------------------------------------------
/requirements.in:
--------------------------------------------------------------------------------
1 | # To run the integration tests you need to create a Python virtualenv and install pyln.testing:
2 | # $ python -m venv venv
3 | # $ source venv/bin/activate
4 | # $ pip install pip-tools
5 | # $ pip-compile --strip-extras
6 | # $ pip-sync
7 |
8 | pyln.testing==24.8.2
9 |
--------------------------------------------------------------------------------
/sendtransaction.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "encoding/hex"
6 | "io"
7 | "net/http"
8 |
9 | "github.com/btcsuite/btcd/wire"
10 | )
11 |
12 | type RawTransactionResponse struct {
13 | Success bool `json:"success"`
14 | ErrMsg string `json:"errmsg"`
15 | }
16 |
17 | func sendRawTransaction(txHex string) (resp RawTransactionResponse) {
18 | // try bitcoind first
19 | if bitcoind != nil {
20 | tx := &wire.MsgTx{}
21 | if txBytes, err := hex.DecodeString(txHex); err == nil {
22 | txBuf := bytes.NewBuffer(txBytes)
23 | if err := tx.BtcDecode(txBuf, wire.ProtocolVersion, wire.WitnessEncoding); err == nil {
24 | if _, err := bitcoind.SendRawTransaction(tx, true); err == nil {
25 | return RawTransactionResponse{true, ""}
26 | }
27 | }
28 | }
29 | }
30 |
31 | // then try explorers
32 | tx := bytes.NewBufferString(txHex)
33 | for _, endpoint := range esploras(network) {
34 | w, err := http.Post(endpoint+"/tx", "text/plain", tx)
35 | if err != nil {
36 | resp = RawTransactionResponse{false, err.Error()}
37 | continue
38 | }
39 | defer w.Body.Close()
40 |
41 | if w.StatusCode >= 300 {
42 | msg, _ := io.ReadAll(w.Body)
43 | resp = RawTransactionResponse{false, string(msg)}
44 | err = nil
45 | continue
46 | }
47 |
48 | return RawTransactionResponse{true, ""}
49 | }
50 |
51 | return resp
52 | }
53 |
--------------------------------------------------------------------------------