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