channeldb/invoices: rigorously test updateHtlc for MPP/AMP scenarios
This commit is contained in:
parent
0b5be8576e
commit
2a49b59f4f
@ -1668,6 +1668,671 @@ func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) {
|
|||||||
require.Equal(t, test.expError, err)
|
require.Equal(t, test.expError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type updateHTLCTest struct {
|
||||||
|
name string
|
||||||
|
input InvoiceHTLC
|
||||||
|
invState ContractState
|
||||||
|
setID *[32]byte
|
||||||
|
output InvoiceHTLC
|
||||||
|
expErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUpdateHTLC asserts the behavior of the updateHTLC method in various
|
||||||
|
// scenarios for MPP and AMP.
|
||||||
|
func TestUpdateHTLC(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
setID := [32]byte{0x01}
|
||||||
|
ampRecord := record.NewAMP([32]byte{0x02}, setID, 3)
|
||||||
|
preimage := lntypes.Preimage{0x04}
|
||||||
|
hash := preimage.Hash()
|
||||||
|
|
||||||
|
diffSetID := [32]byte{0x05}
|
||||||
|
fakePreimage := lntypes.Preimage{0x06}
|
||||||
|
testAlreadyNow := time.Now()
|
||||||
|
|
||||||
|
tests := []updateHTLCTest{
|
||||||
|
{
|
||||||
|
name: "MPP accept",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: nil,
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: nil,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: nil,
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MPP settle",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: nil,
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: nil,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: nil,
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MPP cancel",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: nil,
|
||||||
|
},
|
||||||
|
invState: ContractCanceled,
|
||||||
|
setID: nil,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: nil,
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP accept missing preimage",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: ErrHTLCPreimageMissing,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP accept invalid preimage",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &fakePreimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &fakePreimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: ErrHTLCPreimageMismatch,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP accept valid preimage",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP accept valid preimage different htlc set",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: &diffSetID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP settle missing preimage",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: ErrHTLCPreimageMissing,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP settle invalid preimage",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &fakePreimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &fakePreimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: ErrHTLCPreimageMismatch,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP settle valid preimage",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMP settle valid preimage different htlc set",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: &diffSetID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "accept invoice htlc already settled",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: ErrHTLCAlreadySettled,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cancel invoice htlc already settled",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractCanceled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: ErrHTLCAlreadySettled,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "settle invoice htlc already settled",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateSettled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cancel invoice",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: time.Time{},
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateAccepted,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractCanceled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "accept invoice htlc already canceled",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractAccepted,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cancel invoice htlc already canceled",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractCanceled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "settle invoice htlc already canceled",
|
||||||
|
input: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
invState: ContractSettled,
|
||||||
|
setID: &setID,
|
||||||
|
output: InvoiceHTLC{
|
||||||
|
Amt: 5000,
|
||||||
|
MppTotalAmt: 5000,
|
||||||
|
AcceptHeight: 100,
|
||||||
|
AcceptTime: testNow,
|
||||||
|
ResolveTime: testAlreadyNow,
|
||||||
|
Expiry: 40,
|
||||||
|
State: HtlcStateCanceled,
|
||||||
|
CustomRecords: make(record.CustomSet),
|
||||||
|
AMP: &InvoiceHtlcAMPData{
|
||||||
|
Record: *ampRecord,
|
||||||
|
Hash: hash,
|
||||||
|
Preimage: &preimage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
testUpdateHTLC(t, test)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testUpdateHTLC(t *testing.T, test updateHTLCTest) {
|
||||||
|
htlc := test.input.Copy()
|
||||||
|
err := updateHtlc(testNow, htlc, test.invState, test.setID)
|
||||||
|
require.Equal(t, test.expErr, err)
|
||||||
|
require.Equal(t, test.output, *htlc)
|
||||||
|
}
|
||||||
|
|
||||||
// TestDeleteInvoices tests that deleting a list of invoices will succeed
|
// TestDeleteInvoices tests that deleting a list of invoices will succeed
|
||||||
// if all delete references are valid, or will fail otherwise.
|
// if all delete references are valid, or will fail otherwise.
|
||||||
func TestDeleteInvoices(t *testing.T) {
|
func TestDeleteInvoices(t *testing.T) {
|
||||||
|
@ -117,6 +117,19 @@ var (
|
|||||||
// match the invoice hash.
|
// match the invoice hash.
|
||||||
ErrInvoicePreimageMismatch = errors.New("preimage does not match")
|
ErrInvoicePreimageMismatch = errors.New("preimage does not match")
|
||||||
|
|
||||||
|
// ErrHTLCPreimageMissing is returned when trying to accept/settle an
|
||||||
|
// AMP HTLC but the HTLC-level preimage has not been set.
|
||||||
|
ErrHTLCPreimageMissing = errors.New("AMP htlc missing preimage")
|
||||||
|
|
||||||
|
// ErrHTLCPreimageMismatch is returned when trying to accept/settle an
|
||||||
|
// AMP HTLC but the HTLC-level preimage does not satisfying the
|
||||||
|
// HTLC-level payment hash.
|
||||||
|
ErrHTLCPreimageMismatch = errors.New("htlc preimage mismatch")
|
||||||
|
|
||||||
|
// ErrHTLCAlreadySettled is returned when trying to settle an invoice
|
||||||
|
// but HTLC already exists in the settled state.
|
||||||
|
ErrHTLCAlreadySettled = errors.New("htlc already settled")
|
||||||
|
|
||||||
// ErrInvoiceHasHtlcs is returned when attempting to insert an invoice
|
// ErrInvoiceHasHtlcs is returned when attempting to insert an invoice
|
||||||
// that already has HTLCs.
|
// that already has HTLCs.
|
||||||
ErrInvoiceHasHtlcs = errors.New("cannot add invoice with htlcs")
|
ErrInvoiceHasHtlcs = errors.New("cannot add invoice with htlcs")
|
||||||
@ -2108,10 +2121,25 @@ func updateHtlc(resolveTime time.Time, htlc *InvoiceHTLC,
|
|||||||
// already know the preimage is valid due to checks at
|
// already know the preimage is valid due to checks at
|
||||||
// the invoice level. For AMP HTLCs, verify that the
|
// the invoice level. For AMP HTLCs, verify that the
|
||||||
// per-HTLC preimage-hash pair is valid.
|
// per-HTLC preimage-hash pair is valid.
|
||||||
if setID != nil && !htlc.AMP.Preimage.Matches(htlc.AMP.Hash) {
|
switch {
|
||||||
return fmt.Errorf("AMP preimage mismatch, "+
|
|
||||||
"preimage=%v hash=%v", *htlc.AMP.Preimage,
|
// Non-AMP HTLCs can be settle immediately since we
|
||||||
htlc.AMP.Hash)
|
// already know the preimage is valid due to checks at
|
||||||
|
// the invoice level.
|
||||||
|
case setID == nil:
|
||||||
|
|
||||||
|
// At this popint, the setID is non-nil, meaning this is
|
||||||
|
// an AMP HTLC. We know that htlc.AMP cannot be nil,
|
||||||
|
// otherwise IsInHTLCSet would have returned false.
|
||||||
|
//
|
||||||
|
// Fail if an accepted AMP HTLC has no preimage.
|
||||||
|
case htlc.AMP.Preimage == nil:
|
||||||
|
return ErrHTLCPreimageMissing
|
||||||
|
|
||||||
|
// Fail if the accepted AMP HTLC has an invalid
|
||||||
|
// preimage.
|
||||||
|
case !htlc.AMP.Preimage.Matches(htlc.AMP.Hash):
|
||||||
|
return ErrHTLCPreimageMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
htlcState = HtlcStateSettled
|
htlcState = HtlcStateSettled
|
||||||
@ -2140,8 +2168,7 @@ func updateHtlc(resolveTime time.Time, htlc *InvoiceHTLC,
|
|||||||
// We should never find a settled HTLC on an invoice that isn't in
|
// We should never find a settled HTLC on an invoice that isn't in
|
||||||
// ContractSettled.
|
// ContractSettled.
|
||||||
if htlc.State == HtlcStateSettled {
|
if htlc.State == HtlcStateSettled {
|
||||||
return fmt.Errorf("cannot have a settled htlc with "+
|
return ErrHTLCAlreadySettled
|
||||||
"invoice in state %v", invState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch invState {
|
switch invState {
|
||||||
|
Loading…
Reference in New Issue
Block a user