@@ -20,6 +20,8 @@ import (
2020 "github.com/ipld/go-car/util"
2121)
2222
23+ // ValidateProof validates a proof for a Cid at a specified offset. If the proof is valid, the return
24+ // parameter is true. If the proof is invalid false is returned. In any other case an error is returned.
2325func ValidateProof (ctx context.Context , root cid.Cid , offset uint64 , proof []byte ) (bool , error ) {
2426 r := bufio .NewReader (bytes .NewReader (proof ))
2527
@@ -35,6 +37,9 @@ func ValidateProof(ctx context.Context, root cid.Cid, offset uint64, proof []byt
3537 return false , fmt .Errorf ("the root isn't the expected one" )
3638 }
3739
40+ // TODO(jsign): if we assume some ordering in the CAR file we could simply have a CAR-serial walker
41+ // which would make this much faster and probably simpler in a way avoiding blockstores, etc.
42+ // For now, not have those assumptions and do a naive-ish walk.
3843 for {
3944 block , err := cr .Next ()
4045 if err == io .EOF {
@@ -45,33 +50,35 @@ func ValidateProof(ctx context.Context, root cid.Cid, offset uint64, proof []byt
4550 }
4651 }
4752 dserv := dag .NewDAGService (bsrv .New (bstore , offline .Exchange (bstore )))
53+
54+ // Smart (or lazy?) way to verify the proof. If we assume an ideal full DAGStore, trying to
55+ // re-create the proof with the proof as the underlying blockstore should fail if something
56+ // is missing.
4857 regenProof , err := CreateProof (ctx , root , offset , dserv )
4958 if err != nil {
5059 return false , fmt .Errorf ("regenerating proof to validate: %s" , err )
5160 }
52- if ! bytes .Equal (proof , regenProof ) {
53- return false , fmt .Errorf ("proof is invalid" )
54- }
5561
56- return true , nil
62+ return ! bytes . Equal ( proof , regenProof ) , nil
5763}
5864
65+ // CreateProof creates a proof for a Cid at a specified file offset.
5966func CreateProof (ctx context.Context , root cid.Cid , offset uint64 , dserv ipld.DAGService ) ([]byte , error ) {
6067 n , err := dserv .Get (ctx , root )
6168 if err != nil {
6269 return nil , fmt .Errorf ("get %s from dag service: %s" , root , err )
6370 }
64- list := []ipld.Node {n }
71+ proofNodes := []ipld.Node {n }
6572
66- var currOffset , layer uint64
73+ var currOffset uint64
6774 for n != nil {
6875 var next ipld.Node
6976 for _ , child := range n .Links () {
7077 cn , err := child .GetNode (ctx , dserv )
7178 if err != nil {
72- return nil , fmt .Errorf ("get child from layer %d : %s" , layer , err )
79+ return nil , fmt .Errorf ("get child %s : %s" , child . Cid , err )
7380 }
74- list = append (list , cn )
81+ proofNodes = append (proofNodes , cn )
7582
7683 if next == nil {
7784 fsNode , err := unixfs .ExtractFSNode (n )
@@ -86,7 +93,6 @@ func CreateProof(ctx context.Context, root cid.Cid, offset uint64, dserv ipld.DA
8693 }
8794 }
8895 }
89- layer ++
9096 n = next
9197 }
9298
@@ -99,8 +105,8 @@ func CreateProof(ctx context.Context, root cid.Cid, offset uint64, dserv ipld.DA
99105 return nil , fmt .Errorf ("writing car header: %s" , err )
100106 }
101107 seen := cid .NewSet ()
102- for i := 0 ; i < len (list ); i ++ {
103- n := list [i ]
108+ for i := 0 ; i < len (proofNodes ); i ++ {
109+ n := proofNodes [i ]
104110 if ! seen .Visit (n .Cid ()) {
105111 continue
106112 }
0 commit comments