lnwallet/btcwallet: update BlockChainIO implementation to be backend aware
This commit is contained in:
parent
aca729abfe
commit
0e8af209bd
@ -3,10 +3,17 @@ package btcwallet
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
|
||||||
|
"github.com/lightninglabs/neutrino"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
"github.com/roasbeef/btcwallet/chain"
|
||||||
|
"github.com/roasbeef/btcwallet/waddrmgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -20,56 +27,98 @@ var (
|
|||||||
//
|
//
|
||||||
// This method is a part of the lnwallet.BlockChainIO interface.
|
// This method is a part of the lnwallet.BlockChainIO interface.
|
||||||
func (b *BtcWallet) GetBestBlock() (*chainhash.Hash, int32, error) {
|
func (b *BtcWallet) GetBestBlock() (*chainhash.Hash, int32, error) {
|
||||||
return b.rpc.GetBestBlock()
|
switch backend := b.chain.(type) {
|
||||||
|
|
||||||
|
case *chain.SPVChain:
|
||||||
|
header, height, err := backend.CS.LatestBlock()
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blockHash := header.BlockHash()
|
||||||
|
return &blockHash, int32(height), nil
|
||||||
|
|
||||||
|
case *chain.RPCClient:
|
||||||
|
return backend.GetBestBlock()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, -1, fmt.Errorf("unknown backend")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUtxo returns the original output referenced by the passed outpoint.
|
// GetUtxo returns the original output referenced by the passed outpoint.
|
||||||
//
|
//
|
||||||
// This method is a part of the lnwallet.BlockChainIO interface.
|
// This method is a part of the lnwallet.BlockChainIO interface.
|
||||||
func (b *BtcWallet) GetUtxo(op *wire.OutPoint, _ uint32) (*wire.TxOut, error) {
|
func (b *BtcWallet) GetUtxo(op *wire.OutPoint, heightHint uint32) (*wire.TxOut, error) {
|
||||||
txout, err := b.rpc.GetTxOut(&op.Hash, op.Index, false)
|
switch backend := b.chain.(type) {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
case *chain.SPVChain:
|
||||||
} else if txout == nil {
|
spendReport, err := backend.CS.GetUtxo(
|
||||||
return nil, ErrOutputSpent
|
neutrino.WatchOutPoints(*op),
|
||||||
|
neutrino.StartBlock(&waddrmgr.BlockStamp{
|
||||||
|
Height: int32(heightHint),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if spendReport != nil && spendReport.SpendingTx != nil {
|
||||||
|
return nil, ErrOutputSpent
|
||||||
|
}
|
||||||
|
|
||||||
|
return spendReport.Output, nil
|
||||||
|
|
||||||
|
case *chain.RPCClient:
|
||||||
|
txout, err := backend.GetTxOut(&op.Hash, op.Index, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if txout == nil {
|
||||||
|
return nil, ErrOutputSpent
|
||||||
|
}
|
||||||
|
|
||||||
|
pkScript, err := hex.DecodeString(txout.ScriptPubKey.Hex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wire.TxOut{
|
||||||
|
// Sadly, gettxout returns the output value in BTC
|
||||||
|
// instead of satoshis.
|
||||||
|
Value: int64(txout.Value * 1e8),
|
||||||
|
PkScript: pkScript,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown backend")
|
||||||
}
|
}
|
||||||
|
|
||||||
pkScript, err := hex.DecodeString(txout.ScriptPubKey.Hex)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &wire.TxOut{
|
|
||||||
// Sadly, gettxout returns the output value in BTC
|
|
||||||
// instead of satoshis.
|
|
||||||
Value: int64(txout.Value * 1e8),
|
|
||||||
PkScript: pkScript,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTransaction returns the full transaction identified by the passed
|
|
||||||
// transaction ID.
|
|
||||||
//
|
|
||||||
// This method is a part of the lnwallet.BlockChainIO interface.
|
|
||||||
func (b *BtcWallet) GetTransaction(txid *chainhash.Hash) (*wire.MsgTx, error) {
|
|
||||||
tx, err := b.rpc.GetRawTransaction(txid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tx.MsgTx(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock returns a raw block from the server given its hash.
|
// GetBlock returns a raw block from the server given its hash.
|
||||||
//
|
//
|
||||||
// This method is a part of the lnwallet.BlockChainIO interface.
|
// This method is a part of the lnwallet.BlockChainIO interface.
|
||||||
func (b *BtcWallet) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error) {
|
func (b *BtcWallet) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error) {
|
||||||
block, err := b.rpc.GetBlock(blockHash)
|
switch backend := b.chain.(type) {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return block, nil
|
case *chain.SPVChain:
|
||||||
|
block, err := backend.CS.GetBlockFromNetwork(*blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return block.MsgBlock(), nil
|
||||||
|
|
||||||
|
case *chain.RPCClient:
|
||||||
|
block, err := backend.GetBlock(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return block, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown backend")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockHash returns the hash of the block in the best blockchain at the
|
// GetBlockHash returns the hash of the block in the best blockchain at the
|
||||||
@ -77,12 +126,28 @@ func (b *BtcWallet) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error)
|
|||||||
//
|
//
|
||||||
// This method is a part of the lnwallet.BlockChainIO interface.
|
// This method is a part of the lnwallet.BlockChainIO interface.
|
||||||
func (b *BtcWallet) GetBlockHash(blockHeight int64) (*chainhash.Hash, error) {
|
func (b *BtcWallet) GetBlockHash(blockHeight int64) (*chainhash.Hash, error) {
|
||||||
blockHash, err := b.rpc.GetBlockHash(blockHeight)
|
switch backend := b.chain.(type) {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return blockHash, nil
|
case *chain.SPVChain:
|
||||||
|
blockHeader, err := backend.CS.GetBlockByHeight(uint32(blockHeight))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blockHash := blockHeader.BlockHash()
|
||||||
|
return &blockHash, nil
|
||||||
|
|
||||||
|
case *chain.RPCClient:
|
||||||
|
blockHash, err := backend.GetBlockHash(blockHeight)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockHash, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown backend")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compile time check to ensure that BtcWallet implements the BlockChainIO
|
// A compile time check to ensure that BtcWallet implements the BlockChainIO
|
||||||
|
@ -614,11 +614,30 @@ func (b *BtcWallet) IsSynced() (bool, error) {
|
|||||||
// Grab the best chain state the wallet is currently aware of.
|
// Grab the best chain state the wallet is currently aware of.
|
||||||
syncState := b.wallet.Manager.SyncedTo()
|
syncState := b.wallet.Manager.SyncedTo()
|
||||||
|
|
||||||
// Next, query the btcd node to grab the info about the tip of the main
|
var (
|
||||||
// chain.
|
bestHash *chainhash.Hash
|
||||||
bestHash, bestHeight, err := b.rpc.GetBestBlock()
|
bestHeight int32
|
||||||
if err != nil {
|
err error
|
||||||
return false, err
|
)
|
||||||
|
|
||||||
|
// Next, query the chain backend to grab the info about the tip of the
|
||||||
|
// main chain.
|
||||||
|
switch backend := b.cfg.ChainSource.(type) {
|
||||||
|
case *chain.SPVChain:
|
||||||
|
header, height, err := backend.CS.LatestBlock()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bh := header.BlockHash()
|
||||||
|
bestHash = &bh
|
||||||
|
bestHeight = int32(height)
|
||||||
|
|
||||||
|
case *chain.RPCClient:
|
||||||
|
bestHash, bestHeight, err = backend.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the wallet hasn't yet fully synced to the node's best chain tip,
|
// If the wallet hasn't yet fully synced to the node's best chain tip,
|
||||||
@ -628,12 +647,24 @@ func (b *BtcWallet) IsSynced() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the wallet is on par with the current best chain tip, then we
|
// If the wallet is on par with the current best chain tip, then we
|
||||||
// still may not yet be synced as the btcd node may still be catching
|
// still may not yet be synced as the chain backend may still be
|
||||||
// up to the main chain. So we'll grab the block header in order to
|
// catching up to the main chain. So we'll grab the block header in
|
||||||
// make a guess based on the current time stamp.
|
// order to make a guess based on the current time stamp.
|
||||||
blockHeader, err := b.rpc.GetBlockHeader(bestHash)
|
var blockHeader *wire.BlockHeader
|
||||||
if err != nil {
|
switch backend := b.cfg.ChainSource.(type) {
|
||||||
return false, err
|
|
||||||
|
case *chain.SPVChain:
|
||||||
|
bh, _, err := backend.CS.GetBlockByHash(*bestHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
blockHeader = &bh
|
||||||
|
|
||||||
|
case *chain.RPCClient:
|
||||||
|
blockHeader, err = backend.GetBlockHeader(bestHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the timestamp no the best header is more than 2 hours in the
|
// If the timestamp no the best header is more than 2 hours in the
|
||||||
|
Loading…
Reference in New Issue
Block a user