• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 9915780197

13 Jul 2024 12:30AM UTC coverage: 49.268% (-9.1%) from 58.413%
9915780197

push

github

web-flow
Merge pull request #8653 from ProofOfKeags/fn-prim

DynComms [0/n]: `fn` package additions

92837 of 188433 relevant lines covered (49.27%)

1.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lnwallet/test_utils.go
1
package lnwallet
2

3
import (
4
        "crypto/rand"
5
        "encoding/binary"
6
        "encoding/hex"
7
        "io"
8
        prand "math/rand"
9
        "net"
10
        "testing"
11

12
        "github.com/btcsuite/btcd/btcec/v2"
13
        "github.com/btcsuite/btcd/btcutil"
14
        "github.com/btcsuite/btcd/chaincfg/chainhash"
15
        "github.com/btcsuite/btcd/wire"
16
        "github.com/lightningnetwork/lnd/channeldb"
17
        "github.com/lightningnetwork/lnd/input"
18
        "github.com/lightningnetwork/lnd/keychain"
19
        "github.com/lightningnetwork/lnd/lntypes"
20
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
21
        "github.com/lightningnetwork/lnd/lnwire"
22
        "github.com/lightningnetwork/lnd/shachain"
23
        "github.com/stretchr/testify/require"
24
)
25

26
var (
27
        // For simplicity a single priv key controls all of our test outputs.
28
        testWalletPrivKey = []byte{
29
                0x2b, 0xd8, 0x06, 0xc9, 0x7f, 0x0e, 0x00, 0xaf,
30
                0x1a, 0x1f, 0xc3, 0x32, 0x8f, 0xa7, 0x63, 0xa9,
31
                0x26, 0x97, 0x23, 0xc8, 0xdb, 0x8f, 0xac, 0x4f,
32
                0x93, 0xaf, 0x71, 0xdb, 0x18, 0x6d, 0x6e, 0x90,
33
        }
34

35
        // We're alice :)
36
        bobsPrivKey = []byte{
37
                0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
38
                0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
39
                0xd, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
40
                0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
41
        }
42

43
        // Use a hard-coded HD seed.
44
        testHdSeed = chainhash.Hash{
45
                0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
46
                0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
47
                0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
48
                0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
49
        }
50

51
        // A serializable txn for testing funding txn.
52
        testTx = &wire.MsgTx{
53
                Version: 1,
54
                TxIn: []*wire.TxIn{
55
                        {
56
                                PreviousOutPoint: wire.OutPoint{
57
                                        Hash:  chainhash.Hash{},
58
                                        Index: 0xffffffff,
59
                                },
60
                                SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62},
61
                                Sequence:        0xffffffff,
62
                        },
63
                },
64
                TxOut: []*wire.TxOut{
65
                        {
66
                                Value: 5000000000,
67
                                PkScript: []byte{
68
                                        0x41, // OP_DATA_65
69
                                        0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
70
                                        0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
71
                                        0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
72
                                        0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
73
                                        0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
74
                                        0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
75
                                        0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
76
                                        0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
77
                                        0xa6, // 65-byte signature
78
                                        0xac, // OP_CHECKSIG
79
                                },
80
                        },
81
                },
82
                LockTime: 5,
83
        }
84

85
        // A valid, DER-encoded signature (taken from btcec unit tests).
86
        testSigBytes = []byte{
87
                0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
88
                0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3,
89
                0xa1, 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32,
90
                0xe9, 0xd6, 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab,
91
                0x5f, 0xb8, 0xcd, 0x41, 0x02, 0x20, 0x18, 0x15,
92
                0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60,
93
                0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
94
                0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
95
                0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
96
        }
97

98
        aliceDustLimit = btcutil.Amount(200)
99
        bobDustLimit   = btcutil.Amount(1300)
100

101
        testChannelCapacity float64 = 10
102
)
103

