github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/consensus/consensusset_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"crypto/rand"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/NebulousLabs/Sia/build"
     9  	"github.com/NebulousLabs/Sia/crypto"
    10  	"github.com/NebulousLabs/Sia/modules"
    11  	"github.com/NebulousLabs/Sia/modules/gateway"
    12  	"github.com/NebulousLabs/Sia/modules/miner"
    13  	"github.com/NebulousLabs/Sia/modules/transactionpool"
    14  	"github.com/NebulousLabs/Sia/modules/wallet"
    15  	"github.com/NebulousLabs/Sia/types"
    16  )
    17  
    18  // A consensusSetTester is the helper object for consensus set testing,
    19  // including helper modules and methods for controlling synchronization between
    20  // the tester and the modules.
    21  type consensusSetTester struct {
    22  	gateway   modules.Gateway
    23  	miner     modules.TestMiner
    24  	tpool     modules.TransactionPool
    25  	wallet    modules.Wallet
    26  	walletKey crypto.TwofishKey
    27  
    28  	cs *ConsensusSet
    29  
    30  	persistDir string
    31  }
    32  
    33  // randAddress returns a random address that is not spendable.
    34  func randAddress() types.UnlockHash {
    35  	var uh types.UnlockHash
    36  	_, err := rand.Read(uh[:])
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  	return uh
    41  }
    42  
    43  // addSiafunds makes a transaction that moves some testing genesis siafunds
    44  // into the wallet.
    45  func (cst *consensusSetTester) addSiafunds() {
    46  	// Get an address to receive the siafunds.
    47  	uc, err := cst.wallet.NextAddress()
    48  	if err != nil {
    49  		panic(err)
    50  	}
    51  
    52  	// Create the transaction that sends the anyone-can-spend siafund output to
    53  	// the wallet address (output only available during testing).
    54  	txn := types.Transaction{
    55  		SiafundInputs: []types.SiafundInput{{
    56  			ParentID:         cst.cs.blockRoot.Block.Transactions[0].SiafundOutputID(2),
    57  			UnlockConditions: types.UnlockConditions{},
    58  		}},
    59  		SiafundOutputs: []types.SiafundOutput{{
    60  			Value:      types.NewCurrency64(1e3),
    61  			UnlockHash: uc.UnlockHash(),
    62  		}},
    63  	}
    64  
    65  	// Mine the transaction into the blockchain.
    66  	err = cst.tpool.AcceptTransactionSet([]types.Transaction{txn})
    67  	if err != nil {
    68  		panic(err)
    69  	}
    70  	_, err = cst.miner.AddBlock()
    71  	if err != nil {
    72  		panic(err)
    73  	}
    74  
    75  	// Check that the siafunds made it to the wallet.
    76  	_, siafundBalance, _ := cst.wallet.ConfirmedBalance()
    77  	if siafundBalance.Cmp(types.NewCurrency64(1e3)) != 0 {
    78  		panic("wallet does not have the siafunds")
    79  	}
    80  }
    81  
    82  // mineCoins mines blocks until there are siacoins in the wallet.
    83  func (cst *consensusSetTester) mineSiacoins() {
    84  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
    85  		b, _ := cst.miner.FindBlock()
    86  		err := cst.cs.AcceptBlock(b)
    87  		if err != nil {
    88  			panic(err)
    89  		}
    90  	}
    91  }
    92  
    93  // blankConsensusSetTester creates a consensusSetTester that has only the
    94  // genesis block.
    95  func blankConsensusSetTester(name string) (*consensusSetTester, error) {
    96  	testdir := build.TempDir(modules.ConsensusDir, name)
    97  
    98  	// Create modules.
    99  	g, err := gateway.New("localhost:0", filepath.Join(testdir, modules.GatewayDir))
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	cs, err := New(g, filepath.Join(testdir, modules.ConsensusDir))
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	tp, err := transactionpool.New(cs, g, filepath.Join(testdir, modules.ConsensusDir))
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	key, err := crypto.GenerateTwofishKey()
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	_, err = w.Encrypt(key)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	err = w.Unlock(key)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	// Assemble all objects into a consensusSetTester.
   133  	cst := &consensusSetTester{
   134  		gateway:   g,
   135  		miner:     m,
   136  		tpool:     tp,
   137  		wallet:    w,
   138  		walletKey: key,
   139  
   140  		cs: cs,
   141  
   142  		persistDir: testdir,
   143  	}
   144  	return cst, nil
   145  }
   146  
   147  // createConsensusSetTester creates a consensusSetTester that's ready for use,
   148  // including siacoins and siafunds available in the wallet.
   149  func createConsensusSetTester(name string) (*consensusSetTester, error) {
   150  	cst, err := blankConsensusSetTester(name)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	cst.addSiafunds()
   155  	cst.mineSiacoins()
   156  	return cst, nil
   157  }
   158  
   159  // Close safely closes the consensus set tester. Because there's not a good way
   160  // to errcheck when deferring a close, a panic is called in the event of an
   161  // error.
   162  func (cst *consensusSetTester) Close() error {
   163  	err := cst.cs.Close()
   164  	if err != nil {
   165  		panic(err)
   166  	}
   167  	err = cst.gateway.Close()
   168  	if err != nil {
   169  		panic(err)
   170  	}
   171  	return nil
   172  }
   173  
   174  // TestNilInputs tries to create new consensus set modules using nil inputs.
   175  func TestNilInputs(t *testing.T) {
   176  	testdir := build.TempDir(modules.ConsensusDir, "TestNilInputs")
   177  	_, err := New(nil, testdir)
   178  	if err != errNilGateway {
   179  		t.Fatal(err)
   180  	}
   181  }
   182  
   183  // TestClosing tries to close a consenuss set.
   184  func TestDatabaseClosing(t *testing.T) {
   185  	testdir := build.TempDir(modules.ConsensusDir, "TestClosing")
   186  
   187  	// Create the gateway.
   188  	g, err := gateway.New("localhost:0", filepath.Join(testdir, modules.GatewayDir))
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  	cs, err := New(g, testdir)
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	err = cs.Close()
   197  	if err != nil {
   198  		t.Error(err)
   199  	}
   200  }