@@ -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
1721var 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
5481type SnapshotReader interface {
0 commit comments