104
// CreateTestChannels creates to fully populated channels to be used within
105
// testing fixtures. The channels will be returned as if the funding process
106
// has just completed.  The channel itself is funded with 10 BTC, with 5 BTC
107
// allocated to each side. Within the channel, Alice is the initiator. If
108
// tweaklessCommits is true, then the commits within the channels will use the
109
// new format, otherwise the legacy format.
110
func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType,
111
        dbModifiers ...channeldb.OptionModifier) (*LightningChannel,
112
        *LightningChannel, error) {
×
113

×
114
        channelCapacity, err := btcutil.NewAmount(testChannelCapacity)
×
115
        if err != nil {
×
116
                return nil, nil, err
×
117
        }
×
118

119
        channelBal := channelCapacity / 2
×
120
        csvTimeoutAlice := uint32(5)
×
121
        csvTimeoutBob := uint32(4)
×
122
        isAliceInitiator := true
×
123

×
124
        prevOut := &wire.OutPoint{
×
125
                Hash:  chainhash.Hash(testHdSeed),
×
126
                Index: prand.Uint32(),
×
127
        }
×
128
        fundingTxIn := wire.NewTxIn(prevOut, nil, nil)
×
129

×
130
        // For each party, we'll create a distinct set of keys in order to
×
131
        // emulate the typical set up with live channels.
×
132
        var (
×
133
                aliceKeys []*btcec.PrivateKey
×
134
                bobKeys   []*btcec.PrivateKey
×
135
        )
×
136
        for i := 0; i < 5; i++ {
×
137
                key := make([]byte, len(testWalletPrivKey))
×
138
                copy(key[:], testWalletPrivKey[:])
×
139
                key[0] ^= byte(i + 1)
×
140

×
141
                aliceKey, _ := btcec.PrivKeyFromBytes(key)
×
142
                aliceKeys = append(aliceKeys, aliceKey)
×
143

×
144
                key = make([]byte, len(bobsPrivKey))
×
145
                copy(key[:], bobsPrivKey)
×
146
                key[0] ^= byte(i + 1)
×
147

×
148
                bobKey, _ := btcec.PrivKeyFromBytes(key)
×
149
                bobKeys = append(bobKeys, bobKey)
×
150
        }
×
151

152
        aliceCfg := channeldb.ChannelConfig{
×
153
                ChannelConstraints: channeldb.ChannelConstraints{
×
154
                        DustLimit:        aliceDustLimit,
×
155
                        MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity),
×
156
                        ChanReserve:      channelCapacity / 100,
×
157
                        MinHTLC:          0,
×
158
                        MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
×
159
                        CsvDelay:         uint16(csvTimeoutAlice),
×
160
                },
×
161
                MultiSigKey: keychain.KeyDescriptor{
×
162
                        PubKey: aliceKeys[0].PubKey(),
×
163
                },
×
164
                RevocationBasePoint: keychain.KeyDescriptor{
×
165
                        PubKey: aliceKeys[1].PubKey(),
×
166
                },
×
167
                PaymentBasePoint: keychain.KeyDescriptor{
×
168
                        PubKey: aliceKeys[2].PubKey(),
×
169
                },
×
170
                DelayBasePoint: keychain.KeyDescriptor{
×
171
                        PubKey: aliceKeys[3].PubKey(),
×
172
                },
×
173
                HtlcBasePoint: keychain.KeyDescriptor{
×
174
                        PubKey: aliceKeys[4].PubKey(),
×
175
                },
×
176
        }
×
177
        bobCfg := channeldb.ChannelConfig{
×
178
                ChannelConstraints: channeldb.ChannelConstraints{
×
179
                        DustLimit:        bobDustLimit,
×
180
                        MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity),
×
181
                        ChanReserve:      channelCapacity / 100,
×
182
                        MinHTLC:          0,
×
183
                        MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
×
184
                        CsvDelay:         uint16(csvTimeoutBob),
×
185
                },
×
186
                MultiSigKey: keychain.KeyDescriptor{
×
187
                        PubKey: bobKeys[0].PubKey(),
×
188
                },
