lnwallet: extract fetchparent for individual testing

This commit is contained in:
carla 2020-05-03 14:07:55 +02:00
parent 2c979fc179
commit 54a06cb96a
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
2 changed files with 281 additions and 53 deletions

@ -2494,10 +2494,106 @@ func (lc *LightningChannel) evaluateHTLCView(view *htlcView, ourBalance,
skipUs := make(map[uint64]struct{})
skipThem := make(map[uint64]struct{})
// fetchParentEntry is a helper method that will fetch the parent of
// entry from the corresponding update log.
fetchParentEntry := func(entry *PaymentDescriptor,
remoteLog bool) (*PaymentDescriptor, error) {
// First we run through non-add entries in both logs, populating the
// skip sets and mutating the current chain state (crediting balances,
// etc) to reflect the settle/timeout entry encountered.
for _, entry := range view.ourUpdates {
switch entry.EntryType {
// Skip adds for now. They will be processed below.
case Add:
continue
// Process fee updates, updating the current feePerKw.
case FeeUpdate:
processFeeUpdate(
entry, nextHeight, remoteChain, mutateState,
newView,
)
continue
}
// If we're settling an inbound HTLC, and it hasn't been
// processed yet, then increment our state tracking the total
// number of satoshis we've received within the channel.
if mutateState && entry.EntryType == Settle && !remoteChain &&
entry.removeCommitHeightLocal == 0 {
lc.channelState.TotalMSatReceived += entry.Amount
}
addEntry, err := lc.fetchParent(entry, remoteChain, true)
if err != nil {
return nil, err
}
skipThem[addEntry.HtlcIndex] = struct{}{}
processRemoveEntry(entry, ourBalance, theirBalance,
nextHeight, remoteChain, true, mutateState)
}
for _, entry := range view.theirUpdates {
switch entry.EntryType {
// Skip adds for now. They will be processed below.
case Add:
continue
// Process fee updates, updating the current feePerKw.
case FeeUpdate:
processFeeUpdate(
entry, nextHeight, remoteChain, mutateState,
newView,
)
continue
}
// If the remote party is settling one of our outbound HTLC's,
// and it hasn't been processed, yet, the increment our state
// tracking the total number of satoshis we've sent within the
// channel.
if mutateState && entry.EntryType == Settle && !remoteChain &&
entry.removeCommitHeightLocal == 0 {
lc.channelState.TotalMSatSent += entry.Amount
}
addEntry, err := lc.fetchParent(entry, remoteChain, false)
if err != nil {
return nil, err
}
skipUs[addEntry.HtlcIndex] = struct{}{}
processRemoveEntry(entry, ourBalance, theirBalance,
nextHeight, remoteChain, false, mutateState)
}
// Next we take a second pass through all the log entries, skipping any
// settled HTLCs, and debiting the chain state balance due to any newly
// added HTLCs.
for _, entry := range view.ourUpdates {
isAdd := entry.EntryType == Add
if _, ok := skipUs[entry.HtlcIndex]; !isAdd || ok {
continue
}
processAddEntry(entry, ourBalance, theirBalance, nextHeight,
remoteChain, false, mutateState)
newView.ourUpdates = append(newView.ourUpdates, entry)
}
for _, entry := range view.theirUpdates {
isAdd := entry.EntryType == Add
if _, ok := skipThem[entry.HtlcIndex]; !isAdd || ok {
continue
}
processAddEntry(entry, ourBalance, theirBalance, nextHeight,
remoteChain, true, mutateState)
newView.theirUpdates = append(newView.theirUpdates, entry)
}
return newView, nil
}
// getFetchParent is a helper that looks up update log parent entries in the
// appropriate log.
func (lc *LightningChannel) fetchParent(entry *PaymentDescriptor,
remoteChain, remoteLog bool) (*PaymentDescriptor, error) {
var (
updateLog *updateLog
@ -2543,102 +2639,6 @@ func (lc *LightningChannel) evaluateHTLCView(view *htlcView, ourBalance,
}
return addEntry, nil
}
// First we run through non-add entries in both logs, populating the
// skip sets and mutating the current chain state (crediting balances,
// etc) to reflect the settle/timeout entry encountered.
for _, entry := range view.ourUpdates {
switch entry.EntryType {
// Skip adds for now. They will be processed below.
case Add:
continue
// Process fee updates, updating the current feePerKw.
case FeeUpdate:
processFeeUpdate(
entry, nextHeight, remoteChain, mutateState,
newView,
)
continue
}
// If we're settling an inbound HTLC, and it hasn't been
// processed yet, then increment our state tracking the total
// number of satoshis we've received within the channel.
if mutateState && entry.EntryType == Settle && !remoteChain &&
entry.removeCommitHeightLocal == 0 {
lc.channelState.TotalMSatReceived += entry.Amount
}
addEntry, err := fetchParentEntry(entry, true)
if err != nil {
return nil, err
}
skipThem[addEntry.HtlcIndex] = struct{}{}
processRemoveEntry(entry, ourBalance, theirBalance,
nextHeight, remoteChain, true, mutateState)
}
for _, entry := range view.theirUpdates {
switch entry.EntryType {
// Skip adds for now. They will be processed below.
case Add:
continue
// Process fee updates, updating the current feePerKw.
case FeeUpdate:
processFeeUpdate(
entry, nextHeight, remoteChain, mutateState,
newView,
)
continue
}
// If the remote party is settling one of our outbound HTLC's,
// and it hasn't been processed, yet, the increment our state
// tracking the total number of satoshis we've sent within the
// channel.
if mutateState && entry.EntryType == Settle && !remoteChain &&
entry.removeCommitHeightLocal == 0 {
lc.channelState.TotalMSatSent += entry.Amount
}
addEntry, err := fetchParentEntry(entry, false)
if err != nil {
return nil, err
}
skipUs[addEntry.HtlcIndex] = struct{}{}
processRemoveEntry(entry, ourBalance, theirBalance,
nextHeight, remoteChain, false, mutateState)
}
// Next we take a second pass through all the log entries, skipping any
// settled HTLCs, and debiting the chain state balance due to any newly
// added HTLCs.
for _, entry := range view.ourUpdates {
isAdd := entry.EntryType == Add
if _, ok := skipUs[entry.HtlcIndex]; !isAdd || ok {
continue
}
processAddEntry(entry, ourBalance, theirBalance, nextHeight,
remoteChain, false, mutateState)
newView.ourUpdates = append(newView.ourUpdates, entry)
}
for _, entry := range view.theirUpdates {
isAdd := entry.EntryType == Add
if _, ok := skipThem[entry.HtlcIndex]; !isAdd || ok {
continue
}
processAddEntry(entry, ourBalance, theirBalance, nextHeight,
remoteChain, true, mutateState)
newView.theirUpdates = append(newView.theirUpdates, entry)
}
return newView, nil
}
// processAddEntry evaluates the effect of an add entry within the HTLC log.

@ -7676,3 +7676,231 @@ func TestChannelFeeRateFloor(t *testing.T) {
err)
}
}
// TestFetchParent tests lookup of an entry's parent in the appropriate log.
func TestFetchParent(t *testing.T) {
tests := []struct {
name string
remoteChain bool
remoteLog bool
localEntries []*PaymentDescriptor
remoteEntries []*PaymentDescriptor
// parentIndex is the parent index of the entry that we will
// lookup with fetch parent.
parentIndex uint64
// expectErr indicates that we expect fetch parent to fail.
expectErr bool
// expectedIndex is the htlc index that we expect the parent
// to have.
expectedIndex uint64
}{
{
name: "not found in remote log",
localEntries: nil,
remoteEntries: nil,
remoteChain: true,
remoteLog: true,
parentIndex: 0,
expectErr: true,
},
{
name: "not found in local log",
localEntries: nil,
remoteEntries: nil,
remoteChain: false,
remoteLog: false,
parentIndex: 0,
expectErr: true,
},
{
name: "remote log + chain, remote add height 0",
localEntries: nil,
remoteEntries: []*PaymentDescriptor{
// This entry will be added at log index =0.
{
HtlcIndex: 1,
addCommitHeightLocal: 100,
addCommitHeightRemote: 100,
},
// This entry will be added at log index =1, it
// is the parent entry we are looking for.
{
HtlcIndex: 2,
addCommitHeightLocal: 100,
addCommitHeightRemote: 0,
},
},
remoteChain: true,
remoteLog: true,
parentIndex: 1,
expectErr: true,
},
{
name: "remote log, local chain, local add height 0",
remoteEntries: []*PaymentDescriptor{
// This entry will be added at log index =0.
{
HtlcIndex: 1,
addCommitHeightLocal: 100,
addCommitHeightRemote: 100,
},
// This entry will be added at log index =1, it
// is the parent entry we are looking for.
{
HtlcIndex: 2,
addCommitHeightLocal: 0,
addCommitHeightRemote: 100,
},
},
localEntries: nil,
remoteChain: false,
remoteLog: true,
parentIndex: 1,
expectErr: true,
},
{
name: "local log + chain, local add height 0",
localEntries: []*PaymentDescriptor{
// This entry will be added at log index =0.
{
HtlcIndex: 1,
addCommitHeightLocal: 100,
addCommitHeightRemote: 100,
},
// This entry will be added at log index =1, it
// is the parent entry we are looking for.
{
HtlcIndex: 2,
addCommitHeightLocal: 0,
addCommitHeightRemote: 100,
},
},
remoteEntries: nil,
remoteChain: false,
remoteLog: false,
parentIndex: 1,
expectErr: true,
},
{
name: "local log + remote chain, remote add height 0",
localEntries: []*PaymentDescriptor{
// This entry will be added at log index =0.
{
HtlcIndex: 1,
addCommitHeightLocal: 100,
addCommitHeightRemote: 100,
},
// This entry will be added at log index =1, it
// is the parent entry we are looking for.
{
HtlcIndex: 2,
addCommitHeightLocal: 100,
addCommitHeightRemote: 0,
},
},
remoteEntries: nil,
remoteChain: true,
remoteLog: false,
parentIndex: 1,
expectErr: true,
},
{
name: "remote log found",
localEntries: nil,
remoteEntries: []*PaymentDescriptor{
// This entry will be added at log index =0.
{
HtlcIndex: 1,
addCommitHeightLocal: 100,
addCommitHeightRemote: 0,
},
// This entry will be added at log index =1, it
// is the parent entry we are looking for.
{
HtlcIndex: 2,
addCommitHeightLocal: 100,
addCommitHeightRemote: 100,
},
},
remoteChain: true,
remoteLog: true,
parentIndex: 1,
expectErr: false,
expectedIndex: 2,
},
{
name: "local log found",
localEntries: []*PaymentDescriptor{
// This entry will be added at log index =0.
{
HtlcIndex: 1,
addCommitHeightLocal: 0,
addCommitHeightRemote: 100,
},
// This entry will be added at log index =1, it
// is the parent entry we are looking for.
{
HtlcIndex: 2,
addCommitHeightLocal: 100,
addCommitHeightRemote: 100,
},
},
remoteEntries: nil,
remoteChain: false,
remoteLog: false,
parentIndex: 1,
expectErr: false,
expectedIndex: 2,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
// Create a lightning channel with newly initialized
// local and remote logs.
lc := LightningChannel{
localUpdateLog: newUpdateLog(0, 0),
remoteUpdateLog: newUpdateLog(0, 0),
}
// Add the local and remote entries to update logs.
for _, entry := range test.localEntries {
lc.localUpdateLog.appendHtlc(entry)
}
for _, entry := range test.remoteEntries {
lc.remoteUpdateLog.appendHtlc(entry)
}
parent, err := lc.fetchParent(
&PaymentDescriptor{
ParentIndex: test.parentIndex,
},
test.remoteChain,
test.remoteLog,
)
gotErr := err != nil
if test.expectErr != gotErr {
t.Fatalf("expected error: %v, got: %v, "+
"error:%v", test.expectErr, gotErr, err)
}
// If our lookup failed, we do not need to check parent
// index.
if err != nil {
return
}
if parent.HtlcIndex != test.expectedIndex {
t.Fatalf("expected parent index: %v, got: %v",
test.parentIndex, parent.HtlcIndex)
}
})
}
}