Skip to content

Commit a98b29a

Browse files
committed
fullblockstest: adding the tests for the integration of processBlocks and processHeaderBlocks
Adding the tests that would check if a block with validated header give the expected reponse when block data is added to that node.
1 parent 6272a67 commit a98b29a

File tree

3 files changed

+174
-4
lines changed

3 files changed

+174
-4
lines changed

blockchain/fullblocktests/common_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/utreexo/utreexod/blockchain"
11+
"github.com/utreexo/utreexod/btcutil"
1112
)
1213

1314
type chaingenHarness struct {
@@ -130,3 +131,75 @@ func (g *chaingenHarness) RejectHeader(blockName string, code blockchain.ErrorCo
130131
"marked as known invalid", blockName, blockHash)
131132
}
132133
}
134+
135+
// testAcceptedBlock attempts to process the block in the provided test
136+
// instance and ensures that it was accepted according to the flags
137+
// specified in the test.
138+
func (g *chaingenHarness) AcceptBlock(item AcceptedBlock) {
139+
g.t.Helper()
140+
141+
blockHeight := item.Height
142+
block := btcutil.NewBlock(item.Block)
143+
block.SetHeight(blockHeight)
144+
g.t.Logf("Testing block %s (hash %s, height %d)",
145+
item.Name, block.Hash(), blockHeight)
146+
147+
isMainChain, isOrphan, err := g.chain.ProcessBlock(block,
148+
blockchain.BFNone)
149+
if err != nil {
150+
g.t.Fatalf("block %q (hash %s, height %d) should "+
151+
"have been accepted: %v", item.Name,
152+
block.Hash(), blockHeight, err)
153+
}
154+
155+
// Ensure the main chain and orphan flags match the values
156+
// specified in the test.
157+
if isMainChain != item.IsMainChain {
158+
g.t.Fatalf("block %q (hash %s, height %d) unexpected main "+
159+
"chain flag -- got %v, want %v", item.Name,
160+
block.Hash(), blockHeight, isMainChain,
161+
item.IsMainChain)
162+
}
163+
if isOrphan != item.IsOrphan {
164+
g.t.Fatalf("block %q (hash %s, height %d) unexpected "+
165+
"orphan flag -- got %v, want %v", item.Name,
166+
block.Hash(), blockHeight, isOrphan,
167+
item.IsOrphan)
168+
}
169+
}
170+
171+
// testRejectedBlock attempts to process the block in the provided test
172+
// instance and ensures that it was rejected with the reject code
173+
// specified in the test.
174+
func (g *chaingenHarness) RejectBlock(item RejectedBlock) {
175+
g.t.Helper()
176+
177+
blockHeight := item.Height
178+
block := btcutil.NewBlock(item.Block)
179+
block.SetHeight(blockHeight)
180+
g.t.Logf("Testing block %s (hash %s, height %d)",
181+
item.Name, block.Hash(), blockHeight)
182+
183+
_, _, err := g.chain.ProcessBlock(block, blockchain.BFNone)
184+
if err == nil {
185+
g.t.Fatalf("block %q (hash %s, height %d) should not "+
186+
"have been accepted", item.Name, block.Hash(),
187+
blockHeight)
188+
}
189+
190+
// Ensure the error code is of the expected type and the reject
191+
// code matches the value specified in the test instance.
192+
rerr, ok := err.(blockchain.RuleError)
193+
if !ok {
194+
g.t.Fatalf("block %q (hash %s, height %d) returned "+
195+
"unexpected error type -- got %T, want "+
196+
"blockchain.RuleError", item.Name, block.Hash(),
197+
blockHeight, err)
198+
}
199+
if rerr.ErrorCode != item.RejectCode {
200+
g.t.Fatalf("block %q (hash %s, height %d) does not have "+
201+
"expected reject code -- got %v, want %v",
202+
item.Name, block.Hash(), blockHeight,
203+
rerr.ErrorCode, item.RejectCode)
204+
}
205+
}

blockchain/fullblocktests/generate.go

