-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathlifecycle.go
116 lines (105 loc) · 5.53 KB
/
lifecycle.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
// Copyright 2024 The Tessera authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tessera
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"github.com/transparency-dev/trillian-tessera/api"
"github.com/transparency-dev/trillian-tessera/api/layout"
)
// NoMoreEntries is a sentinel error returned by StreamEntries when no more entries will be returned by calls to the next function.
var ErrNoMoreEntries = errors.New("no more entries")
// LogReader provides read-only access to the log.
type LogReader interface {
// ReadCheckpoint returns the latest checkpoint available.
ReadCheckpoint(ctx context.Context) ([]byte, error)
// ReadTile returns the raw marshalled tile at the given coordinates, if it exists.
// The expected usage for this method is to derive the parameters from a tree size
// that has been committed to by a checkpoint returned by this log. Whenever such a
// tree size is used, this method will behave as per the https://c2sp.org/tlog-tiles
// spec for the /tile/ path.
//
// If callers pass in parameters that are not implied by a published tree size, then
// implementations _may_ act differently from one another, but all will act in ways
// that are allowed by the spec. For example, if the only published tree size has been
// for size 2, then asking for a partial tile of 1 may lead to some implementations
// returning not found, some may return a tile with 1 leaf, and some may return a tile
// with more leaves.
ReadTile(ctx context.Context, level, index uint64, p uint8) ([]byte, error)
// ReadEntryBundle returns the raw marshalled leaf bundle at the given coordinates, if
// it exists.
// The expected usage and corresponding behaviours are similar to ReadTile.
ReadEntryBundle(ctx context.Context, index uint64, p uint8) ([]byte, error)
// IntegratedSize returns the current size of the integrated tree.
//
// This tree will have in place all the static resources the returned size implies, but
// there may not yet be a checkpoint for this size signed, witnessed, or published.
//
// It's ONLY safe to use this value for processes internal to the operation of the log (e.g.
// populating antispam data structures); it MUST NOT not be used as a substitute for
// reading the checkpoint when only data which has been publicly committed to by the
// log should be used. If in doubt, use ReadCheckpoint instead.
IntegratedSize(ctx context.Context) (uint64, error)
// StreamEntries() returns functions `next` and `stop` which act like a pull iterator for
// consecutive entry bundles, starting with the entry bundle which contains the requested entry
// index.
//
// Each call to `next` will return raw entry bundle bytes along with a RangeInfo struct which
// contains information on which entries within that bundle are to be considered valid.
//
// next will hang if it has reached the extent of the current tree, and return once either
// the tree has grown and more entries are available, or cancel was called.
//
// next will cease iterating if either:
// - it produces an error (e.g. via the underlying calls to the log storage)
// - the returned cancel function is called
// and will continue to return an error if called again after either of these cases.
StreamEntries(ctx context.Context, fromEntryIdx uint64) (next func() (layout.RangeInfo, []byte, error), cancel func())
}
// Antispam describes the contract that an antispam implementation must meet in order to be used via the
// WithAntispam option below.
type Antispam interface {
// Decorator must return a function which knows how to decorate an Appender's Add function in order
// to return an index previously assigned to an entry with the same identity hash, if one exists, or
// delegate to the next Add function in the chain otherwise.
Decorator() func(AddFn) AddFn
// Populate should be a long-running function which uses the provided log reader to build the
// antispam index used by the dectorator above.
//
// Typically, implementations of this function will tail the contents of the log using the provided
// log reader to stream entry bundles from the log, and, for each entry bundle, use the
// provided bundle function to convert the bundle into a slice of identity hashes which
// corresponds to the entries the bundle contains. These hashes should then be used to populate
// some form of an identity hash -> index mapping.
//
// This function will be called automatically by Tessera, and is expected to block until the context
// is done.
Populate(context.Context, LogReader, func(entryBundle []byte) ([][]byte, error))
}
// defaultIDHasher returns a list of identity hashes corresponding to entries in the provided bundle.
// Currently, these are simply SHA256 hashes of the raw byte of each entry.
func defaultIDHasher(bundle []byte) ([][]byte, error) {
eb := &api.EntryBundle{}
if err := eb.UnmarshalText(bundle); err != nil {
return nil, fmt.Errorf("unmarshal: %v", err)
}
r := make([][]byte, 0, len(eb.Entries))
for _, e := range eb.Entries {
h := sha256.Sum256(e)
r = append(r, h[:])
}
return r, nil
}