×
189
                RevocationBasePoint: keychain.KeyDescriptor{
×
190
                        PubKey: bobKeys[1].PubKey(),
×
191
                },
×
192
                PaymentBasePoint: keychain.KeyDescriptor{
×
193
                        PubKey: bobKeys[2].PubKey(),
×
194
                },
×
195
                DelayBasePoint: keychain.KeyDescriptor{
×
196
                        PubKey: bobKeys[3].PubKey(),
×
197
                },
×
198
                HtlcBasePoint: keychain.KeyDescriptor{
×
199
                        PubKey: bobKeys[4].PubKey(),
×
200
                },
×
201
        }
×
202

×
203
        bobRoot, err := chainhash.NewHash(bobKeys[0].Serialize())
×
204
        if err != nil {
×
205
                return nil, nil, err
×
206
        }
×
207
        bobPreimageProducer := shachain.NewRevocationProducer(*bobRoot)
×
208
        bobFirstRevoke, err := bobPreimageProducer.AtIndex(0)
×
209
        if err != nil {
×
210
                return nil, nil, err
×
211
        }
×
212
        bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
×
213

×
214
        aliceRoot, err := chainhash.NewHash(aliceKeys[0].Serialize())
×
215
        if err != nil {
×
216
                return nil, nil, err
×
217
        }
×
218
        alicePreimageProducer := shachain.NewRevocationProducer(*aliceRoot)
×
219
        aliceFirstRevoke, err := alicePreimageProducer.AtIndex(0)
×
220
        if err != nil {
×
221
                return nil, nil, err
×
222
        }
×
223
        aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
×
224

×
225
        aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns(
×
226
                channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint,
×
227
                bobCommitPoint, *fundingTxIn, chanType, isAliceInitiator, 0,
×
228
        )
×
229
        if err != nil {
×
230
                return nil, nil, err
×
231
        }
×
232

233
        dbAlice, err := channeldb.Open(t.TempDir(), dbModifiers...)
×
234
        if err != nil {
×
235
                return nil, nil, err
×
236
        }
×
237
        t.Cleanup(func() {
×
238
                require.NoError(t, dbAlice.Close())
×
239
        })
×
240

241
        dbBob, err := channeldb.Open(t.TempDir(), dbModifiers...)
×
242
        if err != nil {
×
243
                return nil, nil, err
×
244
        }
×
245
        t.Cleanup(func() {
×
246
                require.NoError(t, dbBob.Close())
×
247
        })
×
248

249
        estimator := chainfee.NewStaticEstimator(6000, 0)
×
250
        feePerKw, err := estimator.EstimateFeePerKW(1)
×
251
        if err != nil {
×
252
                return nil, nil, err
×
253
        }
×
254
        commitFee := calcStaticFee(chanType, 0)
×
255
        var anchorAmt btcutil.Amount
×
256
        if chanType.HasAnchors() {
×
257
                anchorAmt += 2 * anchorSize
×
258
        }
×
259

260
        aliceBalance := lnwire.NewMSatFromSatoshis(
×
261
                channelBal - commitFee - anchorAmt,
×
262
        )
×
263
        bobBalance := lnwire.NewMSatFromSatoshis(channelBal)
×
264

×
265
        aliceLocalCommit := channeldb.ChannelCommitment{
×
266
                CommitHeight:  0,
×
267
                LocalBalance:  aliceBalance,
×
268
                RemoteBalance: bobBalance,
×
269
                CommitFee:     commitFee,
×
270
                FeePerKw:      btcutil.Amount(feePerKw),
×
271
                CommitTx:      aliceCommitTx,
×
272
                CommitSig:     testSigBytes,
×
273
        }
×
274
        aliceRemoteCommit := channeldb.ChannelCommitment{
×
275
                CommitHeight:  0,
×
276
                LocalBalance:  aliceBalance,
×
277
                RemoteBalance: bobBalance,
×
278
                CommitFee:     commitFee,
×
279
                FeePerKw:      btcutil.Amount(feePerKw),
×
280
                CommitTx:      bobCommitTx,
×
281
                CommitSig:     testSigBytes,
×
282
        }
