/
history_archive_state.go
113 lines (99 loc) · 2.62 KB
/
history_archive_state.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
// Copyright 2016 DiamNet Development Foundation and contributors. Licensed
// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0
package historyarchive
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/diamnet/go/support/errors"
"github.com/diamnet/go/xdr"
)
const NumLevels = 11
type HistoryArchiveState struct {
Version int `json:"version"`
Server string `json:"server"`
CurrentLedger uint32 `json:"currentLedger"`
CurrentBuckets [NumLevels]struct {
Curr string `json:"curr"`
Snap string `json:"snap"`
Next struct {
State uint32 `json:"state"`
Output string `json:"output,omitempty"`
} `json:"next"`
} `json:"currentBuckets"`
}
func (h *HistoryArchiveState) LevelSummary() (string, int, error) {
summ := ""
nz := 0
for _, b := range h.CurrentBuckets {
state := '_'
for _, bs := range []string{
b.Curr, b.Snap, b.Next.Output,
} {
// Ignore empty values
if bs == "" {
continue
}
h, err := DecodeHash(bs)
if err != nil {
return summ, nz, err
}
if !h.IsZero() {
state = '#'
}
}
if state != '_' {
nz += 1
}
summ += string(state)
}
return summ, nz, nil
}
func (h *HistoryArchiveState) Buckets() ([]Hash, error) {
r := []Hash{}
for _, b := range h.CurrentBuckets {
for _, bs := range []string{
b.Curr, b.Snap, b.Next.Output,
} {
// Ignore empty values
if bs == "" {
continue
}
h, err := DecodeHash(bs)
if err != nil {
return r, err
}
if !h.IsZero() {
r = append(r, h)
}
}
}
return r, nil
}
// BucketListHash calculates the hash of bucket list in the HistoryArchiveState.
// This can be later compared with LedgerHeader.BucketListHash of the checkpoint
// ledger to ensure data in history archive has not been changed by a malicious
// actor.
// Warning: Ledger header should be fetched from a trusted (!) diamnet-core
// instead of ex. history archives!
func (h *HistoryArchiveState) BucketListHash() (xdr.Hash, error) {
total := []byte{}
for i, b := range h.CurrentBuckets {
curr, err := hex.DecodeString(b.Curr)
if err != nil {
return xdr.Hash{}, errors.Wrap(err, fmt.Sprintf("Error decoding hex of %d.curr", i))
}
snap, err := hex.DecodeString(b.Snap)
if err != nil {
return xdr.Hash{}, errors.Wrap(err, fmt.Sprintf("Error decoding hex of %d.snap", i))
}
both := append(curr, snap...)
bothHash := sha256.Sum256(both)
total = append(total, bothHash[:]...)
}
return sha256.Sum256(total), nil
}
func (h *HistoryArchiveState) Range() Range {
return Range{Low: 63, High: h.CurrentLedger}
}