Skip to content

Commit 3cde113

Browse files
committed
export snapshot CID
1 parent 415f470 commit 3cde113

2 files changed

Lines changed: 49 additions & 11 deletions

File tree

certstore/snapshot.go

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,76 @@ import (
66
"encoding/binary"
77
"errors"
88
"fmt"
9+
"hash"
910
"io"
1011

1112
"github.com/filecoin-project/go-f3/certs"
1213
"github.com/filecoin-project/go-f3/gpbft"
1314
"github.com/filecoin-project/go-state-types/cbor"
15+
cid "github.com/ipfs/go-cid"
1416
"github.com/ipfs/go-datastore"
17+
"github.com/multiformats/go-multihash"
18+
"golang.org/x/crypto/blake2b"
1519
)
1620

1721
var ErrUnknownLatestCertificate = errors.New("latest certificate is not known")
1822

1923
// ExportLatestSnapshot exports an F3 snapshot that includes the finality certificate chain until the current `latestCertificate`.
2024
//
2125
// Checkout the snapshot format specification at <https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0108.md>
22-
func (cs *Store) ExportLatestSnapshot(ctx context.Context, writer io.Writer) error {
26+
func (cs *Store) ExportLatestSnapshot(ctx context.Context, writer io.Writer) (cid.Cid, error) {
2327
if cs.latestCertificate == nil {
24-
return ErrUnknownLatestCertificate
28+
return cid.Undef, ErrUnknownLatestCertificate
2529
}
2630
return cs.ExportSnapshot(ctx, cs.latestCertificate.GPBFTInstance, writer)
2731
}
2832

2933
// ExportSnapshot exports an F3 snapshot that includes the finality certificate chain from the `Store.firstInstance` to the specified `lastInstance`.
3034
//
3135
// Checkout the snapshot format specification at <https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0108.md>
32-
func (cs *Store) ExportSnapshot(ctx context.Context, latestInstance uint64, writer io.Writer) error {
36+
func (cs *Store) ExportSnapshot(ctx context.Context, latestInstance uint64, writer io.Writer) (cid.Cid, error) {
37+
hasher, err := blake2b.New256(nil)
38+
if err != nil {
39+
return cid.Undef, err
40+
}
41+
hashWriter := hashWriter{hasher, writer}
3342
initialPowerTable, err := cs.GetPowerTable(ctx, cs.firstInstance)
3443
if err != nil {
35-
return fmt.Errorf("failed to get initial power table at instance %d: %w", cs.firstInstance, err)
44+
return cid.Undef, fmt.Errorf("failed to get initial power table at instance %d: %w", cs.firstInstance, err)
3645
}
3746
header := SnapshotHeader{1, cs.firstInstance, latestInstance, initialPowerTable}
38-
if _, err := header.WriteTo(writer); err != nil {
39-
return fmt.Errorf("failed to write snapshot header: %w", err)
47+
if _, err := header.WriteTo(hashWriter); err != nil {
48+
return cid.Undef, fmt.Errorf("failed to write snapshot header: %w", err)
4049
}
4150
for i := cs.firstInstance; i <= latestInstance; i++ {
4251
cert, err := cs.ds.Get(ctx, cs.keyForCert(i))
4352
if err != nil {
44-
return fmt.Errorf("failed to get certificate at instance %d:: %w", i, err)
53+
return cid.Undef, fmt.Errorf("failed to get certificate at instance %d:: %w", i, err)
4554
}
4655
buffer := bytes.NewBuffer(cert)
47-
if _, err := writeSnapshotBlockBytes(writer, buffer); err != nil {
48-
return err
56+
if _, err := writeSnapshotBlockBytes(hashWriter, buffer); err != nil {
57+
return cid.Undef, err
4958
}
5059
}
51-
return nil
60+
hash := hashWriter.hasher.Sum(nil)
61+
mh, err := multihash.Encode(hash, multihash.BLAKE2B_MIN+31)
62+
if err != nil {
63+
return cid.Undef, err
64+
}
65+
66+
return cid.NewCidV1(cid.Raw, mh), nil
67+
}
68+
69+
type hashWriter struct {
70+
hasher hash.Hash
71+
writer io.Writer
72+
}
73+
74+
func (w hashWriter) Write(p []byte) (n int, err error) {
75+
if _, err := w.hasher.Write(p); err != nil {
76+
return 0, err
77+
}
78+
return w.writer.Write(p)
5279
}
5380

5481
type SnapshotReader interface {

certstore/snapshot_test.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ import (
1313
"github.com/filecoin-project/go-f3/internal/consensus"
1414
"github.com/filecoin-project/go-f3/manifest"
1515
"github.com/filecoin-project/go-f3/sim/signing"
16+
"github.com/ipfs/go-cid"
1617
"github.com/ipfs/go-datastore"
18+
"github.com/multiformats/go-multihash"
1719
"github.com/stretchr/testify/require"
1820
"go.uber.org/zap/buffer"
21+
"golang.org/x/crypto/blake2b"
1922
)
2023

2124
func Test_SnapshotExportImportRoundTrip(t *testing.T) {
@@ -88,8 +91,16 @@ func Test_SnapshotExportImportRoundTrip(t *testing.T) {
8891
}
8992

9093
snapshot := buffer.Buffer{}
91-
err = cs.ExportLatestSnapshot(ctx, &snapshot)
94+
c, err := cs.ExportLatestSnapshot(ctx, &snapshot)
9295
require.NoError(t, err)
96+
require.NotEqual(t, c, cid.Undef)
97+
require.Equal(t, int(c.Prefix().Version), 1)
98+
require.Equal(t, int(c.Prefix().Codec), cid.Raw)
99+
require.Equal(t, int(c.Prefix().MhType), 0xb220)
100+
hash := blake2b.Sum256(snapshot.Bytes())
101+
mh, err := multihash.Encode(hash[:], multihash.BLAKE2B_MIN+31)
102+
require.NoError(t, err)
103+
require.Equal(t, c.Hash(), multihash.Multihash(mh))
93104

94105
ds2 := datastore.NewMapDatastore()
95106
err = importSnapshotToDatastoreWithTestingPowerTableFrequency(ctx, bytes.NewReader(snapshot.Bytes()), ds2, testingPowerTableFreqency)

0 commit comments

Comments
 (0)