Skip to content

Commit 740fe1a

Browse files
committed
feat: certstore snapshot export
1 parent 20d68df commit 740fe1a

File tree

3 files changed

+271
-0
lines changed

3 files changed

+271
-0
lines changed

certstore/cbor_gen.go

Lines changed: 175 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

certstore/snapshot.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package certstore
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/binary"
7+
"errors"
8+
"io"
9+
10+
"github.com/filecoin-project/go-f3/gpbft"
11+
"github.com/ipfs/go-datastore"
12+
xerrors "golang.org/x/xerrors"
13+
)
14+
15+
var ErrlatestCertificateNil = errors.New("latest certificate is not available")
16+
17+
// Exports an F3 snapshot that includes the finality certificate chain until the current `latestCertificate`.
18+
func (cs *Store) ExportLatestSnapshot(ctx context.Context, writer io.Writer) error {
19+
if cs.latestCertificate == nil {
20+
return ErrlatestCertificateNil
21+
}
22+
return cs.ExportSnapshot(ctx, cs.latestCertificate.GPBFTInstance, writer)
23+
}
24+
25+
// Exports an F3 snapshot that includes the finality certificate chain until the specified `lastInstance`.
26+
func (cs *Store) ExportSnapshot(ctx context.Context, lastInstance uint64, writer io.Writer) error {
27+
initialPowerTable, err := cs.GetPowerTable(ctx, cs.firstInstance)
28+
if err != nil {
29+
return xerrors.Errorf("failed to get initial power table at instance %d: %w", cs.firstInstance, err)
30+
}
31+
header := SnapshotHeader{1, cs.firstInstance, lastInstance, initialPowerTable}
32+
if err := header.WriteToSnapshot(writer); err != nil {
33+
return xerrors.Errorf("failed to write snapshot header: %w", err)
34+
}
35+
for i := cs.firstInstance; i <= lastInstance; i++ {
36+
cert, err := cs.ds.Get(ctx, cs.keyForCert(i))
37+
if err != nil {
38+
return xerrors.Errorf("failed to get certificate at instance %d:: %w", i, err)
39+
}
40+
buffer := bytes.NewBuffer(cert)
41+
if err := writeSnapshotBlockBytes(writer, buffer); err != nil {
42+
return err
43+
}
44+
}
45+
return nil
46+
}
47+
48+
// Imports an F3 snapshot and opens the certificate store.
49+
//
50+
// The passed Datastore has to be thread safe.
51+
func ImportSnapshotAndOpenStore(ctx context.Context, ds datastore.Datastore) error {
52+
return xerrors.New("to be implemented")
53+
}
54+
55+
type SnapshotHeader struct {
56+
Version uint64
57+
FirstInstance uint64
58+
LatestInstance uint64
59+
InitialPowerTable gpbft.PowerEntries
60+
}
61+
62+
func (h *SnapshotHeader) WriteToSnapshot(writer io.Writer) error {
63+
return writeSnapshotCborEncodedBlock(writer, h)
64+
}
65+
66+
// Writes CBOR-encoded header or data block with a varint-encoded length prefix
67+
func writeSnapshotCborEncodedBlock(writer io.Writer, block MarshalCBOR) error {
68+
var buffer bytes.Buffer
69+
if err := block.MarshalCBOR(&buffer); err != nil {
70+
return err
71+
}
72+
return writeSnapshotBlockBytes(writer, &buffer)
73+
}
74+
75+
// Writes header or data block with a varint-encoded length prefix
76+
func writeSnapshotBlockBytes(writer io.Writer, buffer *bytes.Buffer) error {
77+
buf := make([]byte, 8)
78+
n := binary.PutUvarint(buf, uint64(buffer.Len()))
79+
if _, err := writer.Write(buf[:n]); err != nil {
80+
return err
81+
}
82+
if _, err := buffer.WriteTo(writer); err != nil {
83+
return err
84+
}
85+
return nil
86+
}
87+
88+
type MarshalCBOR interface {
89+
MarshalCBOR(w io.Writer) error
90+
}

gen/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/filecoin-project/go-f3/certexchange"
88
"github.com/filecoin-project/go-f3/certs"
9+
"github.com/filecoin-project/go-f3/certstore"
910
"github.com/filecoin-project/go-f3/chainexchange"
1011
"github.com/filecoin-project/go-f3/gpbft"
1112
gen "github.com/whyrusleeping/cbor-gen"
@@ -47,6 +48,11 @@ func main() {
4748
chainexchange.Message{},
4849
)
4950
})
51+
eg.Go(func() error {
52+
return gen.WriteTupleEncodersToFile("../certstore/cbor_gen.go", "certstore",
53+
certstore.SnapshotHeader{},
54+
)
55+
})
5056
if err := eg.Wait(); err != nil {
5157
fmt.Printf("Failed to complete cborg_gen: %v\n", err)
5258
os.Exit(1)

0 commit comments

Comments
 (0)