fullblocks_test.go raw
1 package blockchain_test
2
3 import (
4 "os"
5
6 "github.com/p9c/p9/pkg/database"
7 _ "github.com/p9c/p9/pkg/database/ffldb"
8 "github.com/p9c/p9/pkg/wire"
9 )
10
11 const (
12 // testDbType is the database backend type to use for the tests.
13 testDbType = "ffldb"
14 // testDbRoot is the root directory used to create all test databases.
15 testDbRoot = "testdbs"
16 // blockDataNet is the expected network in the test block data.
17 blockDataNet = wire.MainNet
18 )
19
20 // filesExists returns whether or not the named file or directory exists.
21 func fileExists(name string) bool {
22 var e error
23 if _, e = os.Stat(name); E.Chk(e) {
24 if os.IsNotExist(e) {
25 return false
26 }
27 }
28 return true
29 }
30
31 // isSupportedDbType returns whether or not the passed database type is currently supported.
32 func isSupportedDbType(dbType string) bool {
33 supportedDrivers := database.SupportedDrivers()
34 for _, driver := range supportedDrivers {
35 if dbType == driver {
36 return true
37 }
38 }
39 return false
40 }
41
42 // // chainSetup is used to create a new db and chain instance with the genesis block already inserted. In addition to the new chain instance, it returns a teardown function the caller should invoke when done testing to clean up.
43 // func chainSetup( dbName string, netparams *chaincfg.Params) (*blockchain.BlockChain, func(), error) {
44 // if !isSupportedDbType(testDbType) {
45 // return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
46 // }
47 // // Handle memory database specially since it doesn't need the disk specific handling.
48 // var db database.DB
49 // var teardown func()
50 // if testDbType == "memdb" {
51 // ndb, e := database.Create(testDbType)
52 // if e != nil {
53 // return nil, nil, fmt.Errorf("error creating db: %v", err)
54 // }
55 // db = ndb
56 // // Setup a teardown function for cleaning up. This function is returned to the caller to be invoked when it is done testing.
57 // teardown = func() {
58 // db.Close()
59 // }
60 // } else {
61 // // Create the root directory for test databases.
62 // if !fileExists(testDbRoot) {
63 // if e := os.MkdirAll(testDbRoot, 0700); E.Chk(e) {
64 // e := fmt.Errorf("unable to create test db "+
65 // "root: %v", err)
66 // return nil, nil, e
67 // }
68 // }
69 // // Create a new database to store the accepted blocks into.
70 // dbPath := filepath.Join(testDbRoot, dbName)
71 // _ = os.RemoveAll(dbPath)
72 // ndb, e := database.Create(testDbType, dbPath, blockDataNet)
73 // if e != nil {
74 // return nil, nil, fmt.Errorf("error creating db: %v", err)
75 // }
76 // db = ndb
77 // // Setup a teardown function for cleaning up. This function is returned to the caller to be invoked when it is done testing.
78 // teardown = func() {
79 // db.Close()
80 // os.RemoveAll(dbPath)
81 // os.RemoveAll(testDbRoot)
82 // }
83 // }
84 // // Copy the chain netparams to ensure any modifications the tests do to the chain parameters do not affect the global instance.
85 // paramsCopy := *netparams
86 // // Create the main chain instance.
87 // chain, e := blockchain.New(&blockchain.Config{
88 // DB: db,
89 // ChainParams: ¶msCopy,
90 // Checkpoints: nil,
91 // TimeSource: blockchain.NewMedianTime(),
92 // SigCache: txscript.NewSigCache(1000),
93 // })
94 // if e != nil {
95 // teardown()
96 // e := fmt.Errorf("failed to create chain instance: %v", err)
97 // return nil, nil, e
98 // }
99 // return chain, teardown, nil
100 // }
101
102 // // TestFullBlocks ensures all tests generated by the fullblocktests package have the expected result when processed via ProcessBlock.
103 // func TestFullBlocks(// t *testing.T) {
104 // tests, e := fullblocktests.Generate(false)
105 // if e != nil {
106 // t.Fatalf("failed to generate tests: %v", err)
107 // }
108 // // Create a new database and chain instance to run tests against.
109 // chain, teardownFunc, e := chainSetup("fullblocktest",
110 // &chaincfg.RegressionTestParams)
111 // if e != nil {
112 // t.Errorf("Failed to setup chain instance: %v", err)
113 // return
114 // }
115 // defer teardownFunc()
116 // // testAcceptedBlock attempts to process the block in the provided test instance and ensures that it was accepted according to the flags specified in the test.
117 // testAcceptedBlock := func(item fullblocktests.AcceptedBlock) {
118 // blockHeight := item.Height
119 // block := util.NewBlock(item.Block)
120 // block.SetHeight(blockHeight)
121 // t.Logf("Testing block %s (hash %s, height %d)",
122 // item.Name, block.Hash(), blockHeight)
123 // isMainChain, isOrphan, e := chain.ProcessBlock(block,
124 // blockchain.BFNone, block.Height())
125 // if e != nil {
126 // t.Fatalf("block %q (hash %s, height %d) should "+
127 // "have been accepted: %v", item.Name,
128 // block.Hash(), blockHeight, err)
129 // }
130 // // Ensure the main chain and orphan flags match the values specified in the test.
131 // if isMainChain != item.IsMainChain {
132 // t.Fatalf("block %q (hash %s, height %d) unexpected main "+
133 // "chain flag -- got %v, want %v", item.Name,
134 // block.Hash(), blockHeight, isMainChain,
135 // item.IsMainChain)
136 // }
137 // if isOrphan != item.IsOrphan {
138 // t.Fatalf("block %q (hash %s, height %d) unexpected "+
139 // "orphan flag -- got %v, want %v", item.Name,
140 // block.Hash(), blockHeight, isOrphan,
141 // item.IsOrphan)
142 // }
143 // }
144 // // testRejectedBlock attempts to process the block in the provided test instance and ensures that it was rejected with the reject code specified in the test.
145 // testRejectedBlock := func(item fullblocktests.RejectedBlock) {
146 // blockHeight := item.Height
147 // block := util.NewBlock(item.Block)
148 // block.SetHeight(blockHeight)
149 // t.Logf("Testing block %s (hash %s, height %d)",
150 // item.Name, block.Hash(), blockHeight)
151 // _, _, e = chain.ProcessBlock(
152 // block, blockchain.BFNone, block.Height())
153 // if e == nil {
154 // t.Fatalf("block %q (hash %s, height %d) should not "+
155 // "have been accepted", item.Name, block.Hash(),
156 // blockHeight)
157 // }
158 // // Ensure the error code is of the expected type and the reject code matches the value specified in the test instance.
159 // rerr, ok := err.(blockchain.RuleError)
160 // if !ok {
161 // t.Fatalf("block %q (hash %s, height %d) returned "+
162 // "unexpected error type -- got %T, want "+
163 // "blockchain.RuleError", item.Name, block.Hash(),
164 // blockHeight, err)
165 // }
166 // if rerr.ErrorCode != item.RejectCode {
167 // t.Fatalf("block %q (hash %s, height %d) does not have "+
168 // "expected reject code -- got %v, want %v",
169 // item.Name, block.Hash(), blockHeight,
170 // rerr.ErrorCode, item.RejectCode)
171 // }
172 // }
173 // // testRejectedNonCanonicalBlock attempts to decode the block in the provided test instance and ensures that it failed to decode with a message error.
174 // testRejectedNonCanonicalBlock := func(item fullblocktests.RejectedNonCanonicalBlock) {
175 // headerLen := len(item.RawBlock)
176 // if headerLen > 80 {
177 // headerLen = 80
178 // }
179 // blockHash := chainhash.DoubleHashH(item.RawBlock[0:headerLen])
180 // blockHeight := item.Height
181 // t.Logf("Testing block %s (hash %s, height %d)", item.Name,
182 // blockHash, blockHeight)
183 // // Ensure there is an error due to deserializing the block.
184 // var msgBlock wire.Block
185 // e := msgBlock.BtcDecode(bytes.NewReader(item.RawBlock), 0, wire.BaseEncoding)
186 // if _, ok := err.(*wire.MessageError); !ok {
187 // t.Fatalf("block %q (hash %s, height %d) should have "+
188 // "failed to decode", item.Name, blockHash,
189 // blockHeight)
190 // }
191 // }
192 // // testOrphanOrRejectedBlock attempts to process the block in the provided test instance and ensures that it was either accepted as an orphan or rejected with a rule violation.
193 // testOrphanOrRejectedBlock := func(item fullblocktests.OrphanOrRejectedBlock) {
194 // blockHeight := item.Height
195 // block := util.NewBlock(item.Block)
196 // block.SetHeight(blockHeight)
197 // t.Logf("Testing block %s (hash %s, height %d)",
198 // item.Name, block.Hash(), blockHeight)
199 // _, isOrphan, e := chain.ProcessBlock(
200 // block, blockchain.BFNone, block.Height())
201 // if e != nil {
202 // // Ensure the error code is of the expected type.
203 // if _, ok := err.(blockchain.RuleError); !ok {
204 // t.Fatalf("block %q (hash %s, height %d) "+
205 // "returned unexpected error type -- "+
206 // "got %T, want blockchain.RuleError",
207 // item.Name, block.Hash(), blockHeight,
208 // err)
209 // }
210 // }
211 // if !isOrphan {
212 // t.Fatalf("block %q (hash %s, height %d) was accepted, "+
213 // "but is not considered an orphan", item.Name,
214 // block.Hash(), blockHeight)
215 // }
216 // }
217 // // testExpectedTip ensures the current tip of the blockchain is the block specified in the provided test instance.
218 // testExpectedTip := func(item fullblocktests.ExpectedTip) {
219 // blockHeight := item.Height
220 // block := util.NewBlock(item.Block)
221 // block.SetHeight(blockHeight)
222 // t.Logf("Testing tip for block %s (hash %s, height %d)",
223 // item.Name, block.Hash(), blockHeight)
224 // // Ensure hash and height match.
225 // best := chain.BestSnapshot()
226 // if best.Hash != item.Block.BlockHash() ||
227 // best.Height != blockHeight {
228 // t.Fatalf("block %q (hash %s, height %d) should be "+
229 // "the current tip -- got (hash %s, height %d)",
230 // item.Name, block.Hash(), blockHeight, best.Hash,
231 // best.Height)
232 // }
233 // }
234 // for testNum, test := range tests {
235 // for itemNum, item := range test {
236 // switch item := item.(type) {
237 // case fullblocktests.AcceptedBlock:
238 // testAcceptedBlock(item)
239 // case fullblocktests.RejectedBlock:
240 // testRejectedBlock(item)
241 // case fullblocktests.RejectedNonCanonicalBlock:
242 // testRejectedNonCanonicalBlock(item)
243 // case fullblocktests.OrphanOrRejectedBlock:
244 // testOrphanOrRejectedBlock(item)
245 // case fullblocktests.ExpectedTip:
246 // testExpectedTip(item)
247 // default:
248 // t.Fatalf("test #%d, item #%d is not one of "+
249 // "the supported test instance types -- "+
250 // "got type: %T", testNum, itemNum, item)
251 // }
252 // }
253 // }
254 // }
255