-
Notifications
You must be signed in to change notification settings - Fork 0
/
io_chain.go
326 lines (287 loc) · 9.8 KB
/
io_chain.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
package rawdb
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"encoding/binary"
"encoding/json"
"fmt"
"math/big"
"github.com/altair-lab/xoreum/common"
"github.com/altair-lab/xoreum/core/types"
"github.com/altair-lab/xoreum/core/state"
"github.com/altair-lab/xoreum/log"
"github.com/altair-lab/xoreum/rlp"
"github.com/altair-lab/xoreum/xordb"
)
// ReadHash retrieves the hash assigned to a block number.
func ReadHash(db xordb.Reader, number uint64) common.Hash {
data, _ := db.Get(headerHashKey(number))
if len(data) == 0 {
fmt.Println("no block by number", number)
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteHash stores the hash assigned to a block number.
func WriteHash(db xordb.Writer, hash common.Hash, number uint64) {
if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {
log.Crit("Failed to store number to hash mapping", "err", err)
}
}
// DeleteHash removes the number to hash mapping.
func DeleteHash(db xordb.Writer, number uint64) {
if err := db.Delete(headerHashKey(number)); err != nil {
log.Crit("Failed to delete number to hash mapping", "err", err)
}
}
// ReadHeaderNumber returns the header number assigned to a hash.
func ReadHeaderNumber(db xordb.Reader, hash common.Hash) *uint64 {
data, _ := db.Get(headerNumberKey(hash))
if len(data) != 8 {
return nil
}
number := binary.BigEndian.Uint64(data)
return &number
}
// ReadHeaderData retrieves a block header data in rlp encoding
func ReadHeaderData(db xordb.Reader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(headerKey(number, hash))
return data
}
// HasHeader verifies the existence of a block header corresponding to the hash.
func HasHeader(db xordb.Reader, hash common.Hash, number uint64) bool {
if has, err := db.Has(headerKey(number, hash)); !has || err != nil {
return false
}
return true
}
// ReadHeader retrieves the block header corresponding to the hash.
func ReadHeader(db xordb.Reader, hash common.Hash, number uint64) *types.Header {
data := ReadHeaderData(db, hash, number)
if len(data) == 0 {
return nil
}
header := new(types.Header)
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
log.Error("Invalid block header", "hash", hash, "err", err)
return nil
}
return header
}
// WriteHeader stores a block header into the database and also stores the hash-
// to-number mapping.
func WriteHeader(db xordb.Writer, header *types.Header) {
// Write the hash -> number mapping
var (
hash = header.Hash()
number = header.Number
encoded = encodeBlockNumber(number)
)
key := headerNumberKey(hash)
if err := db.Put(key, encoded); err != nil {
log.Crit("Failed to store hash to number mapping", "err", err)
}
// Write the encoded header
data, err := rlp.EncodeToBytes(header)
if err != nil {
log.Crit("Failed to RLP encode header", "err", err)
}
key = headerKey(number, hash)
if err := db.Put(key, data); err != nil {
log.Crit("Failed to store header", "err", err)
}
}
// DeleteHeader removes all block header data associated with a hash.
func DeleteHeader(db xordb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(headerNumberKey(hash)); err != nil {
log.Crit("Failed to delete hash to number mapping", "err", err)
}
}
// ReadBodyData retrieves the block body in json encoding
func ReadBodyData(db xordb.Reader, hash common.Hash, number uint64) []byte {
data, _ := db.Get(blockBodyKey(number, hash))
return data
}
// WriteBodyData stores block body into the database in json encoding
func WriteBodyData(db xordb.Writer, hash common.Hash, number uint64, data []byte) {
if err := db.Put(blockBodyKey(number, hash), data); err != nil {
log.Crit("Failed to store block body", "err", err)
}
}
// HasBody verifies the existence of a block body corresponding to the hash.
func HasBody(db xordb.Reader, hash common.Hash, number uint64) bool {
if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil {
return false
}
return true
}
// ReadBody retrieves the block body corresponding to the hash.
func ReadBody(db xordb.Reader, hash common.Hash, number uint64) *types.Body {
data := ReadBodyData(db, hash, number)
if len(data) == 0 {
return nil
}
body := new(types.Body)
json.Unmarshal(data, &body)
txs := body.Transactions
for i := 0; i < len(txs); i++ {
txdata := txs[i].Data
participants := make([]*(ecdsa.PublicKey), len(txdata.Participants))
postStates := make([]*(state.Account), len(txdata.Participants))
for i := 0; i < len(txdata.Participants); i++ {
txdata.Participants[i] = &ecdsa.PublicKey{Curve: elliptic.P256()}
txdata.PostStates[i] = &state.Account{PublicKey: txdata.Participants[i]}
}
txdata = types.Txdata{Participants: participants, PostStates: postStates}
}
json.Unmarshal(data, &body)
return body
}
// WriteBody stores a block body into the database.
func WriteBody(db xordb.Writer, hash common.Hash, number uint64, body *types.Body) {
data, err := json.Marshal(body)
if err != nil {
fmt.Println("error while encoding", err)
}
WriteBodyData(db, hash, number, data)
}
// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db xordb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
}
// ReadTdData retrieves a block's total difficulty corresponding to the hash.
func ReadTdData(db xordb.Reader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(headerTDKey(number, hash))
return data
}
// ReadTd retrieves a block's total difficulty corresponding to the hash.
func ReadTd(db xordb.Reader, hash common.Hash, number uint64) *big.Int {
data := ReadTdData(db, hash, number)
if len(data) == 0 {
return nil
}
td := new(big.Int)
if err := rlp.Decode(bytes.NewReader(data), td); err != nil {
log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err)
return nil
}
return td
}
// WriteTd stores the total difficulty of a block into the database.
func WriteTd(db xordb.Writer, hash common.Hash, number uint64, td *big.Int) {
data, err := rlp.EncodeToBytes(td)
if err != nil {
log.Crit("Failed to RLP encode block total difficulty", "err", err)
}
if err := db.Put(headerTDKey(number, hash), data); err != nil {
log.Crit("Failed to store block total difficulty", "err", err)
}
}
// DeleteTd removes all block total difficulty data associated with a hash.
func DeleteTd(db xordb.Writer, hash common.Hash, number uint64) {
if err := db.Delete(headerTDKey(number, hash)); err != nil {
log.Crit("Failed to delete block total difficulty", "err", err)
}
}
// LoadBlockByBN retrieves an entire block corresponding to the number
func LoadBlockByBN(db xordb.Reader, number uint64) *types.Block {
hash := ReadHash(db, number)
header := ReadHeader(db, hash, number)
if header == nil {
return nil
}
body := ReadBody(db, hash, number)
txs := body.Transactions
b := types.NewBlock(header, txs)
return b
}
// LoadHeaderByBN retrieves an entire header corresponding to the number
func LoadHeaderByBN(db xordb.Reader, number uint64) *types.Header {
hash := ReadHash(db, number)
header := ReadHeader(db, hash, number)
if header == nil {
fmt.Println("header empty")
return nil
}
return types.CopyHeader(header)
}
// LoadHeader retrieves an entire header corresponding to the hash & number
func LoadHeader(db xordb.Reader, hash common.Hash, number uint64) *types.Header {
header := ReadHeader(db, hash, number)
if header == nil {
fmt.Println("header empty")
return nil
}
return types.CopyHeader(header)
}
// LoadBlock retrieves an entire block corresponding to the hash & number
func LoadBlock(db xordb.Reader, hash common.Hash, number uint64) *types.Block {
header := ReadHeader(db, hash, number)
if header == nil {
fmt.Println("header nil")
return nil
}
body := ReadBody(db, hash, number)
txs := body.Transactions
b := types.NewBlock(header, txs)
return b
}
// StoreBlock serializes a block into the database, header and body separately.
func StoreBlock(db xordb.Writer, block *types.Block) {
WriteHash(db, block.Hash(), block.Number())
WriteHeader(db, block.Header())
WriteBody(db, block.Hash(), block.Number(), block.Body())
WriteTxLookupEntries(db, block)
}
// DeleteBlock removes all block data associated with a hash.
func DeleteBlock(db xordb.Writer, hash common.Hash, number uint64) {
DeleteHash(db, number)
DeleteHeader(db, hash, number)
// DeleteBody(db, hash, number)
DeleteTd(db, hash, number)
}
// ReadGenesisHeaderHash retrieves the hash of the genesis block.
func ReadGenesisHeaderHash(db xordb.Reader) common.Hash {
data, _ := db.Get(genesisHeaderKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteGenesisHeaderHash stores the hash of the genesis block.
func WriteGenesisHeaderHash(db xordb.Writer, hash common.Hash) {
if err := db.Put(genesisHeaderKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last header's hash", "err", err)
}
}
// ReadLastHeaderHash retrieves the hash of the last header.
func ReadLastHeaderHash(db xordb.Reader) common.Hash {
data, _ := db.Get(lastHeaderKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteLastHeaderHash stores the hash of the last header.
func WriteLastHeaderHash(db xordb.Writer, hash common.Hash) {
if err := db.Put(lastHeaderKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last header's hash", "err", err)
}
}
// ReadHeadBlockHash retrieves the hash of the last block.
func ReadHeadBlockHash(db xordb.Reader) common.Hash {
data, _ := db.Get(lastBlockKey)
if len(data) == 0 {
return common.Hash{}
}
return common.BytesToHash(data)
}
// WriteHeadBlockHash stores the last block's hash.
func WriteHeadBlockHash(db xordb.Writer, hash common.Hash) {
if err := db.Put(lastBlockKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last block's hash", "err", err)
}
}