mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
203 lines
5.1 KiB
Go
203 lines
5.1 KiB
Go
package htlcswitch
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
|
|
"github.com/go-errors/errors"
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
|
"github.com/lightningnetwork/lnd/contractcourt"
|
|
"github.com/lightningnetwork/lnd/kvdb"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
)
|
|
|
|
var (
|
|
// resBucketKey is used for the root level bucket that stores the
|
|
// CircuitKey -> ResolutionMsg mapping.
|
|
resBucketKey = []byte("resolution-store-bucket-key")
|
|
|
|
// errResMsgNotFound is used to let callers know that the resolution
|
|
// message was not found for the given CircuitKey. This is used in the
|
|
// checkResolutionMsg function.
|
|
errResMsgNotFound = errors.New("resolution message not found")
|
|
)
|
|
|
|
// resolutionStore contains ResolutionMsgs received from the contractcourt. The
|
|
// Switch deletes these from the store when the underlying circuit has been
|
|
// removed via DeleteCircuits. If the circuit hasn't been deleted, the Switch
|
|
// will dispatch the ResolutionMsg to a link if this was a multi-hop HTLC or to
|
|
// itself if the Switch initiated the payment.
|
|
type resolutionStore struct {
|
|
backend kvdb.Backend
|
|
}
|
|
|
|
func newResolutionStore(db kvdb.Backend) *resolutionStore {
|
|
return &resolutionStore{
|
|
backend: db,
|
|
}
|
|
}
|
|
|
|
// addResolutionMsg persists a ResolutionMsg to the resolutionStore.
|
|
func (r *resolutionStore) addResolutionMsg(
|
|
resMsg *contractcourt.ResolutionMsg) error {
|
|
|
|
// The outKey will be the database key.
|
|
outKey := &CircuitKey{
|
|
ChanID: resMsg.SourceChan,
|
|
HtlcID: resMsg.HtlcIndex,
|
|
}
|
|
|
|
var resBuf bytes.Buffer
|
|
if err := serializeResolutionMsg(&resBuf, resMsg); err != nil {
|
|
return err
|
|
}
|
|
|
|
err := kvdb.Update(r.backend, func(tx kvdb.RwTx) error {
|
|
resBucket, err := tx.CreateTopLevelBucket(resBucketKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return resBucket.Put(outKey.Bytes(), resBuf.Bytes())
|
|
}, func() {})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// checkResolutionMsg returns nil if the resolution message is found in the
|
|
// store. It returns an error if no resolution message was found for the
|
|
// passed outKey or if a database error occurred.
|
|
func (r *resolutionStore) checkResolutionMsg(outKey *CircuitKey) error {
|
|
err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
|
|
resBucket := tx.ReadBucket(resBucketKey)
|
|
if resBucket == nil {
|
|
// Return an error if the bucket doesn't exist.
|
|
return errResMsgNotFound
|
|
}
|
|
|
|
msg := resBucket.Get(outKey.Bytes())
|
|
if msg == nil {
|
|
// Return the not found error since no message exists
|
|
// for this CircuitKey.
|
|
return errResMsgNotFound
|
|
}
|
|
|
|
// Return nil to indicate that the message was found.
|
|
return nil
|
|
}, func() {})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// fetchAllResolutionMsg returns a slice of all stored ResolutionMsgs. This is
|
|
// used by the Switch on start-up.
|
|
func (r *resolutionStore) fetchAllResolutionMsg() (
|
|
[]*contractcourt.ResolutionMsg, error) {
|
|
|
|
var msgs []*contractcourt.ResolutionMsg
|
|
|
|
err := kvdb.View(r.backend, func(tx kvdb.RTx) error {
|
|
resBucket := tx.ReadBucket(resBucketKey)
|
|
if resBucket == nil {
|
|
return nil
|
|
}
|
|
|
|
return resBucket.ForEach(func(k, v []byte) error {
|
|
kr := bytes.NewReader(k)
|
|
outKey := &CircuitKey{}
|
|
if err := outKey.Decode(kr); err != nil {
|
|
return err
|
|
}
|
|
|
|
vr := bytes.NewReader(v)
|
|
resMsg, err := deserializeResolutionMsg(vr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set the CircuitKey values on the ResolutionMsg.
|
|
resMsg.SourceChan = outKey.ChanID
|
|
resMsg.HtlcIndex = outKey.HtlcID
|
|
|
|
msgs = append(msgs, resMsg)
|
|
return nil
|
|
})
|
|
}, func() {
|
|
msgs = nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return msgs, nil
|
|
}
|
|
|
|
// deleteResolutionMsg removes a ResolutionMsg with the passed-in CircuitKey.
|
|
func (r *resolutionStore) deleteResolutionMsg(outKey *CircuitKey) error {
|
|
err := kvdb.Update(r.backend, func(tx kvdb.RwTx) error {
|
|
resBucket, err := tx.CreateTopLevelBucket(resBucketKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return resBucket.Delete(outKey.Bytes())
|
|
}, func() {})
|
|
return err
|
|
}
|
|
|
|
// serializeResolutionMsg writes part of a ResolutionMsg to the passed
|
|
// io.Writer.
|
|
func serializeResolutionMsg(w io.Writer,
|
|
resMsg *contractcourt.ResolutionMsg) error {
|
|
|
|
isFail := resMsg.Failure != nil
|
|
|
|
if err := channeldb.WriteElement(w, isFail); err != nil {
|
|
return err
|
|
}
|
|
|
|
// If this is a failure message, then we're done serializing.
|
|
if isFail {
|
|
return nil
|
|
}
|
|
|
|
// Else this is a settle message, and we need to write the preimage.
|
|
return channeldb.WriteElement(w, *resMsg.PreImage)
|
|
}
|
|
|
|
// deserializeResolutionMsg reads part of a ResolutionMsg from the passed
|
|
// io.Reader.
|
|
func deserializeResolutionMsg(r io.Reader) (*contractcourt.ResolutionMsg,
|
|
error) {
|
|
|
|
resMsg := &contractcourt.ResolutionMsg{}
|
|
var isFail bool
|
|
|
|
if err := channeldb.ReadElements(r, &isFail); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If a failure resolution msg was stored, set the Failure field.
|
|
if isFail {
|
|
failureMsg := &lnwire.FailPermanentChannelFailure{}
|
|
resMsg.Failure = failureMsg
|
|
return resMsg, nil
|
|
}
|
|
|
|
var preimage [32]byte
|
|
resMsg.PreImage = &preimage
|
|
|
|
// Else this is a settle resolution msg and we will read the preimage.
|
|
if err := channeldb.ReadElement(r, resMsg.PreImage); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resMsg, nil
|
|
}
|