×
283
        bobLocalCommit := channeldb.ChannelCommitment{
×
284
                CommitHeight:  0,
×
285
                LocalBalance:  bobBalance,
×
286
                RemoteBalance: aliceBalance,
×
287
                CommitFee:     commitFee,
×
288
                FeePerKw:      btcutil.Amount(feePerKw),
×
289
                CommitTx:      bobCommitTx,
×
290
                CommitSig:     testSigBytes,
×
291
        }
×
292
        bobRemoteCommit := channeldb.ChannelCommitment{
×
293
                CommitHeight:  0,
×
294
                LocalBalance:  bobBalance,
×
295
                RemoteBalance: aliceBalance,
×
296
                CommitFee:     commitFee,
×
297
                FeePerKw:      btcutil.Amount(feePerKw),
×
298
                CommitTx:      aliceCommitTx,
×
299
                CommitSig:     testSigBytes,
×
300
        }
×
301

×
302
        var chanIDBytes [8]byte
×
303
        if _, err := io.ReadFull(rand.Reader, chanIDBytes[:]); err != nil {
×
304
                return nil, nil, err
×
305
        }
×
306

307
        shortChanID := lnwire.NewShortChanIDFromInt(
×
308
                binary.BigEndian.Uint64(chanIDBytes[:]),
×
309
        )
×
310

×
311
        aliceChannelState := &channeldb.OpenChannel{
×
312
                LocalChanCfg:            aliceCfg,
×
313
                RemoteChanCfg:           bobCfg,
×
314
                IdentityPub:             aliceKeys[0].PubKey(),
×
315
                FundingOutpoint:         *prevOut,
×
316
                ShortChannelID:          shortChanID,
×
317
                ChanType:                chanType,
×
318
                IsInitiator:             isAliceInitiator,
×
319
                Capacity:                channelCapacity,
×
320
                RemoteCurrentRevocation: bobCommitPoint,
×
321
                RevocationProducer:      alicePreimageProducer,
×
322
                RevocationStore:         shachain.NewRevocationStore(),
×
323
                LocalCommitment:         aliceLocalCommit,
×
324
                RemoteCommitment:        aliceRemoteCommit,
×
325
                Db:                      dbAlice.ChannelStateDB(),
×
326
                Packager:                channeldb.NewChannelPackager(shortChanID),
×
327
                FundingTxn:              testTx,
×
328
        }
×
329
        bobChannelState := &channeldb.OpenChannel{
×
330
                LocalChanCfg:            bobCfg,
×
331
                RemoteChanCfg:           aliceCfg,
×
332
                IdentityPub:             bobKeys[0].PubKey(),
×
333
                FundingOutpoint:         *prevOut,
×
334
                ShortChannelID:          shortChanID,
×
335
                ChanType:                chanType,
×
336
                IsInitiator:             !isAliceInitiator,
×
337
                Capacity:                channelCapacity,
×
338
                RemoteCurrentRevocation: aliceCommitPoint,
×
339
                RevocationProducer:      bobPreimageProducer,
×
340
                RevocationStore:         shachain.NewRevocationStore(),
×
341
                LocalCommitment:         bobLocalCommit,
×
342
                RemoteCommitment:        bobRemoteCommit,
×
343
                Db:                      dbBob.ChannelStateDB(),
×
344
                Packager:                channeldb.NewChannelPackager(shortChanID),
×
345
        }
×
346

×
347
        aliceSigner := input.NewMockSigner(aliceKeys, nil)
×
348
        bobSigner := input.NewMockSigner(bobKeys, nil)
×
349

×
350
        // TODO(roasbeef): make mock version of pre-image store
×
351

×
352
        alicePool := NewSigPool(1, aliceSigner)
