github.com/filecoin-project/specs-actors/v4@v4.0.2/support/agent/blockstore_util.go (about) 1 package agent 2 3 import ( 4 "bytes" 5 "context" 6 7 block "github.com/ipfs/go-block-format" 8 cid "github.com/ipfs/go-cid" 9 cbor "github.com/ipfs/go-ipld-cbor" 10 mh "github.com/multiformats/go-multihash" 11 cbg "github.com/whyrusleeping/cbor-gen" 12 "golang.org/x/xerrors" 13 ) 14 15 // extracted from lotus/chain/vm/vm.go 16 17 func BlockstoreCopy(from, to cbor.IpldBlockstore, root cid.Cid) (blocks uint64, copySize uint64, err error) { 18 var numBlocks uint64 19 var totalCopySize uint64 20 21 cp := func(blk block.Block) error { 22 numBlocks++ 23 totalCopySize += uint64(len(blk.RawData())) 24 return to.Put(context.TODO(), blk) 25 } 26 27 if err := copyRec(from, to, root, cp); err != nil { 28 return 0, 0, xerrors.Errorf("copyRec: %w", err) 29 } 30 31 return numBlocks, totalCopySize, nil 32 } 33 34 func copyRec(from, to cbor.IpldBlockstore, root cid.Cid, cp func(block.Block) error) error { 35 if root.Prefix().MhType == 0 { 36 // identity cid, skip 37 return nil 38 } 39 40 blk, err := from.Get(context.TODO(), root) 41 if err != nil { 42 return xerrors.Errorf("get %s failed: %w", root, err) 43 } 44 45 var lerr error 46 err = linksForObj(blk, func(link cid.Cid) { 47 if lerr != nil { 48 // Theres no error return on linksForObj callback :( 49 return 50 } 51 52 prefix := link.Prefix() 53 if prefix.Codec == cid.FilCommitmentSealed || prefix.Codec == cid.FilCommitmentUnsealed { 54 return 55 } 56 57 // We always have blocks inlined into CIDs, but we may not have their children. 58 if prefix.MhType == mh.IDENTITY { 59 // Unless the inlined block has no children. 60 if prefix.Codec == cid.Raw { 61 return 62 } 63 } 64 65 if err := copyRec(from, to, link, cp); err != nil { 66 lerr = err 67 return 68 } 69 }) 70 if err != nil { 71 return xerrors.Errorf("linksForObj (%x): %w", blk.RawData(), err) 72 } 73 if lerr != nil { 74 return lerr 75 } 76 77 if err := cp(blk); err != nil { 78 return xerrors.Errorf("copy: %w", err) 79 } 80 return nil 81 } 82 83 func linksForObj(blk block.Block, cb func(cid.Cid)) error { 84 switch blk.Cid().Prefix().Codec { 85 case cid.DagCBOR: 86 err := cbg.ScanForLinks(bytes.NewReader(blk.RawData()), cb) 87 if err != nil { 88 return xerrors.Errorf("cbg.ScanForLinks: %w", err) 89 } 90 return nil 91 case cid.Raw: 92 // We implicitly have all children of raw blocks. 93 return nil 94 default: 95 return xerrors.Errorf("vm flush copy method only supports dag cbor") 96 } 97 }