Skip to content

Commit 8a52e70

Browse files
committed
chain_bridge: fetch block headers over blocks
In this commit, we update the header verifier to use the new GetBlockHeader RPC when supported, and avoid fetching a full block. This improves the reliability of proof validation and universe sync for light clients.
1 parent 268bdff commit 8a52e70

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

chain_bridge.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ import (
99
"github.com/lightninglabs/lndclient"
1010
"github.com/lightninglabs/taproot-assets/tapgarden"
1111
"github.com/lightningnetwork/lnd/chainntnfs"
12+
"github.com/lightningnetwork/lnd/lnrpc/verrpc"
1213
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
1314
)
1415

1516
// LndRpcChainBridge is an implementation of the tapgarden.ChainBridge
1617
// interface backed by an active remote lnd node.
1718
type LndRpcChainBridge struct {
1819
lnd *lndclient.LndServices
20+
21+
getBlockHeaderSupported *bool
1922
}
2023

2124
// NewLndRpcChainBridge creates a new chain bridge from an active lnd services
@@ -79,6 +82,19 @@ func (l *LndRpcChainBridge) GetBlock(ctx context.Context,
7982
return block, nil
8083
}
8184

85+
// GetBlockHeader returns a block header given its hash.
86+
func (l *LndRpcChainBridge) GetBlockHeader(ctx context.Context,
87+
hash chainhash.Hash) (*wire.BlockHeader, error) {
88+
89+
header, err := l.lnd.ChainKit.GetBlockHeader(ctx, hash)
90+
if err != nil {
91+
return nil, fmt.Errorf("unable to retrieve block header: %w",
92+
err)
93+
}
94+
95+
return header, nil
96+
}
97+
8298
// GetBlockHash returns the hash of the block in the best blockchain at the
8399
// given height.
84100
func (l *LndRpcChainBridge) GetBlockHash(ctx context.Context,
@@ -93,6 +109,31 @@ func (l *LndRpcChainBridge) GetBlockHash(ctx context.Context,
93109
return blockHash, nil
94110
}
95111

112+
// GetBlockHeaderSupported returns true if the chain backend supports the
113+
// `GetBlockHeader` RPC call.
114+
func (l *LndRpcChainBridge) GetBlockHeaderSupported(ctx context.Context) bool {
115+
// Check if we've already asserted the compatibility of the chain
116+
// backend.
117+
if l.getBlockHeaderSupported != nil {
118+
return *l.getBlockHeaderSupported
119+
}
120+
121+
// The ChainKit.GetBlockHeader() RPC call was added in lnd v0.17.1.
122+
getBlockHeaderMinimalVersion := &verrpc.Version{
123+
AppMajor: 0,
124+
AppMinor: 17,
125+
AppPatch: 1,
126+
}
127+
128+
getBlockHeaderUnsupported := lndclient.AssertVersionCompatible(
129+
l.lnd.Version, getBlockHeaderMinimalVersion,
130+
)
131+
getBlockHeaderSupported := getBlockHeaderUnsupported == nil
132+
133+
l.getBlockHeaderSupported = &getBlockHeaderSupported
134+
return *l.getBlockHeaderSupported
135+
}
136+
96137
// VerifyBlock returns an error if a block (with given header and height) is not
97138
// present on-chain. It also checks to ensure that block height corresponds to
98139
// the given block header.
@@ -121,7 +162,14 @@ func (l *LndRpcChainBridge) VerifyBlock(ctx context.Context,
121162
"expectedHash: %s)", height, hash, expectedHash)
122163
}
123164

124-
// Ensure that the block header corresponds to a block on-chain.
165+
// Ensure that the block header corresponds to a block on-chain. Fetch
166+
// only the corresponding block header and not the entire block if
167+
// supported.
168+
if l.GetBlockHeaderSupported(ctx) {
169+
_, err = l.GetBlockHeader(ctx, header.BlockHash())
170+
return err
171+
}
172+
125173
_, err = l.GetBlock(ctx, header.BlockHash())
126174
return err
127175
}

0 commit comments

Comments
 (0)