×
353
        channelAlice, err := NewLightningChannel(
×
354
                aliceSigner, aliceChannelState, alicePool,
×
355
        )
×
356
        if err != nil {
×
357
                return nil, nil, err
×
358
        }
×
359
        alicePool.Start()
×
360
        t.Cleanup(func() {
×
361
                require.NoError(t, alicePool.Stop())
×
362
        })
×
363

364
        obfuscator := createStateHintObfuscator(aliceChannelState)
×
365

×
366
        bobPool := NewSigPool(1, bobSigner)
×
367
        channelBob, err := NewLightningChannel(
×
368
                bobSigner, bobChannelState, bobPool,
×
369
        )
×
370
        if err != nil {
×
371
                return nil, nil, err
×
372
        }
×
373
        bobPool.Start()
×
374
        t.Cleanup(func() {
×
375
                require.NoError(t, bobPool.Stop())
×
376
        })
×
377

378
        err = SetStateNumHint(
×
379
                aliceCommitTx, 0, obfuscator,
×
380
        )
×
381
        if err != nil {
×
382
                return nil, nil, err
×
383
        }
×
384
        err = SetStateNumHint(
×
385
                bobCommitTx, 0, obfuscator,
×
386
        )
×
387
        if err != nil {
×
388
                return nil, nil, err
×
389
        }
×
390

391
        addr := &net.TCPAddr{
×
392
                IP:   net.ParseIP("127.0.0.1"),
×
393
                Port: 18556,
×
394
        }
×
395
        if err := channelAlice.channelState.SyncPending(addr, 101); err != nil {
×
396
                return nil, nil, err
×
397
        }
×
398

399
        addr = &net.TCPAddr{
×
400
                IP:   net.ParseIP("127.0.0.1"),
×
401
                Port: 18555,
×
402
        }
×
403

×
404
        if err := channelBob.channelState.SyncPending(addr, 101); err != nil {
×
405
                return nil, nil, err
×
406
        }
×
407

408
        // Now that the channel are open, simulate the start of a session by
409
        // having Alice and Bob extend their revocation windows to each other.
410
        err = initRevocationWindows(channelAlice, channelBob)
×
411
        if err != nil {
×
412
                return nil, nil, err
×
413
        }
×
414

415
        return channelAlice, channelBob, nil
×
416
}
417

418
// initRevocationWindows simulates a new channel being opened within the p2p
419
// network by populating the initial revocation windows of the passed
420
// commitment state machines.
421
func initRevocationWindows(chanA, chanB *LightningChannel) error {
×
422
        // If these are taproot chanenls, then we need to also simulate sending
×
423
        // either FundingLocked or ChannelReestablish by calling
×
424
        // InitRemoteMusigNonces for both sides.
×
425
        if chanA.channelState.ChanType.IsTaproot() {
×
426
                chanANonces, err := chanA.GenMusigNonces()
×
427
                if err != nil {
×
428
                        return err
×
429
                }
×
430
                chanBNonces, err := chanB.GenMusigNonces()
×
431
                if err != nil {
×
432
                        return err
×
433
                }
×
434

435
                if err := chanA.InitRemoteMusigNonces(chanBNonces); err != nil {
×
436
                        return err
×
437
                }
×
438
                if err := chanB.InitRemoteMusigNonces(chanANonces); err != nil {
×
439
                        return err
×
440
                }
×
441
        }
442

443
        aliceNextRevoke, err := chanA.NextRevocationKey()
×
444
        if err != nil {
×
445
                return err
×
446
        }
×
447
        if err := chanB.InitNextRevocation(aliceNextRevoke); err != nil {
×
448
                return err
×
449
        }
×
450

451
        bobNextRevoke, err := chanB.NextRevocationKey()
×
452
        if err != nil {
×
453
                return err
×
454
        }
×
455
        if err := chanA.InitNextRevocation(bobNextRevoke); err != nil {
×
456
                return err
×
457
        }
×
458

459
        return nil
×
460
}
461

