├── .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 | [![continuous integration](https://github.com/nbd-wtf/trustedcoin/actions/workflows/test.yml/badge.svg)](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 | --------------------------------------------------------------------------------