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  }