86 lines
1.8 KiB
Go
86 lines
1.8 KiB
Go
package verifyer
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"slices"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/wire"
|
|
)
|
|
|
|
// esplora is a client for the Esplora API, which provides access to Bitcoin
|
|
// blockchain data.
|
|
type esplora struct {
|
|
httpClient *http.Client
|
|
baseURL string
|
|
}
|
|
|
|
func NewEsploraClient(url string, timeout time.Duration) Bitcoin {
|
|
url = strings.TrimSuffix(url, "/")
|
|
|
|
h := &http.Client{
|
|
Timeout: timeout,
|
|
}
|
|
|
|
return esplora{h, url}
|
|
}
|
|
|
|
func (e esplora) GetBlockHash(height int64) (*chainhash.Hash, error) {
|
|
resp, err := e.httpClient.Get(e.baseURL + "/block-height/" + strconv.FormatInt(height, 10))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get block hash: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
hexb, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read block hash: %w", err)
|
|
}
|
|
|
|
hash, err := hex.DecodeString(string(hexb))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode block hash: %w", err)
|
|
}
|
|
if len(hash) != chainhash.HashSize {
|
|
return nil, fmt.Errorf("got block hash (%x) of invalid size (expected %d)", hash, chainhash.HashSize)
|
|
}
|
|
|
|
slices.Reverse(hash)
|
|
var chash chainhash.Hash
|
|
copy(chash[:], hash)
|
|
return &chash, nil
|
|
}
|
|
|
|
func (e esplora) GetBlockHeader(hash *chainhash.Hash) (*wire.BlockHeader, error) {
|
|
resp, err := e.httpClient.Get(fmt.Sprintf("%s/block/%s/header", e.baseURL, hash.String()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
hexb, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
headerHash, err := hex.DecodeString(string(hexb))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
header := &wire.BlockHeader{}
|
|
if err := header.BtcDecode(bytes.NewBuffer(headerHash), 0, 0); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return header, nil
|
|
}
|