462
// pubkeyFromHex parses a Bitcoin public key from a hex encoded string.
463
func pubkeyFromHex(keyHex string) (*btcec.PublicKey, error) {
×
464
        bytes, err := hex.DecodeString(keyHex)
×
465
        if err != nil {
×
466
                return nil, err
×
467
        }
×
468
        return btcec.ParsePubKey(bytes)
×
469
}
470

471
// privkeyFromHex parses a Bitcoin private key from a hex encoded string.
472
func privkeyFromHex(keyHex string) (*btcec.PrivateKey, error) {
×
473
        bytes, err := hex.DecodeString(keyHex)
×
474
        if err != nil {
×
475
                return nil, err
×
476
        }
×
477
        key, _ := btcec.PrivKeyFromBytes(bytes)
×
478
        return key, nil
×
479

480
}
481

482
// blockFromHex parses a full Bitcoin block from a hex encoded string.
483
func blockFromHex(blockHex string) (*btcutil.Block, error) {
×
484
        bytes, err := hex.DecodeString(blockHex)
×
485
        if err != nil {
×
486
                return nil, err
×
487
        }
×
488
        return btcutil.NewBlockFromBytes(bytes)
×
489
}
490

491
// txFromHex parses a full Bitcoin transaction from a hex encoded string.
492
func txFromHex(txHex string) (*btcutil.Tx, error) {
×
493
        bytes, err := hex.DecodeString(txHex)
×
494
        if err != nil {
×
495
                return nil, err
×
496
        }
×
497
        return btcutil.NewTxFromBytes(bytes)
×
498
}
499

500
// calcStaticFee calculates appropriate fees for commitment transactions.  This
501
// function provides a simple way to allow test balance assertions to take fee
502
// calculations into account.
503
//
504
// TODO(bvu): Refactor when dynamic fee estimation is added.
505
func calcStaticFee(chanType channeldb.ChannelType, numHTLCs int) btcutil.Amount {
×
506
        const (
×
507
                htlcWeight = 172
×
508
                feePerKw   = btcutil.Amount(24/4) * 1000
×
509
        )
×
510
        htlcsWeight := htlcWeight * int64(numHTLCs)
×
511
        totalWeight := CommitWeight(chanType) + lntypes.WeightUnit(htlcsWeight)
×
512

×
513
        return feePerKw * (btcutil.Amount(totalWeight)) / 1000
×
514
}
×
515

516
// ForceStateTransition executes the necessary interaction between the two
517
// commitment state machines to transition to a new state locking in any
518
// pending updates. This method is useful when testing interactions between two
519
// live state machines.
520
func ForceStateTransition(chanA, chanB *LightningChannel) error {
×
521
        aliceNewCommit, err := chanA.SignNextCommitment()
×
522
        if err != nil {
×
523
                return err
×
524
        }
×
525
        err = chanB.ReceiveNewCommitment(aliceNewCommit.CommitSigs)
×
526
        if err != nil {
×
527
                return err
×
528
        }
×
529

530
        bobRevocation, _, _, err := chanB.RevokeCurrentCommitment()
×
531
        if err != nil {
×
532
                return err
×
533
        }
×
534
        bobNewCommit, err := chanB.SignNextCommitment()
×
535
        if err != nil {
×
536
                return err
×
537
        }
×
538

539
        _, _, _, _, err = chanA.ReceiveRevocation(bobRevocation)
×
540
        if err != nil {
×
541
                return err
×
542
        }
×
543
        err = chanA.ReceiveNewCommitment(bobNewCommit.CommitSigs)
×
544
        if err != nil {
×
545
                return err
×
546
        }
×
547

548
        aliceRevocation, _, _, err := chanA.RevokeCurrentCommitment()
×
549
        if err != nil {
×
550
                return err
×
551
        }
×
552
        _, _, _, _, err = chanB.ReceiveRevocation(aliceRevocation)
×
553
        if err != nil {
×
554
                return err
×
555
        }
×
556

557
        return nil
×
558
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc