Skip to content

Commit

Permalink
migrate from the other repo.
Browse files Browse the repository at this point in the history
  • Loading branch information
fiatjaf committed Aug 12, 2020
0 parents commit f8e3023
Show file tree
Hide file tree
Showing 11 changed files with 766 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist/*
trustedcoin
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist: $(shell find . -name "*.go")
mkdir -p dist
gox -ldflags="-s -w" -tags="full" -osarch="darwin/amd64 linux/386 linux/amd64 linux/arm freebsd/amd64" -output="dist/trustedcoin_{{.OS}}_{{.Arch}}"
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## The `trustedcoin` plugin

A plugin that uses block explorers (blockstream.info, mempool.space, blockchair.com and blockchain.info) as backends instead of your own Bitcoin node.

This isn't what you should be doing, but sometimes you may need it.

(Remember this will download all blocks c-lightning needs from blockchain.info or blockchair.com in raw, hex format.)

## How to install

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).

[Download it](https://github.com/fiatjaf/trustedcoin/releases), call `chmod +x <binary>` and put it in `~/.lightning/plugins` (create that directory if it doesn't exist).

You only need the binary you can get in [the releases page](https://github.com/fiatjaf/trustedcoin/releases), nothing else.

Then add the following line to your `~/.lightning/config` file:

```
disable-plugin=bcli
```

This disables the default Bitcoin backend plugin so `trustedcoin` can take its place.

### Extra: how to bootstrap a Lightning node from scratch, without Bitcoin Core, on Ubuntu amd64

```
add-apt-repository ppa:lightningnetwork/ppa
apt update
apt install lightningd
mkdir -p ~/.lightning/plugins
echo 'disable-plugin=bcli' >> .lightning/config
cd ~/.lightning/plugins
wget https://github.com/fiatjaf/lightningd-gjson-rpc/releases/download/trustedcoin-v0.2.4/trustedcoin_linux_amd64
chmod +x trustedcoin_linux_amd64
cd
lightningd
```

## Built with [![GoDoc](https://godoc.org/github.com/fiatjaf/lightningd-gjson-rpc?status.svg)](https://godoc.org/github.com/fiatjaf/lightningd-gjson-rpc)
40 changes: 40 additions & 0 deletions estimatefees.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"encoding/json"
"errors"
"net/http"
)

type EstimatedFees struct {
Opening *int `json:"opening"`
MutualClose *int `json:"mutual_close"`
UnilateralClose *int `json:"unilateral_close"`
DelayedToUs *int `json:"delayed_to_us"`
HTLCResolution *int `json:"htlc_resolution"`
Penalty *int `json:"penalty"`
MinAcceptable *int `json:"min_acceptable"`
MaxAcceptable *int `json:"max_acceptable"`
}

func getFeeRatesFromEsplora() (feerates map[string]float64, err error) {
for _, endpoint := range esploras() {
w, errW := http.Get(endpoint + "/fee-estimates")
if errW != nil {
err = errW
continue
}
defer w.Body.Close()

if w.StatusCode >= 300 {
err = errors.New(endpoint + " error: " + w.Status)
return
}

err = json.NewDecoder(w.Body).Decode(&feerates)
return
}

err = errors.New("none of the esploras returned usable responses")
return
}
155 changes: 155 additions & 0 deletions getblock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package main

import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"

"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
)

var heightCache = make(map[int64]string)

func getBlock(height int64) (block, hash string, err error) {
hash, err = getHash(height)
if err != nil {
return
}
if hash == "" /* block unavailable */ {
return
}

for _, try := range []func(string) (string, error){
blockFromBlockchainInfo,
blockFromBlockchair,
} {
blockhex, errW := try(hash)
if errW != nil || blockhex == "" {
err = errW
continue
}

// verify and hash
blockbytes, errW := hex.DecodeString(blockhex)
if errW != nil {
err = errW
continue
}

blockparsed, errW := btcutil.NewBlockFromBytes(blockbytes)
if errW != nil {
err = errW
continue
}
header := blockparsed.MsgBlock().Header

blockhash := hex.EncodeToString(reverseHash(blockparsed.Hash()))
if blockhash != hash {
err = fmt.Errorf("fetched block hash %s doesn't match expected %s",
blockhash, hash)
continue
}

prevHash := hex.EncodeToString(header.PrevBlock[:])
if cachedPrevHash, ok := heightCache[height-1]; ok {
if prevHash != cachedPrevHash {
// something is badly wrong with this block
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)
continue
}
}

