github.com/decred/dcrlnd@v0.7.6/contractcourt/briefcase_test.go (about)

     1  package contractcourt
     2  
     3  import (
     4  	"crypto/rand"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	prand "math/rand"
    12  
    13  	"github.com/davecgh/go-spew/spew"
    14  	"github.com/decred/dcrd/chaincfg/chainhash"
    15  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    16  	"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
    17  	"github.com/decred/dcrd/txscript/v4"
    18  	"github.com/decred/dcrd/wire"
    19  	"github.com/decred/dcrlnd/channeldb"
    20  	"github.com/decred/dcrlnd/input"
    21  	"github.com/decred/dcrlnd/kvdb"
    22  	"github.com/decred/dcrlnd/lntest/channels"
    23  	"github.com/decred/dcrlnd/lnwallet"
    24  )
    25  
    26  var (
    27  	testChainHash = [chainhash.HashSize]byte{
    28  		0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    29  		0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    30  		0x2d, 0xe7, 0x93, 0xe4,
    31  	}
    32  
    33  	testChanPoint1 = wire.OutPoint{
    34  		Hash: chainhash.Hash{
    35  			0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    36  			0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    37  			0x2d, 0xe7, 0x93, 0xe4,
    38  		},
    39  		Index: 1,
    40  	}
    41  
    42  	testChanPoint2 = wire.OutPoint{
    43  		Hash: chainhash.Hash{
    44  			0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    45  			0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    46  			0x2d, 0xe7, 0x93, 0xe4,
    47  		},
    48  		Index: 2,
    49  	}
    50  
    51  	testChanPoint3 = wire.OutPoint{
    52  		Hash: chainhash.Hash{
    53  			0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    54  			0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    55  			0x2d, 0xe7, 0x93, 0xe4,
    56  		},
    57  		Index: 3,
    58  	}
    59  
    60  	testPreimage = [32]byte{
    61  		0x52, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    62  		0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    63  		0x2d, 0xe7, 0x93, 0xe4,
    64  	}
    65  
    66  	key1 = []byte{
    67  		0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
    68  		0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
    69  		0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
    70  		0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
    71  		0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
    72  		0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
    73  		0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
    74  		0xb4, 0x12, 0xa3,
    75  	}
    76  
    77  	testSignDesc = input.SignDescriptor{
    78  		SingleTweak: []byte{
    79  			0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
    80  			0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
    81  			0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
    82  			0x02, 0x02, 0x02, 0x02, 0x02,
    83  		},
    84  		WitnessScript: []byte{
    85  			0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde,
    86  			0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2,
    87  			0xef, 0xb5, 0x71, 0x48,
    88  		},
    89  		Output: &wire.TxOut{
    90  			Value: 5000000000,
    91  			PkScript: []byte{
    92  				0x41, // OP_DATA_65
    93  				0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
    94  				0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
    95  				0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
    96  				0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
    97  				0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
    98  				0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
    99  				0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
   100  				0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
   101  				0xa6, // 65-byte signature
   102  				0xac, // OP_CHECKSIG
   103  			},
   104  		},
   105  		HashType: txscript.SigHashAll,
   106  	}
   107  
   108  	testTx = &wire.MsgTx{
   109  		Version: 2,
   110  		TxIn: []*wire.TxIn{
   111  			{
   112  				PreviousOutPoint: testChanPoint2,
   113  				SignatureScript: []byte{
   114  					0x14, 0xee, 0x91, 0x41,
   115  					0x7e, 0x85, 0x6c, 0xde, 0x10,
   116  					0xa2, 0x91, 0x1e, 0xdc, 0xbd,
   117  					0xbd, 0x69, 0xe2, 0xef, 0xb5,
   118  					0x71, 0x48,
   119  				},
   120  				Sequence: 1,
   121  			},
   122  		},
   123  		TxOut: []*wire.TxOut{
   124  			{
   125  				Value: 5000000000,
   126  				PkScript: []byte{
   127  					0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2,
   128  					0x86, 0x24, 0xe1, 0x81, 0x75, 0xe8,
   129  					0x51, 0xc9, 0x6b, 0x97, 0x3d, 0x81,
   130  					0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
   131  				},
   132  			},
   133  		},
   134  		LockTime: 123,
   135  	}
   136  
   137  	testSig, _ = ecdsa.ParseDERSignature(channels.TestSigBytes)
   138  
   139  	testSignDetails = &input.SignDetails{
   140  		SignDesc:    testSignDesc,
   141  		SigHashType: txscript.SigHashSingle,
   142  		PeerSig:     testSig,
   143  	}
   144  )
   145  
   146  func makeTestDB() (kvdb.Backend, func(), error) {
   147  	// First, create a temporary directory to be used for the duration of
   148  	// this test.
   149  	tempDirName, err := ioutil.TempDir("", "arblog")
   150  	if err != nil {
   151  		return nil, nil, err
   152  	}
   153  
   154  	db, err := kvdb.Create(
   155  		kvdb.BoltBackendName, tempDirName+"/test.db", true,
   156  		kvdb.DefaultDBTimeout,
   157  	)
   158  	if err != nil {
   159  		return nil, nil, err
   160  	}
   161  
   162  	cleanUp := func() {
   163  		db.Close()
   164  		os.RemoveAll(tempDirName)
   165  	}
   166  
   167  	return db, cleanUp, nil
   168  }
   169  
   170  func newTestBoltArbLog(chainhash chainhash.Hash,
   171  	op wire.OutPoint) (ArbitratorLog, func(), error) {
   172  
   173  	testDB, cleanUp, err := makeTestDB()
   174  	if err != nil {
   175  		return nil, nil, err
   176  	}
   177  
   178  	testArbCfg := ChannelArbitratorConfig{
   179  		PutResolverReport: func(_ kvdb.RwTx,
   180  			_ *channeldb.ResolverReport) error {
   181  			return nil
   182  		},
   183  	}
   184  	testLog, err := newBoltArbitratorLog(testDB, testArbCfg, chainhash, op)
   185  	if err != nil {
   186  		return nil, nil, err
   187  	}
   188  
   189  	return testLog, cleanUp, err
   190  }
   191  
   192  func randOutPoint() wire.OutPoint {
   193  	var op wire.OutPoint
   194  	rand.Read(op.Hash[:])
   195  	op.Index = prand.Uint32()
   196  
   197  	return op
   198  }
   199  
   200  func assertResolversEqual(t *testing.T, originalResolver ContractResolver,
   201  	diskResolver ContractResolver) {
   202  
   203  	assertTimeoutResEqual := func(ogRes, diskRes *htlcTimeoutResolver) {
   204  		if !reflect.DeepEqual(ogRes.htlcResolution, diskRes.htlcResolution) {
   205  			t.Fatalf("resolution mismatch: expected %#v, got %v#",
   206  				ogRes.htlcResolution, diskRes.htlcResolution)
   207  		}
   208  		if ogRes.outputIncubating != diskRes.outputIncubating {
   209  			t.Fatalf("expected %v, got %v",
   210  				ogRes.outputIncubating, diskRes.outputIncubating)
   211  		}
   212  		if ogRes.resolved != diskRes.resolved {
   213  			t.Fatalf("expected %v, got %v", ogRes.resolved,
   214  				diskRes.resolved)
   215  		}
   216  		if ogRes.broadcastHeight != diskRes.broadcastHeight {
   217  			t.Fatalf("expected %v, got %v",
   218  				ogRes.broadcastHeight, diskRes.broadcastHeight)
   219  		}
   220  		if ogRes.htlc.HtlcIndex != diskRes.htlc.HtlcIndex {
   221  			t.Fatalf("expected %v, got %v", ogRes.htlc.HtlcIndex,
   222  				diskRes.htlc.HtlcIndex)
   223  		}
   224  	}
   225  
   226  	assertSuccessResEqual := func(ogRes, diskRes *htlcSuccessResolver) {
   227  		if !reflect.DeepEqual(ogRes.htlcResolution, diskRes.htlcResolution) {
   228  			t.Fatalf("resolution mismatch: expected %#v, got %v#",
   229  				ogRes.htlcResolution, diskRes.htlcResolution)
   230  		}
   231  		if ogRes.outputIncubating != diskRes.outputIncubating {
   232  			t.Fatalf("expected %v, got %v",
   233  				ogRes.outputIncubating, diskRes.outputIncubating)
   234  		}
   235  		if ogRes.resolved != diskRes.resolved {
   236  			t.Fatalf("expected %v, got %v", ogRes.resolved,
   237  				diskRes.resolved)
   238  		}
   239  		if ogRes.broadcastHeight != diskRes.broadcastHeight {
   240  			t.Fatalf("expected %v, got %v",
   241  				ogRes.broadcastHeight, diskRes.broadcastHeight)
   242  		}
   243  		if ogRes.htlc.RHash != diskRes.htlc.RHash {
   244  			t.Fatalf("expected %v, got %v", ogRes.htlc.RHash,
   245  				diskRes.htlc.RHash)
   246  		}
   247  	}
   248  
   249  	switch ogRes := originalResolver.(type) {
   250  	case *htlcTimeoutResolver:
   251  		diskRes := diskResolver.(*htlcTimeoutResolver)
   252  		assertTimeoutResEqual(ogRes, diskRes)
   253  
   254  	case *htlcSuccessResolver:
   255  		diskRes := diskResolver.(*htlcSuccessResolver)
   256  		assertSuccessResEqual(ogRes, diskRes)
   257  
   258  	case *htlcOutgoingContestResolver:
   259  		diskRes := diskResolver.(*htlcOutgoingContestResolver)
   260  		assertTimeoutResEqual(
   261  			ogRes.htlcTimeoutResolver, diskRes.htlcTimeoutResolver,
   262  		)
   263  
   264  	case *htlcIncomingContestResolver:
   265  		diskRes := diskResolver.(*htlcIncomingContestResolver)
   266  		assertSuccessResEqual(
   267  			ogRes.htlcSuccessResolver, diskRes.htlcSuccessResolver,
   268  		)
   269  
   270  		if ogRes.htlcExpiry != diskRes.htlcExpiry {
   271  			t.Fatalf("expected %v, got %v", ogRes.htlcExpiry,
   272  				diskRes.htlcExpiry)
   273  		}
   274  
   275  	case *commitSweepResolver:
   276  		diskRes := diskResolver.(*commitSweepResolver)
   277  		if !reflect.DeepEqual(ogRes.commitResolution, diskRes.commitResolution) {
   278  			t.Fatalf("resolution mismatch: expected %v, got %v",
   279  				ogRes.commitResolution, diskRes.commitResolution)
   280  		}
   281  		if ogRes.resolved != diskRes.resolved {
   282  			t.Fatalf("expected %v, got %v", ogRes.resolved,
   283  				diskRes.resolved)
   284  		}
   285  		if ogRes.broadcastHeight != diskRes.broadcastHeight {
   286  			t.Fatalf("expected %v, got %v",
   287  				ogRes.broadcastHeight, diskRes.broadcastHeight)
   288  		}
   289  		if ogRes.chanPoint != diskRes.chanPoint {
   290  			t.Fatalf("expected %v, got %v", ogRes.chanPoint,
   291  				diskRes.chanPoint)
   292  		}
   293  	}
   294  }
   295  
   296  // TestContractInsertionRetrieval tests that were able to insert a set of
   297  // unresolved contracts into the log, and retrieve the same set properly.
   298  //
   299  // We disable govet in this case to avoid the complaint about a copied lock.
   300  //
   301  //nolint:govet
   302  func TestContractInsertionRetrieval(t *testing.T) {
   303  	t.Parallel()
   304  
   305  	// First, we'll create a test instance of the ArbitratorLog
   306  	// implementation backed by bboltdb.
   307  	testLog, cleanUp, err := newTestBoltArbLog(
   308  		testChainHash, testChanPoint1,
   309  	)
   310  	if err != nil {
   311  		t.Fatalf("unable to create test log: %v", err)
   312  	}
   313  	defer cleanUp()
   314  
   315  	// The log created, we'll create a series of resolvers, each properly
   316  	// implementing the ContractResolver interface.
   317  	timeoutResolver := htlcTimeoutResolver{
   318  		htlcResolution: lnwallet.OutgoingHtlcResolution{
   319  			Expiry:          99,
   320  			SignedTimeoutTx: nil,
   321  			CsvDelay:        99,
   322  			ClaimOutpoint:   randOutPoint(),
   323  			SweepSignDesc:   testSignDesc,
   324  		},
   325  		outputIncubating: true,
   326  		resolved:         true,
   327  		broadcastHeight:  102,
   328  		htlc: channeldb.HTLC{
   329  			HtlcIndex: 12,
   330  		},
   331  	}
   332  	successResolver := htlcSuccessResolver{
   333  		htlcResolution: lnwallet.IncomingHtlcResolution{
   334  			Preimage:        testPreimage,
   335  			SignedSuccessTx: nil,
   336  			CsvDelay:        900,
   337  			ClaimOutpoint:   randOutPoint(),
   338  			SweepSignDesc:   testSignDesc,
   339  		},
   340  		outputIncubating: true,
   341  		resolved:         true,
   342  		broadcastHeight:  109,
   343  		htlc: channeldb.HTLC{
   344  			RHash: testPreimage,
   345  		},
   346  		sweepTx: nil,
   347  	}
   348  	resolvers := []ContractResolver{
   349  		&timeoutResolver,
   350  		&successResolver,
   351  		&commitSweepResolver{
   352  			commitResolution: lnwallet.CommitOutputResolution{
   353  				SelfOutPoint:       testChanPoint2,
   354  				SelfOutputSignDesc: testSignDesc,
   355  				MaturityDelay:      99,
   356  			},
   357  			resolved:        false,
   358  			broadcastHeight: 109,
   359  			chanPoint:       testChanPoint1,
   360  		},
   361  	}
   362  
   363  	// All resolvers require a unique ResolverKey() output. To achieve this
   364  	// for the composite resolvers, we'll mutate the underlying resolver
   365  	// with a new outpoint.
   366  	contestTimeout := timeoutResolver
   367  	contestTimeout.htlcResolution.ClaimOutpoint = randOutPoint()
   368  	resolvers = append(resolvers, &htlcOutgoingContestResolver{
   369  		htlcTimeoutResolver: &contestTimeout,
   370  	})
   371  	contestSuccess := successResolver
   372  	contestSuccess.htlcResolution.ClaimOutpoint = randOutPoint()
   373  	resolvers = append(resolvers, &htlcIncomingContestResolver{
   374  		htlcExpiry:          100,
   375  		htlcSuccessResolver: &contestSuccess,
   376  	})
   377  
   378  	// For quick lookup during the test, we'll create this map which allow
   379  	// us to lookup a resolver according to its unique resolver key.
   380  	resolverMap := make(map[string]ContractResolver)
   381  	resolverMap[string(timeoutResolver.ResolverKey())] = resolvers[0]
   382  	resolverMap[string(successResolver.ResolverKey())] = resolvers[1]
   383  	resolverMap[string(resolvers[2].ResolverKey())] = resolvers[2]
   384  	resolverMap[string(resolvers[3].ResolverKey())] = resolvers[3]
   385  	resolverMap[string(resolvers[4].ResolverKey())] = resolvers[4]
   386  
   387  	// Now, we'll insert the resolver into the log, we do not need to apply
   388  	// any closures, so we will pass in nil.
   389  	err = testLog.InsertUnresolvedContracts(nil, resolvers...)
   390  	if err != nil {
   391  		t.Fatalf("unable to insert resolvers: %v", err)
   392  	}
   393  
   394  	// With the resolvers inserted, we'll now attempt to retrieve them from
   395  	// the database, so we can compare them to the versions we created
   396  	// above.
   397  	diskResolvers, err := testLog.FetchUnresolvedContracts()
   398  	if err != nil {
   399  		t.Fatalf("unable to retrieve resolvers: %v", err)
   400  	}
   401  
   402  	if len(diskResolvers) != len(resolvers) {
   403  		t.Fatalf("expected %v got resolvers, instead got %v: %#v",
   404  			len(resolvers), len(diskResolvers),
   405  			diskResolvers)
   406  	}
   407  
   408  	// Now we'll run through each of the resolvers, and ensure that it maps
   409  	// to a resolver perfectly that we inserted previously.
   410  	for _, diskResolver := range diskResolvers {
   411  		resKey := string(diskResolver.ResolverKey())
   412  		originalResolver, ok := resolverMap[resKey]
   413  		if !ok {
   414  			t.Fatalf("unable to find resolver match for %T: %v",
   415  				diskResolver, resKey)
   416  		}
   417  
   418  		assertResolversEqual(t, originalResolver, diskResolver)
   419  	}
   420  
   421  	// We'll now delete the state, then attempt to retrieve the set of
   422  	// resolvers, no resolvers should be found.
   423  	if err := testLog.WipeHistory(); err != nil {
   424  		t.Fatalf("unable to wipe log: %v", err)
   425  	}
   426  	diskResolvers, err = testLog.FetchUnresolvedContracts()
   427  	if err != nil {
   428  		t.Fatalf("unable to fetch unresolved contracts: %v", err)
   429  	}
   430  	if len(diskResolvers) != 0 {
   431  		t.Fatalf("no resolvers should be found, instead %v were",
   432  			len(diskResolvers))
   433  	}
   434  }
   435  
   436  // TestContractResolution tests that once we mark a contract as resolved, it's
   437  // properly removed from the database.
   438  func TestContractResolution(t *testing.T) {
   439  	t.Parallel()
   440  
   441  	// First, we'll create a test instance of the ArbitratorLog
   442  	// implementation backed by bboltdb.
   443  	testLog, cleanUp, err := newTestBoltArbLog(
   444  		testChainHash, testChanPoint1,
   445  	)
   446  	if err != nil {
   447  		t.Fatalf("unable to create test log: %v", err)
   448  	}
   449  	defer cleanUp()
   450  
   451  	// We'll now create a timeout resolver that we'll be using for the
   452  	// duration of this test.
   453  	timeoutResolver := &htlcTimeoutResolver{
   454  		htlcResolution: lnwallet.OutgoingHtlcResolution{
   455  			Expiry:          991,
   456  			SignedTimeoutTx: nil,
   457  			CsvDelay:        992,
   458  			ClaimOutpoint:   randOutPoint(),
   459  			SweepSignDesc:   testSignDesc,
   460  		},
   461  		outputIncubating: true,
   462  		resolved:         true,
   463  		broadcastHeight:  192,
   464  		htlc: channeldb.HTLC{
   465  			HtlcIndex: 9912,
   466  		},
   467  	}
   468  
   469  	// First, we'll insert the resolver into the database and ensure that
   470  	// we get the same resolver out the other side. We do not need to apply
   471  	// any closures.
   472  	err = testLog.InsertUnresolvedContracts(nil, timeoutResolver)
   473  	if err != nil {
   474  		t.Fatalf("unable to insert contract into db: %v", err)
   475  	}
   476  	dbContracts, err := testLog.FetchUnresolvedContracts()
   477  	if err != nil {
   478  		t.Fatalf("unable to fetch contracts from db: %v", err)
   479  	}
   480  	assertResolversEqual(t, timeoutResolver, dbContracts[0])
   481  
   482  	// Now, we'll mark the contract as resolved within the database.
   483  	if err := testLog.ResolveContract(timeoutResolver); err != nil {
   484  		t.Fatalf("unable to resolve contract: %v", err)
   485  	}
   486  
   487  	// At this point, no contracts should exist within the log.
   488  	dbContracts, err = testLog.FetchUnresolvedContracts()
   489  	if err != nil {
   490  		t.Fatalf("unable to fetch contracts from db: %v", err)
   491  	}
   492  	if len(dbContracts) != 0 {
   493  		t.Fatalf("no contract should be from in the db, instead %v "+
   494  			"were", len(dbContracts))
   495  	}
   496  }
   497  
   498  // TestContractSwapping ensures that callers are able to atomically swap to
   499  // distinct contracts for one another.
   500  func TestContractSwapping(t *testing.T) {
   501  	t.Parallel()
   502  
   503  	// First, we'll create a test instance of the ArbitratorLog
   504  	// implementation backed by bboltdb.
   505  	testLog, cleanUp, err := newTestBoltArbLog(
   506  		testChainHash, testChanPoint1,
   507  	)
   508  	if err != nil {
   509  		t.Fatalf("unable to create test log: %v", err)
   510  	}
   511  	defer cleanUp()
   512  
   513  	// We'll create two resolvers, a regular timeout resolver, and the
   514  	// contest resolver that eventually turns into the timeout resolver.
   515  	timeoutResolver := &htlcTimeoutResolver{
   516  		htlcResolution: lnwallet.OutgoingHtlcResolution{
   517  			Expiry:          99,
   518  			SignedTimeoutTx: nil,
   519  			CsvDelay:        99,
   520  			ClaimOutpoint:   randOutPoint(),
   521  			SweepSignDesc:   testSignDesc,
   522  		},
   523  		outputIncubating: true,
   524  		resolved:         true,
   525  		broadcastHeight:  102,
   526  		htlc: channeldb.HTLC{
   527  			HtlcIndex: 12,
   528  		},
   529  	}
   530  	contestResolver := &htlcOutgoingContestResolver{
   531  		htlcTimeoutResolver: timeoutResolver,
   532  	}
   533  
   534  	// We'll first insert the contest resolver into the log with no
   535  	// additional updates.
   536  	err = testLog.InsertUnresolvedContracts(nil, contestResolver)
   537  	if err != nil {
   538  		t.Fatalf("unable to insert contract into db: %v", err)
   539  	}
   540  
   541  	// With the resolver inserted, we'll now attempt to atomically swap it
   542  	// for its underlying timeout resolver.
   543  	err = testLog.SwapContract(contestResolver, timeoutResolver)
   544  	if err != nil {
   545  		t.Fatalf("unable to swap contracts: %v", err)
   546  	}
   547  
   548  	// At this point, there should now only be a single contract in the
   549  	// database.
   550  	dbContracts, err := testLog.FetchUnresolvedContracts()
   551  	if err != nil {
   552  		t.Fatalf("unable to fetch contracts from db: %v", err)
   553  	}
   554  	if len(dbContracts) != 1 {
   555  		t.Fatalf("one contract should be from in the db, instead %v "+
   556  			"were", len(dbContracts))
   557  	}
   558  
   559  	// That single contract should be the underlying timeout resolver.
   560  	assertResolversEqual(t, timeoutResolver, dbContracts[0])
   561  }
   562  
   563  // TestContractResolutionsStorage tests that we're able to properly store and
   564  // retrieve contract resolutions written to disk.
   565  func TestContractResolutionsStorage(t *testing.T) {
   566  	t.Parallel()
   567  
   568  	// First, we'll create a test instance of the ArbitratorLog
   569  	// implementation backed by bboltdb.
   570  	testLog, cleanUp, err := newTestBoltArbLog(
   571  		testChainHash, testChanPoint1,
   572  	)
   573  	if err != nil {
   574  		t.Fatalf("unable to create test log: %v", err)
   575  	}
   576  	defer cleanUp()
   577  
   578  	// With the test log created, we'll now craft a contact resolution that
   579  	// will be using for the duration of this test.
   580  	res := ContractResolutions{
   581  		CommitHash: testChainHash,
   582  		CommitResolution: &lnwallet.CommitOutputResolution{
   583  			SelfOutPoint:       testChanPoint2,
   584  			SelfOutputSignDesc: testSignDesc,
   585  			MaturityDelay:      101,
   586  		},
   587  		HtlcResolutions: lnwallet.HtlcResolutions{
   588  			IncomingHTLCs: []lnwallet.IncomingHtlcResolution{
   589  				{
   590  					Preimage:        testPreimage,
   591  					SignedSuccessTx: nil,
   592  					CsvDelay:        900,
   593  					ClaimOutpoint:   randOutPoint(),
   594  					SweepSignDesc:   testSignDesc,
   595  				},
   596  
   597  				// We add a resolution with SignDetails.
   598  				{
   599  					Preimage:        testPreimage,
   600  					SignedSuccessTx: testTx,
   601  					SignDetails:     testSignDetails,
   602  					CsvDelay:        900,
   603  					ClaimOutpoint:   randOutPoint(),
   604  					SweepSignDesc:   testSignDesc,
   605  				},
   606  
   607  				// We add a resolution with a signed tx, but no
   608  				// SignDetails.
   609  				{
   610  					Preimage:        testPreimage,
   611  					SignedSuccessTx: testTx,
   612  					CsvDelay:        900,
   613  					ClaimOutpoint:   randOutPoint(),
   614  					SweepSignDesc:   testSignDesc,
   615  				},
   616  			},
   617  			OutgoingHTLCs: []lnwallet.OutgoingHtlcResolution{
   618  				// We add a resolution with a signed tx, but no
   619  				// SignDetails.
   620  				{
   621  					Expiry:          103,
   622  					SignedTimeoutTx: testTx,
   623  					CsvDelay:        923923,
   624  					ClaimOutpoint:   randOutPoint(),
   625  					SweepSignDesc:   testSignDesc,
   626  				},
   627  				// Resolution without signed tx.
   628  				{
   629  					Expiry:          103,
   630  					SignedTimeoutTx: nil,
   631  					CsvDelay:        923923,
   632  					ClaimOutpoint:   randOutPoint(),
   633  					SweepSignDesc:   testSignDesc,
   634  				},
   635  				// Resolution with SignDetails.
   636  				{
   637  					Expiry:          103,
   638  					SignedTimeoutTx: testTx,
   639  					SignDetails:     testSignDetails,
   640  					CsvDelay:        923923,
   641  					ClaimOutpoint:   randOutPoint(),
   642  					SweepSignDesc:   testSignDesc,
   643  				},
   644  			},
   645  		},
   646  		AnchorResolution: &lnwallet.AnchorResolution{
   647  			CommitAnchor:         testChanPoint3,
   648  			AnchorSignDescriptor: testSignDesc,
   649  		},
   650  	}
   651  
   652  	// First make sure that fetching unlogged contract resolutions will
   653  	// fail.
   654  	_, err = testLog.FetchContractResolutions()
   655  	if err == nil {
   656  		t.Fatalf("expected reading unlogged resolution from db to fail")
   657  	}
   658  
   659  	// Insert the resolution into the database, then immediately retrieve
   660  	// them so we can compare equality against the original version.
   661  	if err := testLog.LogContractResolutions(&res); err != nil {
   662  		t.Fatalf("unable to insert resolutions into db: %v", err)
   663  	}
   664  	diskRes, err := testLog.FetchContractResolutions()
   665  	if err != nil {
   666  		t.Fatalf("unable to read resolution from db: %v", err)
   667  	}
   668  
   669  	if !reflect.DeepEqual(&res, diskRes) {
   670  		t.Fatalf("resolution mismatch: expected %v\n, got %v",
   671  			spew.Sdump(&res), spew.Sdump(diskRes))
   672  	}
   673  
   674  	// We'll now delete the state, then attempt to retrieve the set of
   675  	// resolvers, no resolutions should be found.
   676  	if err := testLog.WipeHistory(); err != nil {
   677  		t.Fatalf("unable to wipe log: %v", err)
   678  	}
   679  	_, err = testLog.FetchContractResolutions()
   680  	if err != errScopeBucketNoExist {
   681  		t.Fatalf("unexpected error: %v", err)
   682  	}
   683  }
   684  
   685  // TestStateMutation tests that we're able to properly mutate the state of the
   686  // log, then retrieve that same mutated state from disk.
   687  func TestStateMutation(t *testing.T) {
   688  	t.Parallel()
   689  
   690  	testLog, cleanUp, err := newTestBoltArbLog(
   691  		testChainHash, testChanPoint1,
   692  	)
   693  	if err != nil {
   694  		t.Fatalf("unable to create test log: %v", err)
   695  	}
   696  	defer cleanUp()
   697  
   698  	// The default state of an arbitrator should be StateDefault.
   699  	arbState, err := testLog.CurrentState(nil)
   700  	if err != nil {
   701  		t.Fatalf("unable to read arb state: %v", err)
   702  	}
   703  	if arbState != StateDefault {
   704  		t.Fatalf("state mismatch: expected %v, got %v", StateDefault,
   705  			arbState)
   706  	}
   707  
   708  	// We should now be able to mutate the state to an arbitrary one of our
   709  	// choosing, then read that same state back from disk.
   710  	if err := testLog.CommitState(StateFullyResolved); err != nil {
   711  		t.Fatalf("unable to write state: %v", err)
   712  	}
   713  	arbState, err = testLog.CurrentState(nil)
   714  	if err != nil {
   715  		t.Fatalf("unable to read arb state: %v", err)
   716  	}
   717  	if arbState != StateFullyResolved {
   718  		t.Fatalf("state mismatch: expected %v, got %v", StateFullyResolved,
   719  			arbState)
   720  	}
   721  
   722  	// Next, we'll wipe our state and ensure that if we try to query for
   723  	// the current state, we get the proper error.
   724  	err = testLog.WipeHistory()
   725  	if err != nil {
   726  		t.Fatalf("unable to wipe history: %v", err)
   727  	}
   728  
   729  	// If we try to query for the state again, we should get the default
   730  	// state again.
   731  	arbState, err = testLog.CurrentState(nil)
   732  	if err != nil {
   733  		t.Fatalf("unable to fetch current arbitrator state: %v", err)
   734  	}
   735  	if arbState != StateDefault {
   736  		t.Fatalf("state mismatch: expected %v, got %v", StateDefault,
   737  			arbState)
   738  	}
   739  }
   740  
   741  // TestScopeIsolation tests the two distinct ArbitratorLog instances with two
   742  // distinct scopes, don't over write the state of one another.
   743  func TestScopeIsolation(t *testing.T) {
   744  	t.Parallel()
   745  
   746  	// We'll create two distinct test logs. Each log will have a unique
   747  	// scope key, and therefore should be isolated from the other on disk.
   748  	testLog1, cleanUp1, err := newTestBoltArbLog(
   749  		testChainHash, testChanPoint1,
   750  	)
   751  	if err != nil {
   752  		t.Fatalf("unable to create test log: %v", err)
   753  	}
   754  	defer cleanUp1()
   755  
   756  	testLog2, cleanUp2, err := newTestBoltArbLog(
   757  		testChainHash, testChanPoint2,
   758  	)
   759  	if err != nil {
   760  		t.Fatalf("unable to create test log: %v", err)
   761  	}
   762  	defer cleanUp2()
   763  
   764  	// We'll now update the current state of both the logs to a unique
   765  	// state.
   766  	if err := testLog1.CommitState(StateWaitingFullResolution); err != nil {
   767  		t.Fatalf("unable to write state: %v", err)
   768  	}
   769  	if err := testLog2.CommitState(StateContractClosed); err != nil {
   770  		t.Fatalf("unable to write state: %v", err)
   771  	}
   772  
   773  	// Querying each log, the states should be the prior one we set, and be
   774  	// disjoint.
   775  	log1State, err := testLog1.CurrentState(nil)
   776  	if err != nil {
   777  		t.Fatalf("unable to read arb state: %v", err)
   778  	}
   779  	log2State, err := testLog2.CurrentState(nil)
   780  	if err != nil {
   781  		t.Fatalf("unable to read arb state: %v", err)
   782  	}
   783  
   784  	if log1State == log2State {
   785  		t.Fatalf("log states are the same: %v", log1State)
   786  	}
   787  
   788  	if log1State != StateWaitingFullResolution {
   789  		t.Fatalf("state mismatch: expected %v, got %v",
   790  			StateWaitingFullResolution, log1State)
   791  	}
   792  	if log2State != StateContractClosed {
   793  		t.Fatalf("state mismatch: expected %v, got %v",
   794  			StateContractClosed, log2State)
   795  	}
   796  }
   797  
   798  // TestCommitSetStorage tests that we're able to properly read/write active
   799  // commitment sets.
   800  func TestCommitSetStorage(t *testing.T) {
   801  	t.Parallel()
   802  
   803  	testLog, cleanUp, err := newTestBoltArbLog(
   804  		testChainHash, testChanPoint1,
   805  	)
   806  	if err != nil {
   807  		t.Fatalf("unable to create test log: %v", err)
   808  	}
   809  	defer cleanUp()
   810  
   811  	activeHTLCs := []channeldb.HTLC{
   812  		{
   813  			Amt:       1000,
   814  			OnionBlob: make([]byte, 0),
   815  			Signature: make([]byte, 0),
   816  		},
   817  	}
   818  
   819  	confTypes := []HtlcSetKey{
   820  		LocalHtlcSet, RemoteHtlcSet, RemotePendingHtlcSet,
   821  	}
   822  	for _, pendingRemote := range []bool{true, false} {
   823  		for _, confType := range confTypes {
   824  			commitSet := &CommitSet{
   825  				ConfCommitKey: &confType,
   826  				HtlcSets:      make(map[HtlcSetKey][]channeldb.HTLC),
   827  			}
   828  			commitSet.HtlcSets[LocalHtlcSet] = activeHTLCs
   829  			commitSet.HtlcSets[RemoteHtlcSet] = activeHTLCs
   830  
   831  			if pendingRemote {
   832  				commitSet.HtlcSets[RemotePendingHtlcSet] = activeHTLCs
   833  			}
   834  
   835  			err := testLog.InsertConfirmedCommitSet(commitSet)
   836  			if err != nil {
   837  				t.Fatalf("unable to write commit set: %v", err)
   838  			}
   839  
   840  			diskCommitSet, err := testLog.FetchConfirmedCommitSet(nil)
   841  			if err != nil {
   842  				t.Fatalf("unable to read commit set: %v", err)
   843  			}
   844  
   845  			if !reflect.DeepEqual(commitSet, diskCommitSet) {
   846  				t.Fatalf("commit set mismatch: expected %v, got %v",
   847  					spew.Sdump(commitSet), spew.Sdump(diskCommitSet))
   848  			}
   849  		}
   850  	}
   851  
   852  }
   853  
   854  func init() {
   855  	testSignDesc.KeyDesc.PubKey, _ = secp256k1.ParsePubKey(key1)
   856  
   857  	prand.Seed(time.Now().Unix())
   858  }