forked from ten-protocol/go-ten
-
Notifications
You must be signed in to change notification settings - Fork 0
/
blocks.go
169 lines (147 loc) · 4.68 KB
/
blocks.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package db
import (
"bytes"
"errors"
"fmt"
"math/big"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/obscuronet/go-obscuro/go/common"
"github.com/obscuronet/go-obscuro/go/common/errutil"
)
// DB methods relating to block headers.
// GetBlockByHash returns the block header given the hash.
func (db *DB) GetBlockByHash(hash gethcommon.Hash) (*types.Header, error) {
return db.readBlock(db.kvStore, blockHashKey(hash))
}
// GetBlockByHeight returns the block header given the height
func (db *DB) GetBlockByHeight(height *big.Int) (*types.Header, error) {
return db.readBlock(db.kvStore, blockNumberKey(height))
}
// AddBlock adds a types.Header to the known headers
func (db *DB) AddBlock(header *types.Header) error {
b := db.kvStore.NewBatch()
err := db.writeBlockByHash(header)
if err != nil {
return fmt.Errorf("could not write block header. Cause: %w", err)
}
err = db.writeBlockByHeight(header)
if err != nil {
return fmt.Errorf("could not write block header. Cause: %w", err)
}
// Update the tip if the new height is greater than the existing one.
tipBlockHeader, err := db.GetBlockAtTip()
if err != nil && !errors.Is(err, errutil.ErrNotFound) {
return fmt.Errorf("could not retrieve block header at tip. Cause: %w", err)
}
if tipBlockHeader == nil || tipBlockHeader.Number.Cmp(header.Number) == -1 {
err = db.writeBlockAtTip(b, header.Hash())
if err != nil {
return fmt.Errorf("could not write new block hash at tip. Cause: %w", err)
}
}
if err = b.Write(); err != nil {
return fmt.Errorf("could not write batch to DB. Cause: %w", err)
}
return nil
}
// GetBlockListing returns a list of blocks given the pagination
func (db *DB) GetBlockListing(pagination *common.QueryPagination) (*common.BlockListingResponse, error) {
// fetch requested batches
var blocks []common.PublicBlock
for i := pagination.Offset; i < pagination.Offset+uint64(pagination.Size); i++ {
header, err := db.GetBlockByHeight(big.NewInt(int64(i)))
if err != nil && !errors.Is(err, errutil.ErrNotFound) {
return nil, err
}
// check if the block has a rollup
rollup, err := db.GetRollupHeaderByBlock(header.Hash())
if err != nil && !errors.Is(err, errutil.ErrNotFound) {
return nil, err
}
if header != nil {
listedBlock := common.PublicBlock{BlockHeader: *header}
if rollup != nil {
listedBlock.RollupHash = rollup.Hash()
fmt.Println("added at block: ", header.Number.Int64(), " - ", listedBlock.RollupHash)
}
blocks = append(blocks, listedBlock)
}
}
// fetch the total blocks so we can paginate
tipHeader, err := db.GetBlockAtTip()
if err != nil {
return nil, err
}
return &common.BlockListingResponse{
BlocksData: blocks,
Total: tipHeader.Number.Uint64(),
}, nil
}
// GetBlockAtTip returns the block at current Head or Tip
func (db *DB) GetBlockAtTip() (*types.Header, error) {
value, err := db.kvStore.Get(blockHeadedAtTip)
if err != nil {
return nil, err
}
h := gethcommon.BytesToHash(value)
return db.GetBlockByHash(h)
}
// Stores the hash of the block at tip
func (db *DB) writeBlockAtTip(w ethdb.KeyValueWriter, hash gethcommon.Hash) error {
err := w.Put(blockHeadedAtTip, hash.Bytes())
if err != nil {
return err
}
return nil
}
// Stores a block header into the database using the hash as key
func (db *DB) writeBlockByHash(header *types.Header) error {
// Write the encoded header
data, err := rlp.EncodeToBytes(header)
if err != nil {
return err
}
key := blockHashKey(header.Hash())
if err := db.kvStore.Put(key, data); err != nil {
return err
}
db.blockWrites.Inc(1)
return nil
}
// Stores a block header into the database using the height as key
func (db *DB) writeBlockByHeight(header *types.Header) error {
// Write the encoded header
data, err := rlp.EncodeToBytes(header)
if err != nil {
return err
}
key := blockNumberKey(header.Number)
return db.kvStore.Put(key, data)
}
// Retrieves the block header corresponding to the key.
func (db *DB) readBlock(r ethdb.KeyValueReader, key []byte) (*types.Header, error) {
data, err := r.Get(key)
if err != nil {
return nil, err
}
if len(data) == 0 {
return nil, errutil.ErrNotFound
}
header := new(types.Header)
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
return nil, err
}
db.blockReads.Inc(1)
return header, nil
}
// headerKey = blockNumberHeaderPrefix + hash
func blockNumberKey(height *big.Int) []byte {
return append(blockNumberHeaderPrefix, height.Bytes()...)
}
// headerKey = blockHeaderPrefix + hash
func blockHashKey(hash gethcommon.Hash) []byte {
return append(blockHeaderPrefix, hash.Bytes()...)
}