delete(heightCache, height)
return blockhex, hash, nil
}

return
}

func getHash(height int64) (hash string, err error) {
for _, endpoint := range esploras() {
w, errW := http.Get(fmt.Sprintf(endpoint+"/block-height/%d", height))
if errW != nil {
err = errW
continue
}
defer w.Body.Close()

if w.StatusCode >= 404 {
continue
}

data, errW := ioutil.ReadAll(w.Body)
if errW != nil {
err = errW
continue
}

hash = strings.TrimSpace(string(data))

if len(hash) > 64 {
err = errors.New("got something that isn't a block hash: " + hash[:64])
continue
}

heightCache[height] = hash

return hash, nil
}

return "", err
}

func blockFromBlockchainInfo(hash string) (string, error) {
w, err := http.Get(fmt.Sprintf("https://blockchain.info/block/%s?format=hex", hash))
if err != nil {
return "", fmt.Errorf("failed to get raw block %s from blockchain.info: %s", hash, err.Error())
}
defer w.Body.Close()

block, _ := ioutil.ReadAll(w.Body)
if len(block) < 100 {
// block not available here yet
return "", nil
}

return string(block), nil
}

func blockFromBlockchair(hash string) (string, error) {
w, err := http.Get("https://api.blockchair.com/bitcoin/raw/block/" + hash)
if err != nil {
return "", fmt.Errorf("failed to get raw block %s from blockchair.com: %s", hash, err.Error())
}
defer w.Body.Close()

var data struct {
Data map[string]struct {
RawBlock string `json:"raw_block"`
} `json:"data"`
}
err = json.NewDecoder(w.Body).Decode(&data)
if err != nil {
return "", err
}

if bdata, ok := data.Data[hash]; ok {
return bdata.RawBlock, nil
} else {
// block not available here yet
return "", nil
}
}

func reverseHash(hash *chainhash.Hash) []byte {
r := make([]byte, chainhash.HashSize)
for i, b := range hash {
r[chainhash.HashSize-i-1] = b
}
return r
}
34 changes: 34 additions & 0 deletions gettip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"io/ioutil"
"net/http"
"strconv"
)

func getTip() (tip int64, err error) {
for _, endpoint := range esploras() {
w, errW := http.Get(endpoint + "/blocks/tip/height")
if errW != nil {
err = errW
continue
}
defer w.Body.Close()

data, errW := ioutil.ReadAll(w.Body)
if errW != nil {
err = errW
continue
}

tip, errW = strconv.ParseInt(string(data), 10, 64)
if errW != nil {
err = errW
continue
}

return tip, nil
}

return 0, err
}
38 changes: 38 additions & 0 deletions gettransaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"encoding/json"
"net/http"
)

type UTXOResponse struct {
Amount *int64 `json:"amount"`
Script *string `json:"script"`
}

func getTransaction(txid string) (tx struct {
TXID string `json:"txid"`
Vout []struct {
ScriptPubKey string `json:"scriptPubKey"`
Value int64 `json:"value"`
} `json:"vout"`
}, err error) {
for _, endpoint := range esploras() {
w, errW := http.Get(endpoint + "/tx/" + txid)
if errW != nil {
err = errW
continue
}
defer w.Body.Close()

errW = json.NewDecoder(w.Body).Decode(&tx)
if errW != nil {
err = errW
continue
}

return tx, nil
}

return
}
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/fiatjaf/trustedcoin

go 1.14

require (
github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46
github.com/btcsuite/btcutil v1.0.2
github.com/fiatjaf/lightningd-gjson-rpc v1.0.1
)
Loading

0 comments on commit f8e3023

Please sign in to comment.