Skip to content

Commit 562a604

Browse files
authored
Merge pull request bitcoin#677 from jimpo/bip158-test-vectors
BIP 158: Change test vectors from CSV to JSON format.
2 parents 5d17384 + fe1d3f8 commit 562a604

File tree

3 files changed

+118
-122
lines changed

3 files changed

+118
-122
lines changed

bip-0158/gentestvectors.go

Lines changed: 108 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -10,103 +10,110 @@ package main
1010
import (
1111
"bytes"
1212
"encoding/hex"
13+
"encoding/json"
1314
"fmt"
15+
"io"
1416
"io/ioutil"
1517
"os"
1618
"path"
1719

18-
"github.com/roasbeef/btcd/chaincfg"
1920
"github.com/roasbeef/btcd/chaincfg/chainhash"
2021
"github.com/roasbeef/btcd/rpcclient"
2122
"github.com/roasbeef/btcd/wire"
2223
"github.com/roasbeef/btcutil/gcs"
2324
"github.com/roasbeef/btcutil/gcs/builder"
2425
)
2526

27+
var (
28+
// testBlockHeights are the heights of the blocks to include in the test
29+
// vectors. Any new entries must be added in sorted order.
30+
testBlockHeights = []testBlockCase{
31+
{0, "Genesis block"},
32+
{1, "Extended filter is empty"},
33+
{2, ""},
34+
{3, ""},
35+
{926485, "Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"},
36+
{987876, "Coinbase tx has unparseable output script"},
37+
{1263442, "Includes witness data"},
38+
}
39+
)
40+
41+
type testBlockCase struct {
42+
height uint32
43+
comment string
44+
}
45+
46+
type JSONTestWriter struct {
47+
writer io.Writer
48+
firstRowWritten bool
49+
}
50+
51+
func NewJSONTestWriter(writer io.Writer) *JSONTestWriter {
52+
return &JSONTestWriter{writer: writer}
53+
}
54+
55+
func (w *JSONTestWriter) WriteComment(comment string) error {
56+
return w.WriteTestCase([]interface{}{comment})
57+
}
58+
59+
func (w *JSONTestWriter) WriteTestCase(row []interface{}) error {
60+
var err error
61+
if w.firstRowWritten {
62+
_, err = io.WriteString(w.writer, ",\n")
63+
} else {
64+
_, err = io.WriteString(w.writer, "[\n")
65+
w.firstRowWritten = true
66+
}
67+
if err != nil {
68+
return err
69+
}
70+
71+
rowBytes, err := json.Marshal(row)
72+
if err != nil {
73+
return err
74+
}
75+
76+
_, err = w.writer.Write(rowBytes)
77+
return err
78+
}
79+
80+
func (w *JSONTestWriter) Close() error {
81+
if !w.firstRowWritten {
82+
return nil
83+
}
84+
85+
_, err := io.WriteString(w.writer, "\n]\n")
86+
return err
87+
}
88+
2689
func main() {
2790
err := os.Mkdir("gcstestvectors", os.ModeDir|0755)
2891
if err != nil { // Don't overwrite existing output if any
2992
fmt.Println("Couldn't create directory: ", err)
3093
return
3194
}
32-
files := make([]*os.File, 33)
95+
files := make([]*JSONTestWriter, 33)
3396
prevBasicHeaders := make([]chainhash.Hash, 33)
3497
prevExtHeaders := make([]chainhash.Hash, 33)
3598
for i := 1; i <= 32; i++ { // Min 1 bit of collision space, max 32
36-
var blockBuf bytes.Buffer
37-
fName := fmt.Sprintf("gcstestvectors/testnet-%02d.csv", i)
99+
fName := fmt.Sprintf("gcstestvectors/testnet-%02d.json", i)
38100
file, err := os.Create(fName)
39101
if err != nil {
40-
fmt.Println("Error creating CSV file: ", err.Error())
41-
return
42-
}
43-
_, err = file.WriteString("Block Height,Block Hash,Block,Previous Basic Header,Previous Ext Header,Basic Filter,Ext Filter,Basic Header,Ext Header\n")
44-
if err != nil {
45-
fmt.Println("Error writing to CSV file: ", err.Error())
46-
return
47-
}
48-
files[i] = file
49-
basicFilter, err := buildBasicFilter(
50-
chaincfg.TestNet3Params.GenesisBlock, uint8(i))
51-
if err != nil {
52-
fmt.Println("Error generating basic filter: ", err.Error())
53-
return
54-
}
55-
prevBasicHeaders[i], err = builder.MakeHeaderForFilter(basicFilter,
56-
chaincfg.TestNet3Params.GenesisBlock.Header.PrevBlock)
57-
if err != nil {
58-
fmt.Println("Error generating header for filter: ", err.Error())
59-
return
60-
}
61-
if basicFilter == nil {
62-
basicFilter = &gcs.Filter{}
63-
}
64-
extFilter, err := buildExtFilter(
65-
chaincfg.TestNet3Params.GenesisBlock, uint8(i))
66-
if err != nil {
67-
fmt.Println("Error generating ext filter: ", err.Error())
68-
return
69-
}
70-
prevExtHeaders[i], err = builder.MakeHeaderForFilter(extFilter,
71-
chaincfg.TestNet3Params.GenesisBlock.Header.PrevBlock)
72-
if err != nil {
73-
fmt.Println("Error generating header for filter: ", err.Error())
102+
fmt.Println("Error creating output file: ", err.Error())
74103
return
75104
}
76-
if extFilter == nil {
77-
extFilter = &gcs.Filter{}
78-
}
79-
err = chaincfg.TestNet3Params.GenesisBlock.Serialize(&blockBuf)
80-
if err != nil {
81-
fmt.Println("Error serializing block to buffer: ", err.Error())
82-
return
83-
}
84-
bfBytes, err := basicFilter.NBytes()
85-
if err != nil {
86-
fmt.Println("Couldn't get NBytes(): ", err)
87-
return
88-
}
89-
efBytes, err := extFilter.NBytes()
90-
if err != nil {
91-
fmt.Println("Couldn't get NBytes(): ", err)
92-
return
93-
}
94-
err = writeCSVRow(
95-
file,
96-
0, // Height
97-
*chaincfg.TestNet3Params.GenesisHash,
98-
blockBuf.Bytes(),
99-
chaincfg.TestNet3Params.GenesisBlock.Header.PrevBlock,
100-
chaincfg.TestNet3Params.GenesisBlock.Header.PrevBlock,
101-
bfBytes,
102-
efBytes,
103-
prevBasicHeaders[i],
104-
prevExtHeaders[i],
105-
)
105+
defer file.Close()
106+
107+
writer := &JSONTestWriter{writer: file}
108+
defer writer.Close()
109+
110+
err = writer.WriteComment("Block Height,Block Hash,Block,Previous Basic Header,Previous Ext Header,Basic Filter,Ext Filter,Basic Header,Ext Header,Notes")
106111
if err != nil {
107-
fmt.Println("Error writing to CSV file: ", err.Error())
112+
fmt.Println("Error writing to output file: ", err.Error())
108113
return
109114
}
115+
116+
files[i] = writer
110117
}
111118
cert, err := ioutil.ReadFile(
112119
path.Join(os.Getenv("HOME"), "/.btcd/rpc.cert"))
@@ -126,7 +133,9 @@ func main() {
126133
fmt.Println("Couldn't create a new client: ", err.Error())
127134
return
128135
}
129-
for height := 1; height < 988000; height++ {
136+
137+
var testBlockIndex int = 0
138+
for height := 0; testBlockIndex < len(testBlockHeights); height++ {
130139
fmt.Printf("Height: %d\n", height)
131140
blockHash, err := client.GetBlockHash(int64(height))
132141
if err != nil {
@@ -224,62 +233,46 @@ func main() {
224233
}
225234
fmt.Println("Verified against server")
226235
}
227-
switch height {
228-
case 1, 2, 3, 926485, 987876: // Blocks for test cases
236+
237+
if uint32(height) == testBlockHeights[testBlockIndex].height {
229238
var bfBytes []byte
230239
var efBytes []byte
231-
if basicFilter.N() > 0 {
232-
bfBytes, err = basicFilter.NBytes()
233-
if err != nil {
234-
fmt.Println("Couldn't get NBytes(): ", err)
235-
return
236-
}
240+
bfBytes, err = basicFilter.NBytes()
241+
if err != nil {
242+
fmt.Println("Couldn't get NBytes(): ", err)
243+
return
237244
}
238-
if extFilter.N() > 0 { // Exclude special case for block 987876
239-
efBytes, err = extFilter.NBytes()
240-
if err != nil {
241-
fmt.Println("Couldn't get NBytes(): ", err)
242-
return
243-
}
245+
efBytes, err = extFilter.NBytes()
246+
if err != nil {
247+
fmt.Println("Couldn't get NBytes(): ", err)
248+
return
244249
}
245-
writeCSVRow(
246-
files[i],
250+
row := []interface{}{
247251
height,
248-
*blockHash,
249-
blockBytes,
250-
prevBasicHeaders[i],
251-
prevExtHeaders[i],
252-
bfBytes,
253-
efBytes,
254-
basicHeader,
255-
extHeader)
252+
blockHash.String(),
253+
hex.EncodeToString(blockBytes),
254+
prevBasicHeaders[i].String(),
255+
prevExtHeaders[i].String(),
256+
hex.EncodeToString(bfBytes),
257+
hex.EncodeToString(efBytes),
258+
basicHeader.String(),
259+
extHeader.String(),
260+
testBlockHeights[testBlockIndex].comment,
261+
}
262+
err = files[i].WriteTestCase(row)
263+
if err != nil {
264+
fmt.Println("Error writing test case to output: ", err.Error())
265+
return
266+
}
256267
}
257268
prevBasicHeaders[i] = basicHeader
258269
prevExtHeaders[i] = extHeader
259270
}
260-
}
261-
}
262271

263-
// writeCSVRow writes a test vector to a CSV file.
264-
func writeCSVRow(file *os.File, height int, blockHash chainhash.Hash,
265-
blockBytes []byte, prevBasicHeader, prevExtHeader chainhash.Hash,
266-
basicFilter, extFilter []byte, basicHeader, extHeader chainhash.Hash) error {
267-
row := fmt.Sprintf("%d,%s,%s,%s,%s,%s,%s,%s,%s\n",
268-
height,
269-
blockHash.String(),
270-
hex.EncodeToString(blockBytes),
271-
prevBasicHeader.String(),
272-
prevExtHeader.String(),
273-
hex.EncodeToString(basicFilter),
274-
hex.EncodeToString(extFilter),
275-
basicHeader.String(),
276-
extHeader.String(),
277-
)
278-
_, err := file.WriteString(row)
279-
if err != nil {
280-
return err
272+
if uint32(height) == testBlockHeights[testBlockIndex].height {
273+
testBlockIndex++
274+
}
281275
}
282-
return nil
283276
}
284277

285278
// buildBasicFilter builds a basic GCS filter from a block. A basic GCS filter

bip-0158/testnet-20.csv

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)