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 }