cnct+lnwl+hswc: use lntypes.Preimage for witness beacon

This commit is contained in:
Conner Fromknecht 2019-02-19 17:06:00 -08:00
parent 2d8bc99d9e
commit 29f07a58cb
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
16 changed files with 126 additions and 114 deletions

View File

@ -1548,10 +1548,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa
Packager: channeldb.NewChannelPackager(shortChanID),
}
pCache := &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache := newMockPreimageCache()
aliceSigner := &mockSigner{aliceKeyPriv}
bobSigner := &mockSigner{bobKeyPriv}

View File

@ -11,6 +11,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
)
@ -40,7 +41,7 @@ type WitnessSubscription struct {
// sent over.
//
// TODO(roasbeef): couple with WitnessType?
WitnessUpdates <-chan []byte
WitnessUpdates <-chan lntypes.Preimage
// CancelSubscription is a function closure that should be used by a
// client to cancel the subscription once they are no longer interested
@ -62,12 +63,12 @@ type WitnessBeacon interface {
// LookupPreImage attempts to lookup a preimage in the global cache.
// True is returned for the second argument if the preimage is found.
LookupPreimage(payhash []byte) ([]byte, bool)
LookupPreimage(payhash lntypes.Hash) (lntypes.Preimage, bool)
// AddPreimages adds a batch of newly discovered preimages to the global
// cache, and also signals any subscribers of the newly discovered
// witness.
AddPreimages(preimages ...[]byte) error
AddPreimages(preimages ...lntypes.Preimage) error
}
// ChannelArbitratorConfig contains all the functionality that the
@ -1129,7 +1130,7 @@ func (c *ChannelArbitrator) checkChainActions(height uint32,
// know the pre-image and it's close to timing out. We need to
// ensure that we claim the funds that our rightfully ours
// on-chain.
if _, ok := c.cfg.PreimageDB.LookupPreimage(htlc.RHash[:]); !ok {
if _, ok := c.cfg.PreimageDB.LookupPreimage(htlc.RHash); !ok {
continue
}
haveChainActions = haveChainActions || c.shouldGoOnChain(
@ -1206,13 +1207,12 @@ func (c *ChannelArbitrator) checkChainActions(height uint32,
// either learn of it eventually from the outgoing HTLC, or the sender
// will timeout the HTLC.
for _, htlc := range c.activeHTLCs.incomingHTLCs {
payHash := htlc.RHash
// If we have the pre-image, then we should go on-chain to
// redeem the HTLC immediately.
if _, ok := c.cfg.PreimageDB.LookupPreimage(payHash[:]); ok {
if _, ok := c.cfg.PreimageDB.LookupPreimage(htlc.RHash); ok {
log.Tracef("ChannelArbitrator(%v): preimage for "+
"htlc=%x is known!", c.cfg.ChanPoint, payHash[:])
"htlc=%x is known!", c.cfg.ChanPoint,
htlc.RHash[:])
actionMap[HtlcClaimAction] = append(
actionMap[HtlcClaimAction], htlc,
@ -1222,7 +1222,7 @@ func (c *ChannelArbitrator) checkChainActions(height uint32,
log.Tracef("ChannelArbitrator(%v): watching chain to decide "+
"action for incoming htlc=%x", c.cfg.ChanPoint,
payHash[:])
htlc.RHash[:])
// Otherwise, we don't yet have the pre-image, but should watch
// on-chain to see if either: the remote party times out the

View File

@ -2,12 +2,12 @@ package contractcourt
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"io"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lntypes"
)
// htlcIncomingContestResolver is a ContractResolver that's able to resolve an
@ -74,11 +74,11 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
// resolver with the preimage we learn of. This should be called once
// the preimage is revealed so the inner resolver can properly complete
// its duties.
applyPreimage := func(preimage []byte) {
copy(h.htlcResolution.Preimage[:], preimage)
applyPreimage := func(preimage lntypes.Preimage) {
h.htlcResolution.Preimage = preimage
log.Infof("%T(%v): extracted preimage=%x from beacon!", h,
h.htlcResolution.ClaimOutpoint, preimage[:])
log.Infof("%T(%v): extracted preimage=%v from beacon!", h,
h.htlcResolution.ClaimOutpoint, preimage)
// If this our commitment transaction, then we'll need to
// populate the witness for the second-level HTLC transaction.
@ -93,8 +93,6 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
// preimage.
h.htlcResolution.SignedSuccessTx.TxIn[0].Witness[3] = preimage[:]
}
copy(h.htlcResolution.Preimage[:], preimage[:])
}
// If the HTLC hasn't expired yet, then we may still be able to claim
@ -116,12 +114,12 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
// With the epochs and preimage subscriptions initialized, we'll query
// to see if we already know the preimage.
preimage, ok := h.PreimageDB.LookupPreimage(h.payHash[:])
preimage, ok := h.PreimageDB.LookupPreimage(h.payHash)
if ok {
// If we do, then this means we can claim the HTLC! However,
// we don't know how to ourselves, so we'll return our inner
// resolver which has the knowledge to do so.
applyPreimage(preimage[:])
applyPreimage(preimage)
return &h.htlcSuccessResolver, nil
}
@ -131,8 +129,8 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
case preimage := <-preimageSubscription.WitnessUpdates:
// If this isn't our preimage, then we'll continue
// onwards.
newHash := sha256.Sum256(preimage)
preimageMatches := bytes.Equal(newHash[:], h.payHash[:])
hash := preimage.Hash()
preimageMatches := bytes.Equal(hash[:], h.payHash[:])
if !preimageMatches {
continue
}

View File

@ -2,13 +2,15 @@ package contractcourt
import (
"fmt"
"github.com/lightningnetwork/lnd/input"
"io"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lntypes"
)
// htlcOutgoingContestResolver is a ContractResolver that's able to resolve an
@ -58,38 +60,47 @@ func (h *htlcOutgoingContestResolver) Resolve() (ContractResolver, error) {
// If this is the remote party's commitment, then we'll be
// looking for them to spend using the second-level success
// transaction.
var preimage [32]byte
var preimageBytes []byte
if h.htlcResolution.SignedTimeoutTx == nil {
// The witness stack when the remote party sweeps the
// output to them looks like:
//
// * <sender sig> <recvr sig> <preimage> <witness script>
copy(preimage[:], spendingInput.Witness[3])
preimageBytes = spendingInput.Witness[3]
} else {
// Otherwise, they'll be spending directly from our
// commitment output. In which case the witness stack
// looks like:
//
// * <sig> <preimage> <witness script>
copy(preimage[:], spendingInput.Witness[1])
preimageBytes = spendingInput.Witness[1]
}
log.Infof("%T(%v): extracting preimage=%x from on-chain "+
"spend!", h, h.htlcResolution.ClaimOutpoint, preimage[:])
preimage, err := lntypes.MakePreimage(preimageBytes)
if err != nil {
return nil, err
}
log.Infof("%T(%v): extracting preimage=%v from on-chain "+
"spend!", h, h.htlcResolution.ClaimOutpoint,
preimage)
// With the preimage obtained, we can now add it to the global
// cache.
if err := h.PreimageDB.AddPreimages(preimage[:]); err != nil {
if err := h.PreimageDB.AddPreimages(preimage); err != nil {
log.Errorf("%T(%v): unable to add witness to cache",
h, h.htlcResolution.ClaimOutpoint)
}
var pre [32]byte
copy(pre[:], preimage[:])
// Finally, we'll send the clean up message, mark ourselves as
// resolved, then exit.
if err := h.DeliverResolutionMsg(ResolutionMsg{
SourceChan: h.ShortChanID,
HtlcIndex: h.htlcIndex,
PreImage: &preimage,
PreImage: &pre,
}); err != nil {
return nil, err
}

View File

@ -3,15 +3,16 @@ package contractcourt
import (
"encoding/binary"
"fmt"
"github.com/lightningnetwork/lnd/input"
"io"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/sweep"
)
@ -41,7 +42,7 @@ type htlcSuccessResolver struct {
broadcastHeight uint32
// payHash is the payment hash of the original HTLC extended to us.
payHash [32]byte
payHash lntypes.Hash
// sweepTx will be non-nil if we've already crafted a transaction to
// sweep a direct HTLC output. This is only a concern if we're sweeping

View File

@ -1417,7 +1417,7 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
// any contested contracts watched by any on-chain arbitrators
// can now sweep this HTLC on-chain.
go func() {
err := l.cfg.PreimageCache.AddPreimages(pre[:])
err := l.cfg.PreimageCache.AddPreimages(pre)
if err != nil {
l.errorf("unable to add preimage=%x to "+
"cache", pre[:])

View File

@ -1532,10 +1532,7 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
invoiceRegistry = newMockRegistry(globalPolicy.TimeLockDelta)
)
pCache := &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache := newMockPreimageCache()
aliceDb := aliceChannel.State().Db
aliceSwitch, err := initSwitchWithDB(testStartingHeight, aliceDb)
@ -4042,10 +4039,7 @@ func restartLink(aliceChannel *lnwallet.LightningChannel, aliceSwitch *Switch,
invoiceRegistry = newMockRegistry(globalPolicy.TimeLockDelta)
pCache = &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache = newMockPreimageCache()
)
aliceDb := aliceChannel.State().Db

View File

@ -32,26 +32,31 @@ import (
type mockPreimageCache struct {
sync.Mutex
preimageMap map[[32]byte][]byte
preimageMap map[lntypes.Hash]lntypes.Preimage
}
func (m *mockPreimageCache) LookupPreimage(hash []byte) ([]byte, bool) {
func newMockPreimageCache() *mockPreimageCache {
return &mockPreimageCache{
preimageMap: make(map[lntypes.Hash]lntypes.Preimage),
}
}
func (m *mockPreimageCache) LookupPreimage(
hash lntypes.Hash) (lntypes.Preimage, bool) {
m.Lock()
defer m.Unlock()
var h [32]byte
copy(h[:], hash)
p, ok := m.preimageMap[h]
p, ok := m.preimageMap[hash]
return p, ok
}
func (m *mockPreimageCache) AddPreimages(preimages ...[]byte) error {
func (m *mockPreimageCache) AddPreimages(preimages ...lntypes.Preimage) error {
m.Lock()
defer m.Unlock()
for _, preimage := range preimages {
m.preimageMap[sha256.Sum256(preimage)] = preimage
m.preimageMap[preimage.Hash()] = preimage
}
return nil

View File

@ -367,10 +367,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
aliceSigner := &mockSigner{aliceKeyPriv}
bobSigner := &mockSigner{bobKeyPriv}
pCache := &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache := newMockPreimageCache()
alicePool := lnwallet.NewSigPool(runtime.NumCPU(), aliceSigner)
channelAlice, err := lnwallet.NewLightningChannel(
@ -982,10 +979,7 @@ type hopNetwork struct {
func newHopNetwork() *hopNetwork {
defaultDelta := uint32(6)
pCache := &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache := newMockPreimageCache()
globalPolicy := ForwardingPolicy{
MinHTLC: lnwire.NewMSatFromSatoshis(5),

View File

@ -5577,12 +5577,12 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
// We'll now query the preimage cache for the preimage
// for this HTLC. If it's present then we can fully
// populate this resolution.
preimage, _ := pCache.LookupPreimage(htlc.RHash[:])
preimage, _ := pCache.LookupPreimage(htlc.RHash)
// Otherwise, we'll create an incoming HTLC resolution
// as we can satisfy the contract.
var pre [32]byte
copy(pre[:], preimage)
copy(pre[:], preimage[:])
ihr, err := newIncomingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, dustLimit, uint32(csvDelay), ourCommit,

View File

@ -19,6 +19,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
)
@ -584,7 +585,7 @@ func TestForceClose(t *testing.T) {
// Before we force close Alice's channel, we'll add the pre-image of
// Bob's HTLC to her preimage cache.
aliceChannel.pCache.AddPreimages(preimageBob[:])
aliceChannel.pCache.AddPreimages(lntypes.Preimage(preimageBob))
// With the cache populated, we'll now attempt the force close
// initiated by Alice.
@ -4953,7 +4954,7 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) {
// Now that Bob has force closed, we'll modify Alice's pre image cache
// such that she now gains the ability to also settle the incoming HTLC
// from Bob.
aliceChannel.pCache.AddPreimages(preimageBob[:])
aliceChannel.pCache.AddPreimages(lntypes.Preimage(preimageBob))
// We'll then use Bob's transaction to trigger a spend notification for
// Alice.

View File

@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lntypes"
)
// AddressType is an enum-like type which denotes the possible address types
@ -272,15 +273,12 @@ type PreimageCache interface {
// LookupPreimage attempts to look up a preimage according to its hash.
// If found, the preimage is returned along with true for the second
// argument. Otherwise, it'll return false.
LookupPreimage(hash []byte) ([]byte, bool)
LookupPreimage(hash lntypes.Hash) (lntypes.Preimage, bool)
// AddPreimages adds a batch of newly discovered preimages to the global
// cache, and also signals any subscribers of the newly discovered
// witness.
//
// NOTE: The backing slice of MUST NOT be modified, otherwise the
// subscribers may be notified of the incorrect preimages.
AddPreimages(preimages ...[]byte) error
AddPreimages(preimages ...lntypes.Preimage) error
}
// WalletDriver represents a "driver" for a particular concrete

View File

@ -3,7 +3,6 @@ package lnwallet
import (
"bytes"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"io"
@ -18,6 +17,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
)
@ -301,10 +301,7 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
aliceSigner := &input.MockSigner{Privkeys: aliceKeys}
bobSigner := &input.MockSigner{Privkeys: bobKeys}
pCache := &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache := newMockPreimageCache()
// TODO(roasbeef): make mock version of pre-image store
@ -389,26 +386,36 @@ func initRevocationWindows(chanA, chanB *LightningChannel) error {
type mockPreimageCache struct {
sync.Mutex
preimageMap map[[32]byte][]byte
preimageMap map[lntypes.Hash]lntypes.Preimage
}
func (m *mockPreimageCache) LookupPreimage(hash []byte) ([]byte, bool) {
func newMockPreimageCache() *mockPreimageCache {
return &mockPreimageCache{
preimageMap: make(map[lntypes.Hash]lntypes.Preimage),
}
}
func (m *mockPreimageCache) LookupPreimage(
hash lntypes.Hash) (lntypes.Preimage, bool) {
m.Lock()
defer m.Unlock()
var h [32]byte
copy(h[:], hash)
p, ok := m.preimageMap[h]
p, ok := m.preimageMap[hash]
return p, ok
}
func (m *mockPreimageCache) AddPreimages(preimages ...[]byte) error {
func (m *mockPreimageCache) AddPreimages(preimages ...lntypes.Preimage) error {
preimageCopies := make([]lntypes.Preimage, 0, len(preimages))
for _, preimage := range preimages {
preimageCopies = append(preimageCopies, preimage)
}
m.Lock()
defer m.Unlock()
for _, preimage := range preimages {
m.preimageMap[sha256.Sum256(preimage)] = preimage
for _, preimage := range preimageCopies {
m.preimageMap[preimage.Hash()] = preimage
}
return nil

View File

@ -780,10 +780,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
},
}
pCache := &mockPreimageCache{
// hash -> preimage
preimageMap: make(map[[32]byte][]byte),
}
pCache := newMockPreimageCache()
for i, test := range testCases {
expectedCommitmentTx, err := txFromHex(test.expectedCommitmentTxHex)

21
mock.go
View File

@ -1,7 +1,6 @@
package main
import (
"crypto/sha256"
"fmt"
"sync"
"sync/atomic"
@ -16,6 +15,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet"
)
@ -303,26 +303,29 @@ func (m *mockSecretKeyRing) ScalarMult(keyDesc keychain.KeyDescriptor,
type mockPreimageCache struct {
sync.Mutex
preimageMap map[[32]byte][]byte
preimageMap map[lntypes.Hash]lntypes.Preimage
}
func (m *mockPreimageCache) LookupPreimage(hash []byte) ([]byte, bool) {
func newMockPreimageCache() *mockPreimageCache {
return &mockPreimageCache{
preimageMap: make(map[lntypes.Hash]lntypes.Preimage),
}
}
func (m *mockPreimageCache) LookupPreimage(hash lntypes.Hash) (lntypes.Preimage, bool) {
m.Lock()
defer m.Unlock()
var h [32]byte
copy(h[:], hash)
p, ok := m.preimageMap[h]
p, ok := m.preimageMap[hash]
return p, ok
}
func (m *mockPreimageCache) AddPreimages(preimages ...[]byte) error {
func (m *mockPreimageCache) AddPreimages(preimages ...lntypes.Preimage) error {
m.Lock()
defer m.Unlock()
for _, preimage := range preimages {
m.preimageMap[sha256.Sum256(preimage)] = preimage
m.preimageMap[preimage.Hash()] = preimage
}
return nil

View File

@ -13,7 +13,7 @@ import (
// preimageSubscriber reprints an active subscription to be notified once the
// daemon discovers new preimages, either on chain or off-chain.
type preimageSubscriber struct {
updateChan chan []byte
updateChan chan lntypes.Preimage
quit chan struct{}
}
@ -40,7 +40,7 @@ func (p *preimageBeacon) SubscribeUpdates() *contractcourt.WitnessSubscription {
clientID := p.clientCounter
client := &preimageSubscriber{
updateChan: make(chan []byte, 10),
updateChan: make(chan lntypes.Preimage, 10),
quit: make(chan struct{}),
}
@ -66,36 +66,42 @@ func (p *preimageBeacon) SubscribeUpdates() *contractcourt.WitnessSubscription {
// LookupPreImage attempts to lookup a preimage in the global cache. True is
// returned for the second argument if the preimage is found.
func (p *preimageBeacon) LookupPreimage(payHash []byte) ([]byte, bool) {
func (p *preimageBeacon) LookupPreimage(
payHash lntypes.Hash) (lntypes.Preimage, bool) {
p.RLock()
defer p.RUnlock()
// First, we'll check the invoice registry to see if we already know of
// the preimage as it's on that we created ourselves.
var invoiceKey lntypes.Hash
copy(invoiceKey[:], payHash)
invoice, _, err := p.invoices.LookupInvoice(invoiceKey)
invoice, _, err := p.invoices.LookupInvoice(payHash)
switch {
case err == channeldb.ErrInvoiceNotFound:
// If we get this error, then it simply means that this invoice
// wasn't found, so we don't treat it as a critical error.
case err != nil:
return nil, false
return lntypes.Preimage{}, false
}
// If we've found the invoice, then we can return the preimage
// directly.
if err != channeldb.ErrInvoiceNotFound {
return invoice.Terms.PaymentPreimage[:], true
return invoice.Terms.PaymentPreimage, true
}
// Otherwise, we'll perform a final check using the witness cache.
preimage, err := p.wCache.LookupWitness(
channeldb.Sha256HashWitness, payHash,
preimageBytes, err := p.wCache.LookupWitness(
channeldb.Sha256HashWitness, payHash[:],
)
if err != nil {
ltndLog.Errorf("unable to lookup witness: %v", err)
return nil, false
ltndLog.Errorf("Unable to lookup witness: %v", err)
return lntypes.Preimage{}, false
}
preimage, err := lntypes.MakePreimage(preimageBytes)
if err != nil {
ltndLog.Errorf("Unable to build witness: %v", err)
return lntypes.Preimage{}, false
}
return preimage, true
@ -103,7 +109,7 @@ func (p *preimageBeacon) LookupPreimage(payHash []byte) ([]byte, bool) {
// AddPreimages adds a batch of newly discovered preimages to the global cache,
// and also signals any subscribers of the newly discovered witness.
func (p *preimageBeacon) AddPreimages(preimages ...[]byte) error {
func (p *preimageBeacon) AddPreimages(preimages ...lntypes.Preimage) error {
// Exit early if no preimages are presented.
if len(preimages) == 0 {
return nil
@ -111,14 +117,14 @@ func (p *preimageBeacon) AddPreimages(preimages ...[]byte) error {
// Copy the preimages to ensure the backing area can't be modified by
// the caller when delivering notifications.
preimageCopies := make([][]byte, 0, len(preimages))
preimageCopies := make([]lntypes.Preimage, 0, len(preimages))
for _, preimage := range preimages {
srvrLog.Infof("Adding preimage=%x to witness cache", preimage)
srvrLog.Infof("Adding preimage=%v to witness cache", preimage)
preimageCopies = append(preimageCopies, preimage)
}
// First, we'll add the witness to the decaying witness cache.
err := p.wCache.AddWitnesses(channeldb.Sha256HashWitness, preimages...)
err := p.wCache.AddSha256Witnesses(preimages...)
if err != nil {
return err
}