This repository has been archived by the owner on Nov 22, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathblockchain.go
120 lines (100 loc) · 2.41 KB
/
blockchain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package blkparser
import (
"bytes"
"errors"
"fmt"
"os"
)
type Blockchain struct {
Path string
Magic [4]byte
CurrentFile *os.File
CurrentId uint32
}
func NewBlockchain(path string, magic [4]byte) (blockchain *Blockchain, err error) {
blockchain = new(Blockchain)
blockchain.Path = path
blockchain.Magic = magic
blockchain.CurrentId = 0
f, err := os.Open(blkfilename(path, 0))
if err != nil {
return
}
blockchain.CurrentFile = f
return
}
func (blockchain *Blockchain) NextBlock() (block *Block, err error) {
rawblock, err := blockchain.FetchNextBlock()
if err != nil {
newblkfile, err2 := os.Open(blkfilename(blockchain.Path, blockchain.CurrentId+1))
if err2 != nil {
return nil, err2
}
blockchain.CurrentId++
blockchain.CurrentFile.Close()
blockchain.CurrentFile = newblkfile
rawblock, err = blockchain.FetchNextBlock()
}
block, err = NewBlock(rawblock)
if err != nil {
return
}
return
}
func (blockchain *Blockchain) SkipBlock() (err error) {
_, err = blockchain.FetchNextBlock()
if err != nil {
newblkfile, err2 := os.Open(blkfilename(blockchain.Path, blockchain.CurrentId+1))
if err2 != nil {
return err2
}
blockchain.CurrentId++
blockchain.CurrentFile.Close()
blockchain.CurrentFile = newblkfile
_, err = blockchain.FetchNextBlock()
}
return
}
func (blockchain *Blockchain) FetchNextBlock() (rawblock []byte, err error) {
buf := [4]byte{}
_, err = blockchain.CurrentFile.Read(buf[:])
if err != nil {
return
}
if !bytes.Equal(buf[:], blockchain.Magic[:]) {
err = errors.New("Bad magic")
return
}
_, err = blockchain.CurrentFile.Read(buf[:])
if err != nil {
return
}
blocksize := uint32(blksize(buf[:]))
rawblock = make([]byte, blocksize)
_, err = blockchain.CurrentFile.Read(rawblock[:])
if err != nil {
return
}
return
}
// Convenience method to skip directly to the given blkfile / offset,
// you must take care of the height
func (blockchain *Blockchain) SkipTo(blkId uint32, offset int64) (err error) {
blockchain.CurrentId = blkId
f, err := os.Open(blkfilename(blockchain.Path, blkId))
if err != nil {
return
}
blockchain.CurrentFile = f
_, err = blockchain.CurrentFile.Seek(offset, 0)
return
}
func blkfilename(path string, id uint32) string {
return fmt.Sprintf("%s/blk%05d.dat", path, id)
}
func blksize(buf []byte) (size uint64) {
for i := 0; i < len(buf); i++ {
size |= (uint64(buf[i]) << uint(i*8))
}
return
}