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