github.com/NebulousLabs/Sia@v1.3.7/modules/consensus/accept_txntypes_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/NebulousLabs/Sia/crypto"
     7  	"github.com/NebulousLabs/Sia/types"
     8  	"github.com/NebulousLabs/fastrand"
     9  )
    10  
    11  // testBlockSuite tests a wide variety of blocks.
    12  func (cst *consensusSetTester) testBlockSuite() {
    13  	cst.testSimpleBlock()
    14  	cst.testSpendSiacoinsBlock()
    15  	cst.testValidStorageProofBlocks()
    16  	cst.testMissedStorageProofBlocks()
    17  	cst.testFileContractRevision()
    18  	cst.testSpendSiafunds()
    19  }
    20  
    21  // testSimpleBlock mines a simple block (no transactions except those
    22  // automatically added by the miner) and adds it to the consnesus set.
    23  func (cst *consensusSetTester) testSimpleBlock() {
    24  	// Get the starting hash of the consenesus set.
    25  	initialChecksum := cst.cs.dbConsensusChecksum()
    26  	initialHeight := cst.cs.dbBlockHeight()
    27  	initialBlockID := cst.cs.dbCurrentBlockID()
    28  
    29  	// Mine and submit a block
    30  	block, err := cst.miner.AddBlock()
    31  	if err != nil {
    32  		panic(err)
    33  	}
    34  
    35  	// Check that the consensus info functions changed as expected.
    36  	resultingChecksum := cst.cs.dbConsensusChecksum()
    37  	if initialChecksum == resultingChecksum {
    38  		panic("checksum is unchanged after mining a block")
    39  	}
    40  	resultingHeight := cst.cs.dbBlockHeight()
    41  	if resultingHeight != initialHeight+1 {
    42  		panic("height of consensus set did not increase as expected")
    43  	}
    44  	currentPB := cst.cs.dbCurrentProcessedBlock()
    45  	if currentPB.Block.ParentID != initialBlockID {
    46  		panic("new processed block does not have correct information")
    47  	}
    48  	if currentPB.Block.ID() != block.ID() {
    49  		panic("the state's current block is not reporting as the recently mined block.")
    50  	}
    51  	if currentPB.Height != initialHeight+1 {
    52  		panic("the processed block is not reporting the correct height")
    53  	}
    54  	pathID, err := cst.cs.dbGetPath(currentPB.Height)
    55  	if err != nil {
    56  		panic(err)
    57  	}
    58  	if pathID != block.ID() {
    59  		panic("current path does not point to the correct block")
    60  	}
    61  
    62  	// Revert the block that was just added to the consensus set and check for
    63  	// parity with the original state of consensus.
    64  	parent, err := cst.cs.dbGetBlockMap(currentPB.Block.ParentID)
    65  	if err != nil {
    66  		panic(err)
    67  	}
    68  	_, _, err = cst.cs.dbForkBlockchain(parent)
    69  	if err != nil {
    70  		panic(err)
    71  	}
    72  	if cst.cs.dbConsensusChecksum() != initialChecksum {
    73  		panic("adding and reverting a block changed the consensus set")
    74  	}
    75  	// Re-add the block and check for parity with the first time it was added.
    76  	// This test is useful because a different codepath is followed if the
    77  	// diffs have already been generated.
    78  	_, _, err = cst.cs.dbForkBlockchain(currentPB)
    79  	if err != nil {
    80  		panic(err)
    81  	}
    82  	if cst.cs.dbConsensusChecksum() != resultingChecksum {
    83  		panic("adding, reverting, and reading a block was inconsistent with just adding the block")
    84  	}
    85  }
    86  
    87  // TestIntegrationSimpleBlock creates a consensus set tester and uses it to
    88  // call testSimpleBlock.
    89  func TestIntegrationSimpleBlock(t *testing.T) {
    90  	if testing.Short() {
    91  		t.SkipNow()
    92  	}
    93  	t.Parallel()
    94  	cst, err := createConsensusSetTester(t.Name())
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	defer cst.Close()
    99  	cst.testSimpleBlock()
   100  }
   101  
   102  // testSpendSiacoinsBlock mines a block with a transaction spending siacoins
   103  // and adds it to the consensus set.
   104  func (cst *consensusSetTester) testSpendSiacoinsBlock() {
   105  	// Create a random destination address for the output in the transaction.
   106  	destAddr := randAddress()
   107  
   108  	// Create a block containing a transaction with a valid siacoin output.
   109  	txnValue := types.NewCurrency64(1200)
   110  	txnBuilder, err := cst.wallet.StartTransaction()
   111  	if err != nil {
   112  		panic(err)
   113  	}
   114  	err = txnBuilder.FundSiacoins(txnValue)
   115  	if err != nil {
   116  		panic(err)
   117  	}
   118  	outputIndex := txnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: txnValue, UnlockHash: destAddr})
   119  	txnSet, err := txnBuilder.Sign(true)
   120  	if err != nil {
   121  		panic(err)
   122  	}
   123  	err = cst.tpool.AcceptTransactionSet(txnSet)
   124  	if err != nil {
   125  		panic(err)
   126  	}
   127  
   128  	// Mine and apply the block to the consensus set.
   129  	_, err = cst.miner.AddBlock()
   130  	if err != nil {
   131  		panic(err)
   132  	}
   133  
   134  	// See that the destination output was created.
   135  	outputID := txnSet[len(txnSet)-1].SiacoinOutputID(outputIndex)
   136  	sco, err := cst.cs.dbGetSiacoinOutput(outputID)
   137  	if err != nil {
   138  		panic(err)
   139  	}
   140  	if !sco.Value.Equals(txnValue) {
   141  		panic("output added with wrong value")
   142  	}
   143  	if sco.UnlockHash != destAddr {
   144  		panic("output sent to the wrong address")
   145  	}
   146  }
   147  
   148  // TestIntegrationSpendSiacoinsBlock creates a consensus set tester and uses it
   149  // to call testSpendSiacoinsBlock.
   150  func TestIntegrationSpendSiacoinsBlock(t *testing.T) {
   151  	if testing.Short() {
   152  		t.SkipNow()
   153  	}
   154  	t.Parallel()
   155  	cst, err := createConsensusSetTester(t.Name())
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  	defer cst.Close()
   160  	cst.testSpendSiacoinsBlock()
   161  }
   162  
   163  // testValidStorageProofBlocks adds a block with a file contract, and then
   164  // submits a storage proof for that file contract.
   165  func (cst *consensusSetTester) testValidStorageProofBlocks() {
   166  	// COMPATv0.4.0 - Step the block height up past the hardfork amount. This
   167  	// code stops nondeterministic failures when producing storage proofs that
   168  	// is related to buggy old code.
   169  	for cst.cs.dbBlockHeight() <= 10 {
   170  		_, err := cst.miner.AddBlock()
   171  		if err != nil {
   172  			panic(err)
   173  		}
   174  	}
   175  
   176  	// Create a file (as a bytes.Buffer) that will be used for the file
   177  	// contract.
   178  	filesize := uint64(4e3)
   179  	file := fastrand.Bytes(int(filesize))
   180  	merkleRoot := crypto.MerkleRoot(file)
   181  
   182  	// Create a file contract that will be successful.
   183  	validProofDest := randAddress()
   184  	payout := types.NewCurrency64(400e6)
   185  	fc := types.FileContract{
   186  		FileSize:       filesize,
   187  		FileMerkleRoot: merkleRoot,
   188  		WindowStart:    cst.cs.dbBlockHeight() + 1,
   189  		WindowEnd:      cst.cs.dbBlockHeight() + 2,
   190  		Payout:         payout,
   191  		ValidProofOutputs: []types.SiacoinOutput{{
   192  			UnlockHash: validProofDest,
   193  			Value:      types.PostTax(cst.cs.dbBlockHeight(), payout),
   194  		}},
   195  		MissedProofOutputs: []types.SiacoinOutput{{
   196  			UnlockHash: types.UnlockHash{},
   197  			Value:      types.PostTax(cst.cs.dbBlockHeight(), payout),
   198  		}},
   199  	}
   200  
   201  	// Submit a transaction with the file contract.
   202  	oldSiafundPool := cst.cs.dbGetSiafundPool()
   203  	txnBuilder, err := cst.wallet.StartTransaction()
   204  	if err != nil {
   205  		panic(err)
   206  	}
   207  	err = txnBuilder.FundSiacoins(payout)
   208  	if err != nil {
   209  		panic(err)
   210  	}
   211  	fcIndex := txnBuilder.AddFileContract(fc)
   212  	txnSet, err := txnBuilder.Sign(true)
   213  	if err != nil {
   214  		panic(err)
   215  	}
   216  	err = cst.tpool.AcceptTransactionSet(txnSet)
   217  	if err != nil {
   218  		panic(err)
   219  	}
   220  	_, err = cst.miner.AddBlock()
   221  	if err != nil {
   222  		panic(err)
   223  	}
   224  
   225  	// Check that the siafund pool was increased by the tax on the payout.
   226  	siafundPool := cst.cs.dbGetSiafundPool()
   227  	if !siafundPool.Equals(oldSiafundPool.Add(types.Tax(cst.cs.dbBlockHeight()-1, payout))) {
   228  		panic("siafund pool was not increased correctly")
   229  	}
   230  
   231  	// Check that the file contract made it into the database.
   232  	ti := len(txnSet) - 1
   233  	fcid := txnSet[ti].FileContractID(fcIndex)
   234  	_, err = cst.cs.dbGetFileContract(fcid)
   235  	if err != nil {
   236  		panic(err)
   237  	}
   238  
   239  	// Create and submit a storage proof for the file contract.
   240  	segmentIndex, err := cst.cs.StorageProofSegment(fcid)
   241  	if err != nil {
   242  		panic(err)
   243  	}
   244  	segment, hashSet := crypto.MerkleProof(file, segmentIndex)
   245  	sp := types.StorageProof{
   246  		ParentID: fcid,
   247  		HashSet:  hashSet,
   248  	}
   249  	copy(sp.Segment[:], segment)
   250  	txnBuilder, err = cst.wallet.StartTransaction()
   251  	if err != nil {
   252  		panic(err)
   253  	}
   254  	txnBuilder.AddStorageProof(sp)
   255  	txnSet, err = txnBuilder.Sign(true)
   256  	if err != nil {
   257  		panic(err)
   258  	}
   259  	err = cst.tpool.AcceptTransactionSet(txnSet)
   260  	if err != nil {
   261  		panic(err)
   262  	}
   263  	_, err = cst.miner.AddBlock()
   264  	if err != nil {
   265  		panic(err)
   266  	}
   267  
   268  	// Check that the file contract has been removed.
   269  	_, err = cst.cs.dbGetFileContract(fcid)
   270  	if err != errNilItem {
   271  		panic("file contract should not exist in the database")
   272  	}
   273  
   274  	// Check that the siafund pool has not changed.
   275  	postProofPool := cst.cs.dbGetSiafundPool()
   276  	if !postProofPool.Equals(siafundPool) {
   277  		panic("siafund pool should not change after submitting a storage proof")
   278  	}
   279  
   280  	// Check that a delayed output was created for the valid proof.
   281  	spoid := fcid.StorageProofOutputID(types.ProofValid, 0)
   282  	dsco, err := cst.cs.dbGetDSCO(cst.cs.dbBlockHeight()+types.MaturityDelay, spoid)
   283  	if err != nil {
   284  		panic(err)
   285  	}
   286  	if dsco.UnlockHash != fc.ValidProofOutputs[0].UnlockHash {
   287  		panic("wrong unlock hash in dsco")
   288  	}
   289  	if !dsco.Value.Equals(fc.ValidProofOutputs[0].Value) {
   290  		panic("wrong sco value in dsco")
   291  	}
   292  }
   293  
   294  // TestIntegrationValidStorageProofBlocks creates a consensus set tester and
   295  // uses it to call testValidStorageProofBlocks.
   296  func TestIntegrationValidStorageProofBlocks(t *testing.T) {
   297  	if testing.Short() {
   298  		t.SkipNow()
   299  	}
   300  	t.Parallel()
   301  	cst, err := createConsensusSetTester(t.Name())
   302  	if err != nil {
   303  		t.Fatal(err)
   304  	}
   305  	defer cst.Close()
   306  	cst.testValidStorageProofBlocks()
   307  }
   308  
   309  // testMissedStorageProofBlocks adds a block with a file contract, and then
   310  // fails to submit a storage proof before expiration.
   311  func (cst *consensusSetTester) testMissedStorageProofBlocks() {
   312  	// Create a file contract that will be successful.
   313  	filesize := uint64(4e3)
   314  	payout := types.NewCurrency64(400e6)
   315  	missedProofDest := randAddress()
   316  	fc := types.FileContract{
   317  		FileSize:       filesize,
   318  		FileMerkleRoot: crypto.Hash{},
   319  		WindowStart:    cst.cs.dbBlockHeight() + 1,
   320  		WindowEnd:      cst.cs.dbBlockHeight() + 2,
   321  		Payout:         payout,
   322  		ValidProofOutputs: []types.SiacoinOutput{{
   323  			UnlockHash: types.UnlockHash{},
   324  			Value:      types.PostTax(cst.cs.dbBlockHeight(), payout),
   325  		}},
   326  		MissedProofOutputs: []types.SiacoinOutput{{
   327  			UnlockHash: missedProofDest,
   328  			Value:      types.PostTax(cst.cs.dbBlockHeight(), payout),
   329  		}},
   330  	}
   331  
   332  	// Submit a transaction with the file contract.
   333  	oldSiafundPool := cst.cs.dbGetSiafundPool()
   334  	txnBuilder, err := cst.wallet.StartTransaction()
   335  	if err != nil {
   336  		panic(err)
   337  	}
   338  	err = txnBuilder.FundSiacoins(payout)
   339  	if err != nil {
   340  		panic(err)
   341  	}
   342  	fcIndex := txnBuilder.AddFileContract(fc)
   343  	txnSet, err := txnBuilder.Sign(true)
   344  	if err != nil {
   345  		panic(err)
   346  	}
   347  	err = cst.tpool.AcceptTransactionSet(txnSet)
   348  	if err != nil {
   349  		panic(err)
   350  	}
   351  	_, err = cst.miner.AddBlock()
   352  	if err != nil {
   353  		panic(err)
   354  	}
   355  
   356  	// Check that the siafund pool was increased by the tax on the payout.
   357  	siafundPool := cst.cs.dbGetSiafundPool()
   358  	if !siafundPool.Equals(oldSiafundPool.Add(types.Tax(cst.cs.dbBlockHeight()-1, payout))) {
   359  		panic("siafund pool was not increased correctly")
   360  	}
   361  
   362  	// Check that the file contract made it into the database.
   363  	ti := len(txnSet) - 1
   364  	fcid := txnSet[ti].FileContractID(fcIndex)
   365  	_, err = cst.cs.dbGetFileContract(fcid)
   366  	if err != nil {
   367  		panic(err)
   368  	}
   369  
   370  	// Mine a block to close the storage proof window.
   371  	_, err = cst.miner.AddBlock()
   372  	if err != nil {
   373  		panic(err)
   374  	}
   375  
   376  	// Check that the file contract has been removed.
   377  	_, err = cst.cs.dbGetFileContract(fcid)
   378  	if err != errNilItem {
   379  		panic("file contract should not exist in the database")
   380  	}
   381  
   382  	// Check that the siafund pool has not changed.
   383  	postProofPool := cst.cs.dbGetSiafundPool()
   384  	if !postProofPool.Equals(siafundPool) {
   385  		panic("siafund pool should not change after submitting a storage proof")
   386  	}
   387  
   388  	// Check that a delayed output was created for the missed proof.
   389  	spoid := fcid.StorageProofOutputID(types.ProofMissed, 0)
   390  	dsco, err := cst.cs.dbGetDSCO(cst.cs.dbBlockHeight()+types.MaturityDelay, spoid)
   391  	if err != nil {
   392  		panic(err)
   393  	}
   394  	if dsco.UnlockHash != fc.MissedProofOutputs[0].UnlockHash {
   395  		panic("wrong unlock hash in dsco")
   396  	}
   397  	if !dsco.Value.Equals(fc.MissedProofOutputs[0].Value) {
   398  		panic("wrong sco value in dsco")
   399  	}
   400  }
   401  
   402  // TestIntegrationMissedStorageProofBlocks creates a consensus set tester and
   403  // uses it to call testMissedStorageProofBlocks.
   404  func TestIntegrationMissedStorageProofBlocks(t *testing.T) {
   405  	if testing.Short() {
   406  		t.SkipNow()
   407  	}
   408  	t.Parallel()
   409  	cst, err := createConsensusSetTester(t.Name())
   410  	if err != nil {
   411  		t.Fatal(err)
   412  	}
   413  	defer cst.Close()
   414  	cst.testMissedStorageProofBlocks()
   415  }
   416  
   417  // testFileContractRevision creates and revises a file contract on the
   418  // blockchain.
   419  func (cst *consensusSetTester) testFileContractRevision() {
   420  	// COMPATv0.4.0 - Step the block height up past the hardfork amount. This
   421  	// code stops nondeterministic failures when producing storage proofs that
   422  	// is related to buggy old code.
   423  	for cst.cs.dbBlockHeight() <= 10 {
   424  		_, err := cst.miner.AddBlock()
   425  		if err != nil {
   426  			panic(err)
   427  		}
   428  	}
   429  
   430  	// Create a file (as a bytes.Buffer) that will be used for the file
   431  	// contract.
   432  	filesize := uint64(4e3)
   433  	file := fastrand.Bytes(int(filesize))
   434  	merkleRoot := crypto.MerkleRoot(file)
   435  
   436  	// Create a spendable unlock hash for the file contract.
   437  	sk, pk := crypto.GenerateKeyPair()
   438  	uc := types.UnlockConditions{
   439  		PublicKeys: []types.SiaPublicKey{{
   440  			Algorithm: types.SignatureEd25519,
   441  			Key:       pk[:],
   442  		}},
   443  		SignaturesRequired: 1,
   444  	}
   445  
   446  	// Create a file contract that will be revised.
   447  	validProofDest := randAddress()
   448  	payout := types.NewCurrency64(400e6)
   449  	fc := types.FileContract{
   450  		FileSize:       filesize,
   451  		FileMerkleRoot: crypto.Hash{},
   452  		WindowStart:    cst.cs.dbBlockHeight() + 2,
   453  		WindowEnd:      cst.cs.dbBlockHeight() + 3,
   454  		Payout:         payout,
   455  		ValidProofOutputs: []types.SiacoinOutput{{
   456  			UnlockHash: validProofDest,
   457  			Value:      types.PostTax(cst.cs.dbBlockHeight(), payout),
   458  		}},
   459  		MissedProofOutputs: []types.SiacoinOutput{{
   460  			UnlockHash: types.UnlockHash{},
   461  			Value:      types.PostTax(cst.cs.dbBlockHeight(), payout),
   462  		}},
   463  		UnlockHash: uc.UnlockHash(),
   464  	}
   465  
   466  	// Submit a transaction with the file contract.
   467  	txnBuilder, err := cst.wallet.StartTransaction()
   468  	if err != nil {
   469  		panic(err)
   470  	}
   471  	err = txnBuilder.FundSiacoins(payout)
   472  	if err != nil {
   473  		panic(err)
   474  	}
   475  	fcIndex := txnBuilder.AddFileContract(fc)
   476  	txnSet, err := txnBuilder.Sign(true)
   477  	if err != nil {
   478  		panic(err)
   479  	}
   480  	err = cst.tpool.AcceptTransactionSet(txnSet)
   481  	if err != nil {
   482  		panic(err)
   483  	}
   484  	_, err = cst.miner.AddBlock()
   485  	if err != nil {
   486  		panic(err)
   487  	}
   488  
   489  	// Submit a revision for the file contract.
   490  	ti := len(txnSet) - 1
   491  	fcid := txnSet[ti].FileContractID(fcIndex)
   492  	fcr := types.FileContractRevision{
   493  		ParentID:          fcid,
   494  		UnlockConditions:  uc,
   495  		NewRevisionNumber: 69292,
   496  
   497  		NewFileSize:           filesize,
   498  		NewFileMerkleRoot:     merkleRoot,
   499  		NewWindowStart:        cst.cs.dbBlockHeight() + 1,
   500  		NewWindowEnd:          cst.cs.dbBlockHeight() + 2,
   501  		NewValidProofOutputs:  fc.ValidProofOutputs,
   502  		NewMissedProofOutputs: fc.MissedProofOutputs,
   503  		NewUnlockHash:         uc.UnlockHash(),
   504  	}
   505  	ts := types.TransactionSignature{
   506  		ParentID:       crypto.Hash(fcid),
   507  		CoveredFields:  types.CoveredFields{WholeTransaction: true},
   508  		PublicKeyIndex: 0,
   509  	}
   510  	txn := types.Transaction{
   511  		FileContractRevisions: []types.FileContractRevision{fcr},
   512  		TransactionSignatures: []types.TransactionSignature{ts},
   513  	}
   514  	encodedSig := crypto.SignHash(txn.SigHash(0), sk)
   515  	txn.TransactionSignatures[0].Signature = encodedSig[:]
   516  	err = cst.tpool.AcceptTransactionSet([]types.Transaction{txn})
   517  	if err != nil {
   518  		panic(err)
   519  	}
   520  	_, err = cst.miner.AddBlock()
   521  	if err != nil {
   522  		panic(err)
   523  	}
   524  
   525  	// Create and submit a storage proof for the file contract.
   526  	segmentIndex, err := cst.cs.StorageProofSegment(fcid)
   527  	if err != nil {
   528  		panic(err)
   529  	}
   530  	segment, hashSet := crypto.MerkleProof(file, segmentIndex)
   531  	sp := types.StorageProof{
   532  		ParentID: fcid,
   533  		HashSet:  hashSet,
   534  	}
   535  	copy(sp.Segment[:], segment)
   536  	txnBuilder, err = cst.wallet.StartTransaction()
   537  	if err != nil {
   538  		panic(err)
   539  	}
   540  	txnBuilder.AddStorageProof(sp)
   541  	txnSet, err = txnBuilder.Sign(true)
   542  	if err != nil {
   543  		panic(err)
   544  	}
   545  	err = cst.tpool.AcceptTransactionSet(txnSet)
   546  	if err != nil {
   547  		panic(err)
   548  	}
   549  	_, err = cst.miner.AddBlock()
   550  	if err != nil {
   551  		panic(err)
   552  	}
   553  
   554  	// Check that the file contract has been removed.
   555  	_, err = cst.cs.dbGetFileContract(fcid)
   556  	if err != errNilItem {
   557  		panic("file contract should not exist in the database")
   558  	}
   559  }
   560  
   561  // TestIntegrationFileContractRevision creates a consensus set tester and uses
   562  // it to call testFileContractRevision.
   563  func TestIntegrationFileContractRevision(t *testing.T) {
   564  	if testing.Short() {
   565  		t.SkipNow()
   566  	}
   567  	t.Parallel()
   568  	cst, err := createConsensusSetTester(t.Name())
   569  	if err != nil {
   570  		t.Fatal(err)
   571  	}
   572  	defer cst.Close()
   573  	cst.testFileContractRevision()
   574  }
   575  
   576  // testSpendSiafunds spends siafunds on the blockchain.
   577  func (cst *consensusSetTester) testSpendSiafunds() {
   578  	// Create a random destination address for the output in the transaction.
   579  	destAddr := randAddress()
   580  
   581  	// Create a block containing a transaction with a valid siafund output.
   582  	txnValue := types.NewCurrency64(3)
   583  	txnBuilder, err := cst.wallet.StartTransaction()
   584  	if err != nil {
   585  		panic(err)
   586  	}
   587  	err = txnBuilder.FundSiafunds(txnValue)
   588  	if err != nil {
   589  		panic(err)
   590  	}
   591  	outputIndex := txnBuilder.AddSiafundOutput(types.SiafundOutput{Value: txnValue, UnlockHash: destAddr})
   592  	txnSet, err := txnBuilder.Sign(true)
   593  	if err != nil {
   594  		panic(err)
   595  	}
   596  	err = cst.tpool.AcceptTransactionSet(txnSet)
   597  	if err != nil {
   598  		panic(err)
   599  	}
   600  
   601  	// Find the siafund inputs used in the txn set.
   602  	var claimValues []types.Currency
   603  	var claimIDs []types.SiacoinOutputID
   604  	for _, txn := range txnSet {
   605  		for _, sfi := range txn.SiafundInputs {
   606  			sfo, err := cst.cs.dbGetSiafundOutput(sfi.ParentID)
   607  			if err != nil {
   608  				// It's not in the database because it's in an earlier
   609  				// transaction: disregard it - testing the first layer of
   610  				// dependencies is sufficient.
   611  				continue
   612  			}
   613  			poolDiff := cst.cs.dbGetSiafundPool().Sub(sfo.ClaimStart)
   614  			value := poolDiff.Div(types.SiafundCount).Mul(sfo.Value)
   615  			claimValues = append(claimValues, value)
   616  			claimIDs = append(claimIDs, sfi.ParentID.SiaClaimOutputID())
   617  		}
   618  	}
   619  	if len(claimValues) == 0 {
   620  		panic("no siafund outputs created?")
   621  	}
   622  
   623  	// Mine and apply the block to the consensus set.
   624  	_, err = cst.miner.AddBlock()
   625  	if err != nil {
   626  		panic(err)
   627  	}
   628  
   629  	// See that the destination output was created.
   630  	outputID := txnSet[len(txnSet)-1].SiafundOutputID(outputIndex)
   631  	sfo, err := cst.cs.dbGetSiafundOutput(outputID)
   632  	if err != nil {
   633  		panic(err)
   634  	}
   635  	if !sfo.Value.Equals(txnValue) {
   636  		panic("output added with wrong value")
   637  	}
   638  	if sfo.UnlockHash != destAddr {
   639  		panic("output sent to the wrong address")
   640  	}
   641  	if !sfo.ClaimStart.Equals(cst.cs.dbGetSiafundPool()) {
   642  		panic("ClaimStart is not being set correctly")
   643  	}
   644  
   645  	// Verify that all expected claims were created and added to the set of
   646  	// delayed siacoin outputs.
   647  	for i, id := range claimIDs {
   648  		dsco, err := cst.cs.dbGetDSCO(cst.cs.dbBlockHeight()+types.MaturityDelay, id)
   649  		if err != nil {
   650  			panic(err)
   651  		}
   652  		if !dsco.Value.Equals(claimValues[i]) {
   653  			panic("expected a different claim value on the siaclaim")
   654  		}
   655  	}
   656  }
   657  
   658  // TestIntegrationSpendSiafunds creates a consensus set tester and uses it
   659  // to call testSpendSiafunds.
   660  func (cst *consensusSetTester) TestIntegrationSpendSiafunds(t *testing.T) {
   661  	if testing.Short() {
   662  		t.SkipNow()
   663  	}
   664  	t.Parallel()
   665  	cst, err := createConsensusSetTester(t.Name())
   666  	if err != nil {
   667  		t.Fatal(err)
   668  	}
   669  	defer cst.Close()
   670  	cst.testSpendSiafunds()
   671  }
   672  
   673  // testDelayedOutputMaturity adds blocks that result in many delayed outputs
   674  // maturing at the same time, verifying that bulk maturity is handled
   675  // correctly.
   676  
   677  // TestRegressionDelayedOutputMaturity creates a consensus set tester and uses
   678  // it to call testDelayedOutputMaturity. In the past, bolt's ForEach function
   679  // had been used incorrectly resulting in the incorrect processing of bulk
   680  // delayed outputs.
   681  
   682  // testFileContractMaturity adds blocks that result in many file contracts
   683  // being closed at the same time.
   684  
   685  // TestRegressionFileContractMaturity creates a consensus set tester and uses
   686  // it to call testFileContractMaturity. In the past, bolt's ForEach function
   687  // had been used incorrectly, resulting in the incorrect processing of bulk
   688  // file contracts.
   689  
   690  /*
   691  // testPaymentChannelBlocks submits blocks to set up, use, and close a payment
   692  // channel.
   693  func (cst *consensusSetTester) testPaymentChannelBlocks() error {
   694  	// The current method of doing payment channels is gimped because public
   695  	// keys do not have timelocks. We will be hardforking to include timelocks
   696  	// in public keys in 0.4.0, but in the meantime we need an alternate
   697  	// method.
   698  
   699  	// Gimped payment channels: 2-of-2 multisig where one key is controlled by
   700  	// the funding entity, and one key is controlled by the receiving entity. An
   701  	// address is created containing both keys, and then the funding entity
   702  	// creates, but does not sign, a transaction sending coins to the channel
   703  	// address. A second transaction is created that sends all the coins in the
   704  	// funding output back to the funding entity. The receiving entity signs the
   705  	// transaction with a timelocked signature. The funding entity will get the
   706  	// refund after T blocks as long as the output is not double spent. The
   707  	// funding entity then signs the first transaction and opens the channel.
   708  	//
   709  	// Creating the channel:
   710  	//	1. Create a 2-of-2 unlock conditions, one key held by each entity.
   711  	//	2. Funding entity creates, but does not sign, a transaction sending
   712  	//		money to the payment channel address. (txn A)
   713  	//	3. Funding entity creates and signs a transaction spending the output
   714  	//		created in txn A that sends all the money back as a refund. (txn B)
   715  	//	4. Receiving entity signs txn B with a timelocked signature, so that the
   716  	//		funding entity cannot get the refund for several days. The funding entity
   717  	//		is given a fully signed and eventually-spendable txn B.
   718  	//	5. The funding entity signs and broadcasts txn A.
   719  	//
   720  	// Using the channel:
   721  	//	Each the receiving entity and the funding entity keeps a record of how
   722  	//	much has been sent down the unclosed channel, and watches the
   723  	//	blockchain for a channel closing transaction. To send more money down
   724  	//	the channel, the funding entity creates and signs a transaction sending
   725  	//	X+y coins to the receiving entity from the channel address. The
   726  	//	transaction is sent to the receiving entity, who will keep it and
   727  	//	potentially sign and broadcast it later. The funding entity will only
   728  	//	send money down the channel if 'work' or some other sort of event has
   729  	//	completed that indicates the receiving entity should get more money.
   730  	//
   731  	// Closing the channel:
   732  	//	The receiving entity will sign the transaction that pays them the most
   733  	//	money and then broadcast that transaction. This will spend the output
   734  	//	and close the channel, invalidating txn B and preventing any future
   735  	//	transactions from being made over the channel. The channel must be
   736  	//	closed before the timelock expires on the second signature in txn B,
   737  	//	otherwise the funding entity will be able to get a full refund.
   738  	//
   739  	//	The funding entity should be waiting until either the receiving entity
   740  	//	closes the channel or the timelock expires. If the receiving entity
   741  	//	closes the channel, all is good. If not, then the funding entity can
   742  	//	close the channel and get a full refund.
   743  
   744  	// Create a 2-of-2 unlock conditions, 1 key for each the sender and the
   745  	// receiver in the payment channel.
   746  	sk1, pk1, err := crypto.StdKeyGen.Generate() // Funding entity.
   747  	if err != nil {
   748  		return err
   749  	}
   750  	sk2, pk2, err := crypto.StdKeyGen.Generate() // Receiving entity.
   751  	if err != nil {
   752  		return err
   753  	}
   754  	uc := types.UnlockConditions{
   755  		PublicKeys: []types.SiaPublicKey{
   756  			{
   757  				Algorithm: types.SignatureEd25519,
   758  				Key:       pk1[:],
   759  			},
   760  			{
   761  				Algorithm: types.SignatureEd25519,
   762  				Key:       pk2[:],
   763  			},
   764  		},
   765  		SignaturesRequired: 2,
   766  	}
   767  	channelAddress := uc.UnlockHash()
   768  
   769  	// Funding entity creates but does not sign a transaction that funds the
   770  	// channel address. Because the wallet is not very flexible, the channel
   771  	// txn needs to be fully custom. To get a custom txn, manually create an
   772  	// address and then use the wallet to fund that address.
   773  	channelSize := types.NewCurrency64(10e3)
   774  	channelFundingSK, channelFundingPK, err := crypto.StdKeyGen.Generate()
   775  	if err != nil {
   776  		return err
   777  	}
   778  	channelFundingUC := types.UnlockConditions{
   779  		PublicKeys: []types.SiaPublicKey{{
   780  			Algorithm: types.SignatureEd25519,
   781  			Key:       channelFundingPK[:],
   782  		}},
   783  		SignaturesRequired: 1,
   784  	}
   785  	channelFundingAddr := channelFundingUC.UnlockHash()
   786  	fundTxnBuilder := cst.wallet.StartTransaction()
   787  	if err != nil {
   788  		return err
   789  	}
   790  	err = fundTxnBuilder.FundSiacoins(channelSize)
   791  	if err != nil {
   792  		return err
   793  	}
   794  	scoFundIndex := fundTxnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: channelSize, UnlockHash: channelFundingAddr})
   795  	fundTxnSet, err := fundTxnBuilder.Sign(true)
   796  	if err != nil {
   797  		return err
   798  	}
   799  	fundOutputID := fundTxnSet[len(fundTxnSet)-1].SiacoinOutputID(int(scoFundIndex))
   800  	channelTxn := types.Transaction{
   801  		SiacoinInputs: []types.SiacoinInput{{
   802  			ParentID:         fundOutputID,
   803  			UnlockConditions: channelFundingUC,
   804  		}},
   805  		SiacoinOutputs: []types.SiacoinOutput{{
   806  			Value:      channelSize,
   807  			UnlockHash: channelAddress,
   808  		}},
   809  		TransactionSignatures: []types.TransactionSignature{{
   810  			ParentID:       crypto.Hash(fundOutputID),
   811  			PublicKeyIndex: 0,
   812  			CoveredFields:  types.CoveredFields{WholeTransaction: true},
   813  		}},
   814  	}
   815  
   816  	// Funding entity creates and signs a transaction that spends the full
   817  	// channel output.
   818  	channelOutputID := channelTxn.SiacoinOutputID(0)
   819  	refundUC, err := cst.wallet.NextAddress()
   820  	refundAddr := refundUC.UnlockHash()
   821  	if err != nil {
   822  		return err
   823  	}
   824  	refundTxn := types.Transaction{
   825  		SiacoinInputs: []types.SiacoinInput{{
   826  			ParentID:         channelOutputID,
   827  			UnlockConditions: uc,
   828  		}},
   829  		SiacoinOutputs: []types.SiacoinOutput{{
   830  			Value:      channelSize,
   831  			UnlockHash: refundAddr,
   832  		}},
   833  		TransactionSignatures: []types.TransactionSignature{{
   834  			ParentID:       crypto.Hash(channelOutputID),
   835  			PublicKeyIndex: 0,
   836  			CoveredFields:  types.CoveredFields{WholeTransaction: true},
   837  		}},
   838  	}
   839  	sigHash := refundTxn.SigHash(0)
   840  	cryptoSig1, err := crypto.SignHash(sigHash, sk1)
   841  	if err != nil {
   842  		return err
   843  	}
   844  	refundTxn.TransactionSignatures[0].Signature = cryptoSig1[:]
   845  
   846  	// Receiving entity signs the transaction that spends the full channel
   847  	// output, but with a timelock.
   848  	refundTxn.TransactionSignatures = append(refundTxn.TransactionSignatures, types.TransactionSignature{
   849  		ParentID:       crypto.Hash(channelOutputID),
   850  		PublicKeyIndex: 1,
   851  		Timelock:       cst.cs.dbBlockHeight() + 2,
   852  		CoveredFields:  types.CoveredFields{WholeTransaction: true},
   853  	})
   854  	sigHash = refundTxn.SigHash(1)
   855  	cryptoSig2, err := crypto.SignHash(sigHash, sk2)
   856  	if err != nil {
   857  		return err
   858  	}
   859  	refundTxn.TransactionSignatures[1].Signature = cryptoSig2[:]
   860  
   861  	// Funding entity will now sign and broadcast the funding transaction.
   862  	sigHash = channelTxn.SigHash(0)
   863  	cryptoSig0, err := crypto.SignHash(sigHash, channelFundingSK)
   864  	if err != nil {
   865  		return err
   866  	}
   867  	channelTxn.TransactionSignatures[0].Signature = cryptoSig0[:]
   868  	err = cst.tpool.AcceptTransactionSet(append(fundTxnSet, channelTxn))
   869  	if err != nil {
   870  		return err
   871  	}
   872  	// Put the txn in a block.
   873  	_, err = cst.miner.AddBlock()
   874  	if err != nil {
   875  		return err
   876  	}
   877  
   878  	// Try to submit the refund transaction before the timelock has expired.
   879  	err = cst.tpool.AcceptTransactionSet([]types.Transaction{refundTxn})
   880  	if err != types.ErrPrematureSignature {
   881  		return err
   882  	}
   883  
   884  	// Create a transaction that has partially used the channel, and submit it
   885  	// to the blockchain to close the channel.
   886  	closeTxn := types.Transaction{
   887  		SiacoinInputs: []types.SiacoinInput{{
   888  			ParentID:         channelOutputID,
   889  			UnlockConditions: uc,
   890  		}},
   891  		SiacoinOutputs: []types.SiacoinOutput{
   892  			{
   893  				Value:      channelSize.Sub(types.NewCurrency64(5)),
   894  				UnlockHash: refundAddr,
   895  			},
   896  			{
   897  				Value: types.NewCurrency64(5),
   898  			},
   899  		},
   900  		TransactionSignatures: []types.TransactionSignature{
   901  			{
   902  				ParentID:       crypto.Hash(channelOutputID),
   903  				PublicKeyIndex: 0,
   904  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
   905  			},
   906  			{
   907  				ParentID:       crypto.Hash(channelOutputID),
   908  				PublicKeyIndex: 1,
   909  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
   910  			},
   911  		},
   912  	}
   913  	sigHash = closeTxn.SigHash(0)
   914  	cryptoSig3, err := crypto.SignHash(sigHash, sk1)
   915  	if err != nil {
   916  		return err
   917  	}
   918  	closeTxn.TransactionSignatures[0].Signature = cryptoSig3[:]
   919  	sigHash = closeTxn.SigHash(1)
   920  	cryptoSig4, err := crypto.SignHash(sigHash, sk2)
   921  	if err != nil {
   922  		return err
   923  	}
   924  	closeTxn.TransactionSignatures[1].Signature = cryptoSig4[:]
   925  	err = cst.tpool.AcceptTransactionSet([]types.Transaction{closeTxn})
   926  	if err != nil {
   927  		return err
   928  	}
   929  
   930  	// Mine the block with the transaction.
   931  	_, err = cst.miner.AddBlock()
   932  	if err != nil {
   933  		return err
   934  	}
   935  	closeRefundID := closeTxn.SiacoinOutputID(0)
   936  	closePaymentID := closeTxn.SiacoinOutputID(1)
   937  	exists := cst.cs.db.inSiacoinOutputs(closeRefundID)
   938  	if !exists {
   939  		return errors.New("close txn refund output doesn't exist")
   940  	}
   941  	exists = cst.cs.db.inSiacoinOutputs(closePaymentID)
   942  	if !exists {
   943  		return errors.New("close txn payment output doesn't exist")
   944  	}
   945  
   946  	// Create a payment channel where the receiving entity never responds to
   947  	// the initial transaction.
   948  	{
   949  		// Funding entity creates but does not sign a transaction that funds the
   950  		// channel address. Because the wallet is not very flexible, the channel
   951  		// txn needs to be fully custom. To get a custom txn, manually create an
   952  		// address and then use the wallet to fund that address.
   953  		channelSize := types.NewCurrency64(10e3)
   954  		channelFundingSK, channelFundingPK, err := crypto.StdKeyGen.Generate()
   955  		if err != nil {
   956  			return err
   957  		}
   958  		channelFundingUC := types.UnlockConditions{
   959  			PublicKeys: []types.SiaPublicKey{{
   960  				Algorithm: types.SignatureEd25519,
   961  				Key:       channelFundingPK[:],
   962  			}},
   963  			SignaturesRequired: 1,
   964  		}
   965  		channelFundingAddr := channelFundingUC.UnlockHash()
   966  		fundTxnBuilder := cst.wallet.StartTransaction()
   967  		err = fundTxnBuilder.FundSiacoins(channelSize)
   968  		if err != nil {
   969  			return err
   970  		}
   971  		scoFundIndex := fundTxnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: channelSize, UnlockHash: channelFundingAddr})
   972  		fundTxnSet, err := fundTxnBuilder.Sign(true)
   973  		if err != nil {
   974  			return err
   975  		}
   976  		fundOutputID := fundTxnSet[len(fundTxnSet)-1].SiacoinOutputID(int(scoFundIndex))
   977  		channelTxn := types.Transaction{
   978  			SiacoinInputs: []types.SiacoinInput{{
   979  				ParentID:         fundOutputID,
   980  				UnlockConditions: channelFundingUC,
   981  			}},
   982  			SiacoinOutputs: []types.SiacoinOutput{{
   983  				Value:      channelSize,
   984  				UnlockHash: channelAddress,
   985  			}},
   986  			TransactionSignatures: []types.TransactionSignature{{
   987  				ParentID:       crypto.Hash(fundOutputID),
   988  				PublicKeyIndex: 0,
   989  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
   990  			}},
   991  		}
   992  
   993  		// Funding entity creates and signs a transaction that spends the full
   994  		// channel output.
   995  		channelOutputID := channelTxn.SiacoinOutputID(0)
   996  		refundUC, err := cst.wallet.NextAddress()
   997  		refundAddr := refundUC.UnlockHash()
   998  		if err != nil {
   999  			return err
  1000  		}
  1001  		refundTxn := types.Transaction{
  1002  			SiacoinInputs: []types.SiacoinInput{{
  1003  				ParentID:         channelOutputID,
  1004  				UnlockConditions: uc,
  1005  			}},
  1006  			SiacoinOutputs: []types.SiacoinOutput{{
  1007  				Value:      channelSize,
  1008  				UnlockHash: refundAddr,
  1009  			}},
  1010  			TransactionSignatures: []types.TransactionSignature{{
  1011  				ParentID:       crypto.Hash(channelOutputID),
  1012  				PublicKeyIndex: 0,
  1013  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
  1014  			}},
  1015  		}
  1016  		sigHash := refundTxn.SigHash(0)
  1017  		cryptoSig1, err := crypto.SignHash(sigHash, sk1)
  1018  		if err != nil {
  1019  			return err
  1020  		}
  1021  		refundTxn.TransactionSignatures[0].Signature = cryptoSig1[:]
  1022  
  1023  		// Receiving entity never communitcates, funding entity must reclaim
  1024  		// the 'channelSize' coins that were intended to go to the channel.
  1025  		reclaimUC, err := cst.wallet.NextAddress()
  1026  		reclaimAddr := reclaimUC.UnlockHash()
  1027  		if err != nil {
  1028  			return err
  1029  		}
  1030  		reclaimTxn := types.Transaction{
  1031  			SiacoinInputs: []types.SiacoinInput{{
  1032  				ParentID:         fundOutputID,
  1033  				UnlockConditions: channelFundingUC,
  1034  			}},
  1035  			SiacoinOutputs: []types.SiacoinOutput{{
  1036  				Value:      channelSize,
  1037  				UnlockHash: reclaimAddr,
  1038  			}},
  1039  			TransactionSignatures: []types.TransactionSignature{{
  1040  				ParentID:       crypto.Hash(fundOutputID),
  1041  				PublicKeyIndex: 0,
  1042  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
  1043  			}},
  1044  		}
  1045  		sigHash = reclaimTxn.SigHash(0)
  1046  		cryptoSig, err := crypto.SignHash(sigHash, channelFundingSK)
  1047  		if err != nil {
  1048  			return err
  1049  		}
  1050  		reclaimTxn.TransactionSignatures[0].Signature = cryptoSig[:]
  1051  		err = cst.tpool.AcceptTransactionSet(append(fundTxnSet, reclaimTxn))
  1052  		if err != nil {
  1053  			return err
  1054  		}
  1055  		block, _ := cst.miner.FindBlock()
  1056  		err = cst.cs.AcceptBlock(block)
  1057  		if err != nil {
  1058  			return err
  1059  		}
  1060  		reclaimOutputID := reclaimTxn.SiacoinOutputID(0)
  1061  		exists := cst.cs.db.inSiacoinOutputs(reclaimOutputID)
  1062  		if !exists {
  1063  			return errors.New("failed to reclaim an output that belongs to the funding entity")
  1064  		}
  1065  	}
  1066  
  1067  	// Create a channel and the open the channel, but close the channel using
  1068  	// the timelocked signature.
  1069  	{
  1070  		// Funding entity creates but does not sign a transaction that funds the
  1071  		// channel address. Because the wallet is not very flexible, the channel
  1072  		// txn needs to be fully custom. To get a custom txn, manually create an
  1073  		// address and then use the wallet to fund that address.
  1074  		channelSize := types.NewCurrency64(10e3)
  1075  		channelFundingSK, channelFundingPK, err := crypto.StdKeyGen.Generate()
  1076  		if err != nil {
  1077  			return err
  1078  		}
  1079  		channelFundingUC := types.UnlockConditions{
  1080  			PublicKeys: []types.SiaPublicKey{{
  1081  				Algorithm: types.SignatureEd25519,
  1082  				Key:       channelFundingPK[:],
  1083  			}},
  1084  			SignaturesRequired: 1,
  1085  		}
  1086  		channelFundingAddr := channelFundingUC.UnlockHash()
  1087  		fundTxnBuilder := cst.wallet.StartTransaction()
  1088  		err = fundTxnBuilder.FundSiacoins(channelSize)
  1089  		if err != nil {
  1090  			return err
  1091  		}
  1092  		scoFundIndex := fundTxnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: channelSize, UnlockHash: channelFundingAddr})
  1093  		fundTxnSet, err := fundTxnBuilder.Sign(true)
  1094  		if err != nil {
  1095  			return err
  1096  		}
  1097  		fundOutputID := fundTxnSet[len(fundTxnSet)-1].SiacoinOutputID(int(scoFundIndex))
  1098  		channelTxn := types.Transaction{
  1099  			SiacoinInputs: []types.SiacoinInput{{
  1100  				ParentID:         fundOutputID,
  1101  				UnlockConditions: channelFundingUC,
  1102  			}},
  1103  			SiacoinOutputs: []types.SiacoinOutput{{
  1104  				Value:      channelSize,
  1105  				UnlockHash: channelAddress,
  1106  			}},
  1107  			TransactionSignatures: []types.TransactionSignature{{
  1108  				ParentID:       crypto.Hash(fundOutputID),
  1109  				PublicKeyIndex: 0,
  1110  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
  1111  			}},
  1112  		}
  1113  
  1114  		// Funding entity creates and signs a transaction that spends the full
  1115  		// channel output.
  1116  		channelOutputID := channelTxn.SiacoinOutputID(0)
  1117  		refundUC, err := cst.wallet.NextAddress()
  1118  		refundAddr := refundUC.UnlockHash()
  1119  		if err != nil {
  1120  			return err
  1121  		}
  1122  		refundTxn := types.Transaction{
  1123  			SiacoinInputs: []types.SiacoinInput{{
  1124  				ParentID:         channelOutputID,
  1125  				UnlockConditions: uc,
  1126  			}},
  1127  			SiacoinOutputs: []types.SiacoinOutput{{
  1128  				Value:      channelSize,
  1129  				UnlockHash: refundAddr,
  1130  			}},
  1131  			TransactionSignatures: []types.TransactionSignature{{
  1132  				ParentID:       crypto.Hash(channelOutputID),
  1133  				PublicKeyIndex: 0,
  1134  				CoveredFields:  types.CoveredFields{WholeTransaction: true},
  1135  			}},
  1136  		}
  1137  		sigHash := refundTxn.SigHash(0)
  1138  		cryptoSig1, err := crypto.SignHash(sigHash, sk1)
  1139  		if err != nil {
  1140  			return err
  1141  		}
  1142  		refundTxn.TransactionSignatures[0].Signature = cryptoSig1[:]
  1143  
  1144  		// Receiving entity signs the transaction that spends the full channel
  1145  		// output, but with a timelock.
  1146  		refundTxn.TransactionSignatures = append(refundTxn.TransactionSignatures, types.TransactionSignature{
  1147  			ParentID:       crypto.Hash(channelOutputID),
  1148  			PublicKeyIndex: 1,
  1149  			Timelock:       cst.cs.dbBlockHeight() + 2,
  1150  			CoveredFields:  types.CoveredFields{WholeTransaction: true},
  1151  		})
  1152  		sigHash = refundTxn.SigHash(1)
  1153  		cryptoSig2, err := crypto.SignHash(sigHash, sk2)
  1154  		if err != nil {
  1155  			return err
  1156  		}
  1157  		refundTxn.TransactionSignatures[1].Signature = cryptoSig2[:]
  1158  
  1159  		// Funding entity will now sign and broadcast the funding transaction.
  1160  		sigHash = channelTxn.SigHash(0)
  1161  		cryptoSig0, err := crypto.SignHash(sigHash, channelFundingSK)
  1162  		if err != nil {
  1163  			return err
  1164  		}
  1165  		channelTxn.TransactionSignatures[0].Signature = cryptoSig0[:]
  1166  		err = cst.tpool.AcceptTransactionSet(append(fundTxnSet, channelTxn))
  1167  		if err != nil {
  1168  			return err
  1169  		}
  1170  		// Put the txn in a block.
  1171  		block, _ := cst.miner.FindBlock()
  1172  		err = cst.cs.AcceptBlock(block)
  1173  		if err != nil {
  1174  			return err
  1175  		}
  1176  
  1177  		// Receiving entity never signs another transaction, so the funding
  1178  		// entity waits until the timelock is complete, and then submits the
  1179  		// refundTxn.
  1180  		for i := 0; i < 3; i++ {
  1181  			block, _ := cst.miner.FindBlock()
  1182  			err = cst.cs.AcceptBlock(block)
  1183  			if err != nil {
  1184  				return err
  1185  			}
  1186  		}
  1187  		err = cst.tpool.AcceptTransactionSet([]types.Transaction{refundTxn})
  1188  		if err != nil {
  1189  			return err
  1190  		}
  1191  		block, _ = cst.miner.FindBlock()
  1192  		err = cst.cs.AcceptBlock(block)
  1193  		if err != nil {
  1194  			return err
  1195  		}
  1196  		refundOutputID := refundTxn.SiacoinOutputID(0)
  1197  		exists := cst.cs.db.inSiacoinOutputs(refundOutputID)
  1198  		if !exists {
  1199  			return errors.New("timelocked refund transaction did not get spent correctly")
  1200  		}
  1201  	}
  1202  
  1203  	return nil
  1204  }
  1205  */
  1206  
  1207  /*
  1208  // TestPaymentChannelBlocks creates a consensus set tester and uses it to call
  1209  // testPaymentChannelBlocks.
  1210  func TestPaymentChannelBlocks(t *testing.T) {
  1211  	if testing.Short() {
  1212  		t.SkipNow()
  1213  	}
  1214  	cst, err := createConsensusSetTester(t.Name())
  1215  	if err != nil {
  1216  		t.Fatal(err)
  1217  	}
  1218  	defer cst.closeCst()
  1219  	err = cst.testPaymentChannelBlocks()
  1220  	if err != nil {
  1221  		t.Fatal(err)
  1222  	}
  1223  }
  1224  */