2017-08-11 06:59:06 +02:00
|
|
|
// +build !rpctest
|
|
|
|
|
2016-12-14 00:32:44 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2017-10-04 01:41:19 +02:00
|
|
|
"fmt"
|
2018-09-12 16:33:46 +02:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
|
|
|
"io/ioutil"
|
2016-12-14 00:32:44 +01:00
|
|
|
"reflect"
|
2018-09-12 16:33:46 +02:00
|
|
|
"sync"
|
2016-12-14 00:32:44 +01:00
|
|
|
"testing"
|
2018-09-12 16:33:46 +02:00
|
|
|
"time"
|
2016-12-14 00:32:44 +01:00
|
|
|
|
2018-06-05 03:34:16 +02:00
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
|
|
"github.com/btcsuite/btcd/txscript"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/btcsuite/btcutil"
|
2018-09-12 16:33:46 +02:00
|
|
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
2018-07-31 09:17:17 +02:00
|
|
|
"github.com/lightningnetwork/lnd/lnwallet"
|
2016-12-14 00:32:44 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
outPoints = []wire.OutPoint{
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-01-05 22:56:27 +01:00
|
|
|
Hash: [chainhash.HashSize]byte{
|
2016-12-14 00:32:44 +01:00
|
|
|
0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
|
|
|
|
0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
|
|
|
0x2d, 0xe7, 0x93, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
|
|
|
|
0x1f, 0xb, 0x4c, 0xf9, 0x9e, 0xc5, 0x8c, 0xe9,
|
|
|
|
},
|
|
|
|
Index: 9,
|
|
|
|
},
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-01-05 22:56:27 +01:00
|
|
|
Hash: [chainhash.HashSize]byte{
|
2016-12-14 00:32:44 +01:00
|
|
|
0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
|
|
|
|
0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
|
|
|
|
0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
|
|
|
|
0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
|
|
|
|
},
|
|
|
|
Index: 49,
|
|
|
|
},
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-01-05 22:56:27 +01:00
|
|
|
Hash: [chainhash.HashSize]byte{
|
2016-12-14 00:32:44 +01:00
|
|
|
0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
|
|
|
|
0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
2017-10-09 03:15:34 +02:00
|
|
|
0x0d, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
|
2016-12-14 00:32:44 +01:00
|
|
|
0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
|
|
|
|
},
|
|
|
|
Index: 23,
|
|
|
|
},
|
2017-10-09 03:15:34 +02:00
|
|
|
{
|
|
|
|
Hash: [chainhash.HashSize]byte{
|
|
|
|
0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
|
|
|
|
0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
|
|
|
|
0x0d, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
|
|
|
|
0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
|
|
|
},
|
|
|
|
Index: 30,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Hash: [chainhash.HashSize]byte{
|
|
|
|
0x0d, 0xe7, 0x95, 0xe4, 0xfc, 0xd2, 0xc6, 0xda,
|
|
|
|
0xb7, 0x25, 0xb8, 0x4d, 0x63, 0x59, 0xe6, 0x96,
|
|
|
|
0x31, 0x13, 0xa1, 0x17, 0x81, 0xb6, 0x37, 0xd8,
|
|
|
|
0x1e, 0x0b, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
|
|
|
|
},
|
|
|
|
Index: 2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Hash: [chainhash.HashSize]byte{
|
|
|
|
0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
|
|
|
0x51, 0xb6, 0x37, 0xd8, 0x1f, 0x0b, 0x4c, 0xf9,
|
|
|
|
0x9e, 0xc5, 0x8c, 0xe9, 0xfc, 0xd2, 0xc6, 0xda,
|
|
|
|
0x2d, 0xe7, 0x93, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
|
|
|
|
},
|
|
|
|
Index: 9,
|
|
|
|
},
|
2016-12-14 00:32:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
keys = [][]byte{
|
2017-02-23 20:02:08 +01:00
|
|
|
{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
2016-12-14 00:32:44 +01:00
|
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
|
|
0xb4, 0x12, 0xa3,
|
|
|
|
},
|
2017-02-23 20:02:08 +01:00
|
|
|
{0x07, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
2016-12-14 00:32:44 +01:00
|
|
|
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
|
|
|
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
|
|
|
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
|
|
|
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
|
|
|
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
|
|
|
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
|
|
|
0xb4, 0x12, 0xa3,
|
|
|
|
},
|
2017-02-23 20:02:08 +01:00
|
|
|
{0x02, 0xce, 0x0b, 0x14, 0xfb, 0x84, 0x2b, 0x1b,
|
2016-12-14 00:32:44 +01:00
|
|
|
0xa5, 0x49, 0xfd, 0xd6, 0x75, 0xc9, 0x80, 0x75, 0xf1,
|
|
|
|
0x2e, 0x9c, 0x51, 0x0f, 0x8e, 0xf5, 0x2b, 0xd0, 0x21,
|
|
|
|
0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
signDescriptors = []lnwallet.SignDescriptor{
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-07-31 00:54:22 +02:00
|
|
|
SingleTweak: []byte{
|
2016-12-14 00:32:44 +01:00
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
},
|
|
|
|
WitnessScript: []byte{
|
|
|
|
0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde,
|
|
|
|
0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2,
|
|
|
|
0xef, 0xb5, 0x71, 0x48,
|
|
|
|
},
|
|
|
|
Output: &wire.TxOut{
|
|
|
|
Value: 5000000000,
|
|
|
|
PkScript: []byte{
|
|
|
|
0x41, // OP_DATA_65
|
|
|
|
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
|
|
|
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
|
|
|
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
|
|
|
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
|
|
|
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
|
|
|
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
|
|
|
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
|
|
|
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
|
|
|
0xa6, // 65-byte signature
|
|
|
|
0xac, // OP_CHECKSIG
|
|
|
|
},
|
|
|
|
},
|
|
|
|
HashType: txscript.SigHashAll,
|
|
|
|
},
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-07-31 00:54:22 +02:00
|
|
|
SingleTweak: []byte{
|
2016-12-14 00:32:44 +01:00
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
},
|
|
|
|
WitnessScript: []byte{
|
|
|
|
0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde,
|
|
|
|
0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2,
|
|
|
|
0xef, 0xb5, 0x71, 0x48,
|
|
|
|
},
|
|
|
|
Output: &wire.TxOut{
|
|
|
|
Value: 5000000000,
|
|
|
|
PkScript: []byte{
|
|
|
|
0x41, // OP_DATA_65
|
|
|
|
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
|
|
|
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
|
|
|
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
|
|
|
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
|
|
|
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
|
|
|
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
|
|
|
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
|
|
|
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
|
|
|
0xa6, // 65-byte signature
|
|
|
|
0xac, // OP_CHECKSIG
|
|
|
|
},
|
|
|
|
},
|
|
|
|
HashType: txscript.SigHashAll,
|
|
|
|
},
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-07-31 00:54:22 +02:00
|
|
|
SingleTweak: []byte{
|
2016-12-14 00:32:44 +01:00
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
0x02, 0x02, 0x02, 0x02, 0x02,
|
|
|
|
},
|
|
|
|
WitnessScript: []byte{
|
|
|
|
0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde,
|
|
|
|
0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2,
|
|
|
|
0xef, 0xb5, 0x71, 0x48,
|
|
|
|
},
|
|
|
|
Output: &wire.TxOut{
|
|
|
|
Value: 5000000000,
|
|
|
|
PkScript: []byte{
|
|
|
|
0x41, // OP_DATA_65
|
|
|
|
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
|
|
|
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
|
|
|
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
|
|
|
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
|
|
|
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
|
|
|
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
|
|
|
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
|
|
|
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
|
|
|
0xa6, // 65-byte signature
|
|
|
|
0xac, // OP_CHECKSIG
|
|
|
|
},
|
|
|
|
},
|
|
|
|
HashType: txscript.SigHashAll,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
kidOutputs = []kidOutput{
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-09-29 03:32:44 +02:00
|
|
|
breachedOutput: breachedOutput{
|
|
|
|
amt: btcutil.Amount(13e7),
|
2017-10-09 03:15:34 +02:00
|
|
|
outpoint: outPoints[1],
|
2017-09-29 03:32:44 +02:00
|
|
|
witnessType: lnwallet.CommitmentTimeLock,
|
|
|
|
},
|
2017-10-09 03:15:34 +02:00
|
|
|
originChanPoint: outPoints[0],
|
|
|
|
blocksToMaturity: uint32(42),
|
|
|
|
confHeight: uint32(1000),
|
2016-12-14 00:32:44 +01:00
|
|
|
},
|
|
|
|
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-09-29 03:32:44 +02:00
|
|
|
breachedOutput: breachedOutput{
|
|
|
|
amt: btcutil.Amount(24e7),
|
2017-10-09 03:15:34 +02:00
|
|
|
outpoint: outPoints[2],
|
2017-09-29 03:32:44 +02:00
|
|
|
witnessType: lnwallet.CommitmentTimeLock,
|
|
|
|
},
|
2017-05-05 00:45:31 +02:00
|
|
|
originChanPoint: outPoints[0],
|
2017-10-09 03:15:34 +02:00
|
|
|
blocksToMaturity: uint32(42),
|
|
|
|
confHeight: uint32(1000),
|
2016-12-14 00:32:44 +01:00
|
|
|
},
|
|
|
|
|
2017-02-23 20:02:08 +01:00
|
|
|
{
|
2017-09-29 03:32:44 +02:00
|
|
|
breachedOutput: breachedOutput{
|
|
|
|
amt: btcutil.Amount(2e5),
|
2017-10-09 03:15:34 +02:00
|
|
|
outpoint: outPoints[3],
|
2017-09-29 03:32:44 +02:00
|
|
|
witnessType: lnwallet.CommitmentTimeLock,
|
|
|
|
},
|
2017-10-09 03:15:34 +02:00
|
|
|
originChanPoint: outPoints[0],
|
|
|
|
blocksToMaturity: uint32(28),
|
|
|
|
confHeight: uint32(500),
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
breachedOutput: breachedOutput{
|
|
|
|
amt: btcutil.Amount(10e6),
|
|
|
|
outpoint: outPoints[4],
|
|
|
|
witnessType: lnwallet.CommitmentTimeLock,
|
|
|
|
},
|
|
|
|
originChanPoint: outPoints[0],
|
|
|
|
blocksToMaturity: uint32(28),
|
|
|
|
confHeight: uint32(500),
|
2016-12-14 00:32:44 +01:00
|
|
|
},
|
|
|
|
}
|
2017-09-29 03:32:44 +02:00
|
|
|
|
|
|
|
babyOutputs = []babyOutput{
|
|
|
|
{
|
2017-10-09 03:15:34 +02:00
|
|
|
kidOutput: kidOutputs[1],
|
2017-09-29 03:32:44 +02:00
|
|
|
expiry: 3829,
|
|
|
|
timeoutTx: timeoutTx,
|
|
|
|
},
|
|
|
|
{
|
2017-10-09 03:15:34 +02:00
|
|
|
kidOutput: kidOutputs[2],
|
|
|
|
expiry: 4,
|
2017-09-29 03:32:44 +02:00
|
|
|
timeoutTx: timeoutTx,
|
|
|
|
},
|
|
|
|
{
|
2017-10-09 03:15:34 +02:00
|
|
|
kidOutput: kidOutputs[3],
|
2017-09-29 03:32:44 +02:00
|
|
|
expiry: 4,
|
|
|
|
timeoutTx: timeoutTx,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dummy timeout tx used to test serialization, borrowed from btcd
|
|
|
|
// msgtx_test
|
|
|
|
timeoutTx = &wire.MsgTx{
|
|
|
|
Version: 1,
|
|
|
|
TxIn: []*wire.TxIn{
|
|
|
|
{
|
|
|
|
PreviousOutPoint: wire.OutPoint{
|
|
|
|
Hash: chainhash.Hash{
|
|
|
|
0xa5, 0x33, 0x52, 0xd5, 0x13, 0x57, 0x66, 0xf0,
|
|
|
|
0x30, 0x76, 0x59, 0x74, 0x18, 0x26, 0x3d, 0xa2,
|
|
|
|
0xd9, 0xc9, 0x58, 0x31, 0x59, 0x68, 0xfe, 0xa8,
|
|
|
|
0x23, 0x52, 0x94, 0x67, 0x48, 0x1f, 0xf9, 0xcd,
|
|
|
|
},
|
|
|
|
Index: 19,
|
|
|
|
},
|
|
|
|
SignatureScript: []byte{},
|
|
|
|
Witness: [][]byte{
|
|
|
|
{ // 70-byte signature
|
|
|
|
0x30, 0x43, 0x02, 0x1f, 0x4d, 0x23, 0x81, 0xdc,
|
|
|
|
0x97, 0xf1, 0x82, 0xab, 0xd8, 0x18, 0x5f, 0x51,
|
|
|
|
0x75, 0x30, 0x18, 0x52, 0x32, 0x12, 0xf5, 0xdd,
|
|
|
|
0xc0, 0x7c, 0xc4, 0xe6, 0x3a, 0x8d, 0xc0, 0x36,
|
|
|
|
0x58, 0xda, 0x19, 0x02, 0x20, 0x60, 0x8b, 0x5c,
|
|
|
|
0x4d, 0x92, 0xb8, 0x6b, 0x6d, 0xe7, 0xd7, 0x8e,
|
|
|
|
0xf2, 0x3a, 0x2f, 0xa7, 0x35, 0xbc, 0xb5, 0x9b,
|
|
|
|
0x91, 0x4a, 0x48, 0xb0, 0xe1, 0x87, 0xc5, 0xe7,
|
|
|
|
0x56, 0x9a, 0x18, 0x19, 0x70, 0x01,
|
|
|
|
},
|
|
|
|
{ // 33-byte serialize pub key
|
|
|
|
0x03, 0x07, 0xea, 0xd0, 0x84, 0x80, 0x7e, 0xb7,
|
|
|
|
0x63, 0x46, 0xdf, 0x69, 0x77, 0x00, 0x0c, 0x89,
|
|
|
|
0x39, 0x2f, 0x45, 0xc7, 0x64, 0x25, 0xb2, 0x61,
|
|
|
|
0x81, 0xf5, 0x21, 0xd7, 0xf3, 0x70, 0x06, 0x6a,
|
|
|
|
0x8f,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Sequence: 0xffffffff,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
TxOut: []*wire.TxOut{
|
|
|
|
{
|
|
|
|
Value: 395019,
|
|
|
|
PkScript: []byte{ // p2wkh output
|
|
|
|
0x00, // Version 0 witness program
|
|
|
|
0x14, // OP_DATA_20
|
|
|
|
0x9d, 0xda, 0xc6, 0xf3, 0x9d, 0x51, 0xe0, 0x39,
|
|
|
|
0x8e, 0x53, 0x2a, 0x22, 0xc4, 0x1b, 0xa1, 0x89,
|
|
|
|
0x40, 0x6a, 0x85, 0x23, // 20-byte pub key hash
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2018-09-12 16:33:46 +02:00
|
|
|
|
|
|
|
testChanPoint = wire.OutPoint{}
|
|
|
|
defaultTestTimeout = 5 * time.Second
|
2016-12-14 00:32:44 +01:00
|
|
|
)
|
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
func init() {
|
2017-10-04 01:41:19 +02:00
|
|
|
// Finish initializing our test vectors by parsing the desired public keys and
|
|
|
|
// properly populating the sign descriptors of all baby and kid outputs.
|
2017-09-29 03:32:44 +02:00
|
|
|
for i := range signDescriptors {
|
2016-12-14 00:32:44 +01:00
|
|
|
pk, err := btcec.ParsePubKey(keys[i], btcec.S256())
|
|
|
|
if err != nil {
|
2017-10-04 01:41:19 +02:00
|
|
|
panic(fmt.Sprintf("unable to parse pub key during init: %v", err))
|
2016-12-14 00:32:44 +01:00
|
|
|
}
|
2018-02-18 00:29:01 +01:00
|
|
|
signDescriptors[i].KeyDesc.PubKey = pk
|
2017-09-29 03:32:44 +02:00
|
|
|
|
|
|
|
}
|
2017-10-09 03:15:34 +02:00
|
|
|
for i := range kidOutputs {
|
|
|
|
isd := i % len(signDescriptors)
|
|
|
|
kidOutputs[i].signDesc = signDescriptors[isd]
|
2016-12-14 00:32:44 +01:00
|
|
|
}
|
|
|
|
|
2017-10-09 03:15:34 +02:00
|
|
|
for i := range babyOutputs {
|
|
|
|
isd := i % len(signDescriptors)
|
|
|
|
babyOutputs[i].kidOutput.signDesc = signDescriptors[isd]
|
2016-12-14 00:32:44 +01:00
|
|
|
}
|
|
|
|
|
2017-10-09 03:15:34 +02:00
|
|
|
initIncubateTests()
|
2016-12-14 00:32:44 +01:00
|
|
|
}
|
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
func TestKidOutputSerialization(t *testing.T) {
|
2018-09-05 15:39:01 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
for i, kid := range kidOutputs {
|
|
|
|
var b bytes.Buffer
|
|
|
|
if err := kid.Encode(&b); err != nil {
|
|
|
|
t.Fatalf("Encode #%d: unable to serialize "+
|
|
|
|
"kid output: %v", i, err)
|
|
|
|
}
|
2016-12-14 00:32:44 +01:00
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
var deserializedKid kidOutput
|
|
|
|
if err := deserializedKid.Decode(&b); err != nil {
|
|
|
|
t.Fatalf("Decode #%d: unable to deserialize "+
|
|
|
|
"kid output: %v", i, err)
|
|
|
|
}
|
2016-12-14 00:32:44 +01:00
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
if !reflect.DeepEqual(kid, deserializedKid) {
|
|
|
|
t.Fatalf("DeepEqual #%d: unexpected kidOutput, "+
|
|
|
|
"want %+v, got %+v",
|
|
|
|
i, kid, deserializedKid)
|
|
|
|
}
|
2016-12-14 00:32:44 +01:00
|
|
|
}
|
2017-09-29 03:32:44 +02:00
|
|
|
}
|
2016-12-14 00:32:44 +01:00
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
func TestBabyOutputSerialization(t *testing.T) {
|
2018-09-05 15:39:01 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
2017-09-29 03:32:44 +02:00
|
|
|
for i, baby := range babyOutputs {
|
|
|
|
var b bytes.Buffer
|
|
|
|
if err := baby.Encode(&b); err != nil {
|
|
|
|
t.Fatalf("Encode #%d: unable to serialize "+
|
|
|
|
"baby output: %v", i, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var deserializedBaby babyOutput
|
|
|
|
if err := deserializedBaby.Decode(&b); err != nil {
|
|
|
|
t.Fatalf("Decode #%d: unable to deserialize "+
|
|
|
|
"baby output: %v", i, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(baby, deserializedBaby) {
|
|
|
|
t.Fatalf("DeepEqual #%d: unexpected babyOutput, "+
|
|
|
|
"want %+v, got %+v",
|
|
|
|
i, baby, deserializedBaby)
|
|
|
|
}
|
2016-12-14 00:32:44 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2018-09-12 16:33:46 +02:00
|
|
|
|
|
|
|
type nurseryTestContext struct {
|
|
|
|
nursery *utxoNursery
|
|
|
|
notifier *nurseryMockNotifier
|
|
|
|
publishChan chan chainhash.Hash
|
|
|
|
store *nurseryStoreInterceptor
|
|
|
|
}
|
|
|
|
|
|
|
|
func createNurseryTestContext(t *testing.T) *nurseryTestContext {
|
|
|
|
// Create a temporary database and connect nurseryStore to it. The
|
|
|
|
// alternative, mocking nurseryStore, is not chosen because there is
|
|
|
|
// still considerable logic in the store.
|
|
|
|
|
|
|
|
tempDirName, err := ioutil.TempDir("", "channeldb")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create temp dir: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cdb, err := channeldb.Open(tempDirName)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to open channeldb: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
store, err := newNurseryStore(&chainhash.Hash{}, cdb)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap the store in an inceptor to be able to wait for events in this
|
|
|
|
// test.
|
|
|
|
storeIntercepter := newNurseryStoreInterceptor(store)
|
|
|
|
|
|
|
|
notifier := newNurseryMockNotifier(t)
|
|
|
|
|
|
|
|
cfg := NurseryConfig{
|
|
|
|
Notifier: notifier,
|
|
|
|
DB: cdb,
|
|
|
|
Store: storeIntercepter,
|
|
|
|
ChainIO: &mockChainIO{},
|
|
|
|
GenSweepScript: func() ([]byte, error) {
|
|
|
|
return []byte{}, nil
|
|
|
|
},
|
|
|
|
Estimator: &mockFeeEstimator{},
|
|
|
|
Signer: &nurseryMockSigner{},
|
|
|
|
}
|
|
|
|
|
|
|
|
publishChan := make(chan chainhash.Hash, 1)
|
|
|
|
cfg.PublishTransaction = func(tx *wire.MsgTx) error {
|
|
|
|
t.Logf("Publishing tx %v", tx.TxHash())
|
|
|
|
publishChan <- tx.TxHash()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
nursery := newUtxoNursery(&cfg)
|
|
|
|
nursery.Start()
|
|
|
|
|
|
|
|
return &nurseryTestContext{
|
|
|
|
nursery: nursery,
|
|
|
|
notifier: notifier,
|
|
|
|
store: storeIntercepter,
|
|
|
|
publishChan: publishChan,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createOutgoingRes(onLocalCommitment bool) *lnwallet.OutgoingHtlcResolution {
|
|
|
|
// Set up an outgoing htlc resolution to hand off to nursery.
|
|
|
|
closeTx := &wire.MsgTx{}
|
|
|
|
|
|
|
|
htlcOp := wire.OutPoint{
|
|
|
|
Hash: closeTx.TxHash(),
|
|
|
|
Index: 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
outgoingRes := lnwallet.OutgoingHtlcResolution{
|
|
|
|
Expiry: 125,
|
|
|
|
SweepSignDesc: lnwallet.SignDescriptor{
|
|
|
|
Output: &wire.TxOut{
|
|
|
|
Value: 10000,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
CsvDelay: 2,
|
|
|
|
}
|
|
|
|
|
|
|
|
if onLocalCommitment {
|
|
|
|
timeoutTx := &wire.MsgTx{
|
|
|
|
TxIn: []*wire.TxIn{
|
|
|
|
{
|
|
|
|
PreviousOutPoint: htlcOp,
|
|
|
|
Witness: [][]byte{{}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
TxOut: []*wire.TxOut{
|
|
|
|
{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
outgoingRes.SignedTimeoutTx = timeoutTx
|
|
|
|
} else {
|
|
|
|
outgoingRes.ClaimOutpoint = htlcOp
|
|
|
|
}
|
|
|
|
|
|
|
|
return &outgoingRes
|
|
|
|
}
|
|
|
|
|
|
|
|
func incubateTestOutput(t *testing.T, nursery *utxoNursery,
|
|
|
|
onLocalCommitment bool) *lnwallet.OutgoingHtlcResolution {
|
|
|
|
|
|
|
|
outgoingRes := createOutgoingRes(onLocalCommitment)
|
|
|
|
|
|
|
|
// Hand off to nursery.
|
|
|
|
err := nursery.IncubateOutputs(
|
|
|
|
testChanPoint,
|
|
|
|
nil,
|
|
|
|
[]lnwallet.OutgoingHtlcResolution{*outgoingRes},
|
|
|
|
nil, 0,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IncubateOutputs is executing synchronously and we expect the output
|
|
|
|
// to immediately show up in the report.
|
|
|
|
expectedStage := uint32(2)
|
|
|
|
if onLocalCommitment {
|
|
|
|
expectedStage = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(joostjager): Nursery is currently not reporting this limbo
|
|
|
|
// balance.
|
|
|
|
if onLocalCommitment {
|
|
|
|
assertNurseryReport(t, nursery, 1, expectedStage)
|
|
|
|
}
|
|
|
|
|
|
|
|
return outgoingRes
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertNurseryReport(t *testing.T, nursery *utxoNursery,
|
|
|
|
expectedNofHtlcs int, expectedStage uint32) {
|
|
|
|
report, err := nursery.NurseryReport(&testChanPoint)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(report.htlcs) != expectedNofHtlcs {
|
|
|
|
t.Fatalf("expected %v outputs to be reported, but report "+
|
|
|
|
"only contains %v", expectedNofHtlcs, len(report.htlcs))
|
|
|
|
}
|
|
|
|
htlcReport := report.htlcs[0]
|
|
|
|
if htlcReport.stage != expectedStage {
|
|
|
|
t.Fatalf("expected htlc be advanced to stage %v, but it is "+
|
|
|
|
"reported in stage %v", expectedStage, htlcReport.stage)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertNurseryReportUnavailable(t *testing.T, nursery *utxoNursery) {
|
|
|
|
_, err := nursery.NurseryReport(&testChanPoint)
|
|
|
|
if err != ErrContractNotFound {
|
|
|
|
t.Fatal("expected report to be unavailable")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNurseryOutgoingHtlcSuccessOnLocal(t *testing.T) {
|
|
|
|
ctx := createNurseryTestContext(t)
|
|
|
|
|
|
|
|
outgoingRes := incubateTestOutput(t, ctx.nursery, true)
|
|
|
|
|
|
|
|
// Notify arrival of block where HTLC CLTV expires.
|
|
|
|
ctx.notifier.notifyEpoch(125)
|
|
|
|
|
|
|
|
// This should trigger nursery to publish the timeout tx.
|
|
|
|
select {
|
|
|
|
case <-ctx.publishChan:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
t.Fatalf("tx not published")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Confirm the timeout tx. This should promote the HTLC to KNDR state.
|
|
|
|
timeoutTxHash := outgoingRes.SignedTimeoutTx.TxHash()
|
|
|
|
if err := ctx.notifier.confirmTx(&timeoutTxHash, 126); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for output to be promoted in store to KNDR.
|
|
|
|
select {
|
|
|
|
case <-ctx.store.cribToKinderChan:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
t.Fatalf("output not promoted to KNDR")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify arrival of block where second level HTLC unlocks.
|
|
|
|
ctx.notifier.notifyEpoch(128)
|
|
|
|
|
|
|
|
// Check final sweep into wallet.
|
|
|
|
testSweep(t, ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNurseryOutgoingHtlcSuccessOnRemote(t *testing.T) {
|
|
|
|
ctx := createNurseryTestContext(t)
|
|
|
|
|
|
|
|
outgoingRes := incubateTestOutput(t, ctx.nursery, false)
|
|
|
|
|
|
|
|
// Notify confirmation of the commitment tx. Is only listened to when
|
|
|
|
// resolving remote commitment tx.
|
|
|
|
//
|
|
|
|
// TODO(joostjager): This is probably not correct?
|
|
|
|
err := ctx.notifier.confirmTx(&outgoingRes.ClaimOutpoint.Hash, 124)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for output to be promoted from PSCL to KNDR.
|
|
|
|
select {
|
|
|
|
case <-ctx.store.preschoolToKinderChan:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
t.Fatalf("output not promoted to KNDR")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify arrival of block where HTLC CLTV expires.
|
|
|
|
ctx.notifier.notifyEpoch(125)
|
|
|
|
|
|
|
|
// Check final sweep into wallet.
|
|
|
|
testSweep(t, ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testSweep(t *testing.T, ctx *nurseryTestContext) {
|
|
|
|
// Wait for nursery to publish the sweep tx.
|
|
|
|
var sweepTxHash chainhash.Hash
|
|
|
|
select {
|
|
|
|
case sweepTxHash = <-ctx.publishChan:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
t.Fatalf("sweep tx not published")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify stage in nursery report. HTLCs should now both still be in
|
|
|
|
// stage two.
|
|
|
|
assertNurseryReport(t, ctx.nursery, 1, 2)
|
|
|
|
|
|
|
|
// Confirm the sweep tx.
|
|
|
|
err := ctx.notifier.confirmTx(&sweepTxHash, 129)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for output to be promoted in store to GRAD.
|
|
|
|
select {
|
|
|
|
case <-ctx.store.graduateKinderChan:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
t.Fatalf("output not graduated")
|
|
|
|
}
|
|
|
|
|
|
|
|
// As there only was one output to graduate, we expect the channel to be
|
|
|
|
// closed and no report available anymore.
|
|
|
|
assertNurseryReportUnavailable(t, ctx.nursery)
|
|
|
|
}
|
|
|
|
|
|
|
|
type nurseryStoreInterceptor struct {
|
|
|
|
ns NurseryStore
|
|
|
|
|
|
|
|
// TODO(joostjager): put more useful info through these channels.
|
|
|
|
cribToKinderChan chan struct{}
|
|
|
|
cribToRemoteSpendChan chan struct{}
|
|
|
|
graduateKinderChan chan struct{}
|
|
|
|
preschoolToKinderChan chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newNurseryStoreInterceptor(ns NurseryStore) *nurseryStoreInterceptor {
|
|
|
|
return &nurseryStoreInterceptor{
|
|
|
|
ns: ns,
|
|
|
|
cribToKinderChan: make(chan struct{}),
|
|
|
|
cribToRemoteSpendChan: make(chan struct{}),
|
|
|
|
graduateKinderChan: make(chan struct{}),
|
|
|
|
preschoolToKinderChan: make(chan struct{}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) Incubate(kidOutputs []kidOutput,
|
|
|
|
babyOutputs []babyOutput) error {
|
|
|
|
|
|
|
|
return i.ns.Incubate(kidOutputs, babyOutputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) CribToKinder(babyOutput *babyOutput) error {
|
|
|
|
err := i.ns.CribToKinder(babyOutput)
|
|
|
|
|
|
|
|
i.cribToKinderChan <- struct{}{}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) PreschoolToKinder(kidOutput *kidOutput) error {
|
|
|
|
err := i.ns.PreschoolToKinder(kidOutput)
|
|
|
|
|
|
|
|
i.preschoolToKinderChan <- struct{}{}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) GraduateKinder(height uint32) error {
|
|
|
|
err := i.ns.GraduateKinder(height)
|
|
|
|
|
|
|
|
i.graduateKinderChan <- struct{}{}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) FetchPreschools() ([]kidOutput, error) {
|
|
|
|
return i.ns.FetchPreschools()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) FetchClass(height uint32) (*wire.MsgTx,
|
|
|
|
[]kidOutput, []babyOutput, error) {
|
|
|
|
|
|
|
|
return i.ns.FetchClass(height)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) FinalizeKinder(height uint32,
|
|
|
|
tx *wire.MsgTx) error {
|
|
|
|
|
|
|
|
return i.ns.FinalizeKinder(height, tx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) LastFinalizedHeight() (uint32, error) {
|
|
|
|
return i.ns.LastFinalizedHeight()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) GraduateHeight(height uint32) error {
|
|
|
|
return i.ns.GraduateHeight(height)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) LastGraduatedHeight() (uint32, error) {
|
|
|
|
return i.ns.LastGraduatedHeight()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) HeightsBelowOrEqual(height uint32) (
|
|
|
|
[]uint32, error) {
|
|
|
|
|
|
|
|
return i.ns.HeightsBelowOrEqual(height)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) ForChanOutputs(chanPoint *wire.OutPoint,
|
|
|
|
callback func([]byte, []byte) error) error {
|
|
|
|
|
|
|
|
return i.ns.ForChanOutputs(chanPoint, callback)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) ListChannels() ([]wire.OutPoint, error) {
|
|
|
|
return i.ns.ListChannels()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) IsMatureChannel(chanPoint *wire.OutPoint) (
|
|
|
|
bool, error) {
|
|
|
|
|
|
|
|
return i.ns.IsMatureChannel(chanPoint)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *nurseryStoreInterceptor) RemoveChannel(chanPoint *wire.OutPoint) error {
|
|
|
|
return i.ns.RemoveChannel(chanPoint)
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockFeeEstimator struct{}
|
|
|
|
|
|
|
|
func (m *mockFeeEstimator) EstimateFeePerKW(
|
|
|
|
numBlocks uint32) (lnwallet.SatPerKWeight, error) {
|
|
|
|
|
|
|
|
return lnwallet.SatPerKWeight(10000), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockFeeEstimator) Start() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (m *mockFeeEstimator) Stop() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type nurseryMockSigner struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockSigner) SignOutputRaw(tx *wire.MsgTx,
|
|
|
|
signDesc *lnwallet.SignDescriptor) ([]byte, error) {
|
|
|
|
|
|
|
|
return []byte{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockSigner) ComputeInputScript(tx *wire.MsgTx,
|
|
|
|
signDesc *lnwallet.SignDescriptor) (*lnwallet.InputScript, error) {
|
|
|
|
|
|
|
|
return &lnwallet.InputScript{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type nurseryMockNotifier struct {
|
|
|
|
confChannel map[chainhash.Hash]chan *chainntnfs.TxConfirmation
|
|
|
|
epochChan chan *chainntnfs.BlockEpoch
|
|
|
|
spendChan chan *chainntnfs.SpendDetail
|
|
|
|
mutex sync.RWMutex
|
|
|
|
t *testing.T
|
|
|
|
}
|
|
|
|
|
|
|
|
func newNurseryMockNotifier(t *testing.T) *nurseryMockNotifier {
|
|
|
|
return &nurseryMockNotifier{
|
|
|
|
confChannel: make(map[chainhash.Hash]chan *chainntnfs.TxConfirmation),
|
|
|
|
epochChan: make(chan *chainntnfs.BlockEpoch),
|
|
|
|
spendChan: make(chan *chainntnfs.SpendDetail),
|
|
|
|
t: t,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) notifyEpoch(height int32) {
|
|
|
|
select {
|
|
|
|
case m.epochChan <- &chainntnfs.BlockEpoch{
|
|
|
|
Height: height,
|
|
|
|
}:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
m.t.Fatal("epoch event not consumed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) confirmTx(txid *chainhash.Hash, height uint32) error {
|
|
|
|
confirm := &chainntnfs.TxConfirmation{
|
|
|
|
BlockHeight: height,
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case m.getConfChannel(txid) <- confirm:
|
|
|
|
case <-time.After(defaultTestTimeout):
|
|
|
|
return fmt.Errorf("confirmation not consumed")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
|
|
|
|
_ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return &chainntnfs.ConfirmationEvent{
|
|
|
|
Confirmed: m.getConfChannel(txid),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) getConfChannel(
|
|
|
|
txid *chainhash.Hash) chan *chainntnfs.TxConfirmation {
|
|
|
|
|
|
|
|
m.mutex.Lock()
|
|
|
|
defer m.mutex.Unlock()
|
|
|
|
|
|
|
|
channel, ok := m.confChannel[*txid]
|
|
|
|
if ok {
|
|
|
|
return channel
|
|
|
|
}
|
|
|
|
channel = make(chan *chainntnfs.TxConfirmation)
|
|
|
|
m.confChannel[*txid] = channel
|
|
|
|
|
|
|
|
return channel
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) RegisterBlockEpochNtfn(
|
|
|
|
bestBlock *chainntnfs.BlockEpoch) (*chainntnfs.BlockEpochEvent, error) {
|
|
|
|
return &chainntnfs.BlockEpochEvent{
|
|
|
|
Epochs: m.epochChan,
|
|
|
|
Cancel: func() {},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) Start() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) Stop() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *nurseryMockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
|
|
|
_ []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
|
|
|
|
|
|
|
return &chainntnfs.SpendEvent{
|
|
|
|
Spend: m.spendChan,
|
|
|
|
Cancel: func() {},
|
|
|
|
}, nil
|
|
|
|
}
|