1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package sharding
17
18 import (
19 "context"
20 "encoding/base64"
21 "encoding/json"
22 "errors"
23 "fmt"
24 "os"
25 "strconv"
26 "strings"
27
28 "github.com/google/trillian"
29 "github.com/google/trillian/types"
30 "github.com/sigstore/rekor/pkg/log"
31 "sigs.k8s.io/yaml"
32 )
33
34 type LogRanges struct {
35 inactive Ranges
36 active int64
37 }
38
39 type Ranges []LogRange
40
41 type LogRange struct {
42 TreeID int64 `json:"treeID" yaml:"treeID"`
43 TreeLength int64 `json:"treeLength" yaml:"treeLength"`
44 EncodedPublicKey string `json:"encodedPublicKey" yaml:"encodedPublicKey"`
45 decodedPublicKey string
46 }
47
48 func NewLogRanges(ctx context.Context, logClient trillian.TrillianLogClient, path string, treeID uint) (LogRanges, error) {
49 if path == "" {
50 log.Logger.Info("No config file specified, skipping init of logRange map")
51 return LogRanges{}, nil
52 }
53 if treeID == 0 {
54 return LogRanges{}, errors.New("non-zero tlog_id required when passing in shard config filepath; please set the active tree ID via the `--trillian_log_server.tlog_id` flag")
55 }
56
57 ranges, err := logRangesFromPath(path)
58 if err != nil {
59 return LogRanges{}, fmt.Errorf("log ranges from path: %w", err)
60 }
61 for i, r := range ranges {
62 r, err := updateRange(ctx, logClient, r)
63 if err != nil {
64 return LogRanges{}, fmt.Errorf("updating range for tree id %d: %w", r.TreeID, err)
65 }
66 ranges[i] = r
67 }
68 log.Logger.Info("Ranges: %v", ranges)
69 return LogRanges{
70 inactive: ranges,
71 active: int64(treeID),
72 }, nil
73 }
74
75 func logRangesFromPath(path string) (Ranges, error) {
76 var ranges Ranges
77 contents, err := os.ReadFile(path)
78 if err != nil {
79 return Ranges{}, err
80 }
81 if string(contents) == "" {
82 log.Logger.Info("Sharding config file contents empty, skipping init of logRange map")
83 return Ranges{}, nil
84 }
85 if err := yaml.Unmarshal(contents, &ranges); err != nil {
86
87 if jerr := json.Unmarshal(contents, &ranges); jerr == nil {
88 return ranges, nil
89 }
90 return Ranges{}, err
91 }
92 return ranges, nil
93 }
94
95
96 func updateRange(ctx context.Context, logClient trillian.TrillianLogClient, r LogRange) (LogRange, error) {
97
98 if r.TreeLength == 0 {
99 resp, err := logClient.GetLatestSignedLogRoot(ctx, &trillian.GetLatestSignedLogRootRequest{LogId: r.TreeID})
100 if err != nil {
101 return LogRange{}, fmt.Errorf("getting signed log root for tree %d: %w", r.TreeID, err)
102 }
103 var root types.LogRootV1
104 if err := root.UnmarshalBinary(resp.SignedLogRoot.LogRoot); err != nil {
105 return LogRange{}, err
106 }
107 r.TreeLength = int64(root.TreeSize)
108 }
109
110 if r.EncodedPublicKey != "" {
111 decoded, err := base64.StdEncoding.DecodeString(r.EncodedPublicKey)
112 if err != nil {
113 return LogRange{}, err
114 }
115 r.decodedPublicKey = string(decoded)
116 }
117 return r, nil
118 }
119
120 func (l *LogRanges) ResolveVirtualIndex(index int) (int64, int64) {
121 indexLeft := index
122 for _, l := range l.inactive {
123 if indexLeft < int(l.TreeLength) {
124 return l.TreeID, int64(indexLeft)
125 }
126 indexLeft -= int(l.TreeLength)
127 }
128
129
130 return l.active, int64(indexLeft)
131 }
132
133 func (l *LogRanges) ActiveTreeID() int64 {
134 return l.active
135 }
136
137 func (l *LogRanges) NoInactive() bool {
138 return l.inactive == nil
139 }
140
141
142 func (l *LogRanges) AllShards() []int64 {
143 shards := []int64{l.ActiveTreeID()}
144 for _, in := range l.GetInactive() {
145 shards = append(shards, in.TreeID)
146 }
147 return shards
148 }
149
150
151
152 func (l *LogRanges) TotalInactiveLength() int64 {
153 var total int64
154 for _, r := range l.inactive {
155 total += r.TreeLength
156 }
157 return total
158 }
159
160 func (l *LogRanges) SetInactive(r []LogRange) {
161 l.inactive = r
162 }
163
164 func (l *LogRanges) GetInactive() []LogRange {
165 return l.inactive
166 }
167
168 func (l *LogRanges) AppendInactive(r LogRange) {
169 l.inactive = append(l.inactive, r)
170 }
171
172 func (l *LogRanges) SetActive(i int64) {
173 l.active = i
174 }
175
176 func (l *LogRanges) GetActive() int64 {
177 return l.active
178 }
179
180 func (l *LogRanges) String() string {
181 ranges := []string{}
182 for _, r := range l.inactive {
183 ranges = append(ranges, fmt.Sprintf("%d=%d", r.TreeID, r.TreeLength))
184 }
185 ranges = append(ranges, fmt.Sprintf("active=%d", l.active))
186 return strings.Join(ranges, ",")
187 }
188
189
190
191 func (l *LogRanges) PublicKey(activePublicKey, treeID string) (string, error) {
192
193 if treeID == "" {
194 return activePublicKey, nil
195 }
196 tid, err := strconv.Atoi(treeID)
197 if err != nil {
198 return "", err
199 }
200
201 for _, i := range l.inactive {
202 if int(i.TreeID) == tid {
203 if i.decodedPublicKey != "" {
204 return i.decodedPublicKey, nil
205 }
206
207 return activePublicKey, nil
208 }
209 }
210 if tid == int(l.active) {
211 return activePublicKey, nil
212 }
213 return "", fmt.Errorf("%d is not a valid tree ID and doesn't have an associated public key", tid)
214 }
215
View as plain text