+97-4
Original file line numberDiff line numberDiff line change
@@ -2214,7 +2214,15 @@ func GenerateHeaders() (generator *testGenerator, tests [][]TestInstance) {
22142214
blockHeight := g.blockHeights[blockName]
22152215
return RejectedHeader{blockName, blockHeader, blockHeight, code}
22162216
}
2217-
2217+
acceptBlock := func(blockName string, block *wire.MsgBlock, isMainChain, isOrphan bool) TestInstance {
2218+
blockHeight := g.blockHeights[blockName]
2219+
return AcceptedBlock{blockName, block, blockHeight, isMainChain,
2220+
isOrphan}
2221+
}
2222+
rejectBlock := func(blockName string, block *wire.MsgBlock, code blockchain.ErrorCode) TestInstance {
2223+
blockHeight := g.blockHeights[blockName]
2224+
return RejectedBlock{blockName, block, blockHeight, code}
2225+
}
22182226
// Define some convenience helper functions to populate the tests slice
22192227
// with test instances that have the described characteristics.
22202228
//
@@ -2224,6 +2232,13 @@ func GenerateHeaders() (generator *testGenerator, tests [][]TestInstance) {
22242232
//
22252233
// rejected creates and appends a single rejectHeader test instance for
22262234
// the current tip.
2235+
//
2236+
// acceptedBlock creates and appends a single acceptBlock test instance for
2237+
// the current tip which expects the block to be accepted to the main
2238+
// chain.
2239+
//
2240+
// rejectedBlock creates and appends a single rejectBlock test instance for
2241+
// the current tip.
22272242
accepted := func() {
22282243
tests = append(tests, []TestInstance{
22292244
acceptHeader(g.tipName, g.tip),
@@ -2234,6 +2249,16 @@ func GenerateHeaders() (generator *testGenerator, tests [][]TestInstance) {
22342249
rejectHeader(g.tipName, g.tip, code),
22352250
})
22362251
}
2252+
acceptedBlock := func() {
2253+
tests = append(tests, []TestInstance{
2254+
acceptBlock(g.tipName, g.tip, true, false),
2255+
})
2256+
}
2257+
rejectedBlock := func(code blockchain.ErrorCode) {
2258+
tests = append(tests, []TestInstance{
2259+
rejectBlock(g.tipName, g.tip, code),
2260+
})
2261+
}
22372262
// ---------------------------------------------------------------------
22382263
// Generate enough blocks to have mature coinbase outputs to work with.
22392264
//
@@ -2317,11 +2342,79 @@ func GenerateHeaders() (generator *testGenerator, tests [][]TestInstance) {
23172342
g.updateBlockState("b3", origHash, "b3", b3)
23182343
}
23192344
rejected(blockchain.ErrUnexpectedDifficulty)
2320-
// Adding a block with valid header
2345+
// Adding a block with valid header but invalid spend
23212346
//
2322-
// ... -> b0() -> b4(1)
2347+
// ... -> b0() -> b4(2)
23232348
g.setTip("b0")
2324-
g.nextBlock("b4", outs[1])
2349+
g.nextBlock("b4", outs[2])
23252350
accepted()
2351+
// Adding a block with valid header and valid spend, but invalid parent
2352+
//
2353+
// ... -> b0() -> b5(1)
2354+
g.nextBlock("b5", outs[1])
2355+
accepted()
2356+
// Adding a block with valid header and valid spend and valid parent
2357+
//
2358+
// ... -> b0() -> b6(1)
2359+
g.setTip("b0")
2360+
g.nextBlock("b6", outs[1])
2361+
// Accepting/Rejecting the blocks for the headers that were
2362+
// accepted/rejected
2363+
testInstances = make([]TestInstance, 0)
2364+
for i := uint16(0); i < coinbaseMaturity; i++ {
2365+
blockName := fmt.Sprintf("bm%d", i)
2366+
g.setTip(blockName)
2367+
testInstances = append(testInstances, acceptBlock(g.tipName,
2368+
g.tip, true, false))
2369+
}
2370+
tests = append(tests, testInstances)
2371+
// Accepting the block b0
2372+
//
2373+
// ... -> b0
2374+
g.setTip("b0")
2375+
acceptedBlock()
2376+
// Rejecting the block data for b1 because of high hash
2377+
// ... -> b0()
2378+
// \-> b1(1)
2379+
g.setTip("b1")
2380+
rejectedBlock(blockchain.ErrHighHash)
2381+
// Acccept the block as orphan
2382+
//
2383+
// -> b1a(1)
2384+
g.setTip("b1a")
2385+
tests = append(tests, []TestInstance{
2386+
acceptBlock(g.tipName, g.tip, false, true),
2387+
})
2388+
// Reject the block with invalid proof of work
2389+
//
2390+
// ... -> b0()
2391+
// \-> b2(1)
2392+
g.setTip("b2")
2393+
rejectedBlock(blockchain.ErrUnexpectedDifficulty)
2394+
// Reject the block with invalid negative proof of work
2395+
//
2396+
// ... -> b0()
2397+
// \-> b3(1)
2398+
g.setTip("b3")
2399+
rejectedBlock(blockchain.ErrUnexpectedDifficulty)
2400+
// Rejecting the block with valid header but invalid spend
2401+
//
2402+
// ... -> b0()
2403+
// \-> b4(2)
2404+
g.setTip("b4")
2405+
rejectedBlock(blockchain.ErrImmatureSpend)
2406+
// Since the block is rejected, so rejecting the header also
2407+
// which was earlier accepted.
2408+
rejected(blockchain.ErrKnownInvalidBlock)
2409+
// Rejecting a block with valid header and valid spend, but invalid parent
2410+
//
2411+
// -> b4(2) -> b5(1)
2412+
g.setTip("b5")
2413+
rejectedBlock(blockchain.ErrInvalidAncestorBlock)
2414+
// Accepting the block
2415+
//
2416+
// ... -> b0() -> b6(1)
2417+
g.setTip("b6")
2418+
acceptedBlock()
23262419
return &g, tests
23272420
}

blockchain/fullblocktests/process_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ func TestProcessLogic(t *testing.T) {
4040
harness.AcceptHeader(item.Name)
4141
case RejectedHeader:
4242
harness.RejectHeader(item.Name, item.RejectCode)
43+
case AcceptedBlock:
44+
harness.AcceptBlock(item)
45+
case RejectedBlock:
46+
harness.RejectBlock(item)
4347
default:
4448
t.Fatalf("test #%d, item #%d is not one of "+
4549
"the supported test instance types -- "+

0 commit comments

Comments
 (0)