lotus/chain/actors/manifest.go
Steven Allen 30981d0fdd
feat: refactor: actor bundling system (#8838)
1. Include the builtin-actors in the lotus source tree.
2. Embed the bundle on build instead of downloading at runtime.
3. Avoid reading the bundle whenever possible by including bundle
   metadata (the bundle CID, the actor CIDs, etc.).
4. Remove everything related to dependency injection.
    1. We're no longer downloading the bundle, so doing anything ahead
       of time doesn't really help.
    2. We register the manifests on init because, unfortunately, they're
       global.
    3. We explicitly load the current actors bundle in the genesis
       state-tree method.
    4. For testing, we just change the in-use bundle with a bit of a
       hack. It's not great, but using dependency injection doesn't make
       any sense either because, again, the manifest information is
       global.
    5. Remove the bundle.toml file. Bundles may be overridden by
       specifying an override path in the parameters file, or an
       environment variable.

fixes #8701
2022-06-13 10:15:00 -07:00

145 lines
3.2 KiB
Go

package actors
import (
"context"
"strings"
"sync"
"github.com/filecoin-project/go-state-types/manifest"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/actors/adt"
cid "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
)
var manifestCids map[Version]cid.Cid = make(map[Version]cid.Cid)
var manifests map[Version]map[string]cid.Cid = make(map[Version]map[string]cid.Cid)
var actorMeta map[cid.Cid]actorEntry = make(map[cid.Cid]actorEntry)
const (
AccountKey = "account"
CronKey = "cron"
InitKey = "init"
MarketKey = "storagemarket"
MinerKey = "storageminer"
MultisigKey = "multisig"
PaychKey = "paymentchannel"
PowerKey = "storagepower"
RewardKey = "reward"
SystemKey = "system"
VerifregKey = "verifiedregistry"
)
func GetBuiltinActorsKeys() []string {
return []string{
AccountKey,
CronKey,
InitKey,
MarketKey,
MinerKey,
MultisigKey,
PaychKey,
PowerKey,
RewardKey,
SystemKey,
VerifregKey,
}
}
var (
manifestMx sync.RWMutex
)
type actorEntry struct {
name string
version Version
}
// ClearManifest clears all known manifests. This is usually used in tests that need to switch networks.
func ClearManifests() {
manifestMx.Lock()
defer manifestMx.Unlock()
manifestCids = make(map[Version]cid.Cid)
manifests = make(map[Version]map[string]cid.Cid)
actorMeta = make(map[cid.Cid]actorEntry)
}
// RegisterManifest registers an actors manifest with lotus.
func RegisterManifest(av Version, manifestCid cid.Cid, entries map[string]cid.Cid) {
manifestMx.Lock()
defer manifestMx.Unlock()
manifestCids[av] = manifestCid
manifests[av] = entries
for name, c := range entries {
actorMeta[c] = actorEntry{name: name, version: av}
}
}
// GetManifest gets a loaded manifest.
func GetManifest(av Version) (cid.Cid, bool) {
manifestMx.RLock()
defer manifestMx.RUnlock()
c, ok := manifestCids[av]
return c, ok
}
// ReadManifest reads a manifest from a blockstore. It does not "add" it.
func ReadManifest(ctx context.Context, store cbor.IpldStore, mfCid cid.Cid) (map[string]cid.Cid, error) {
adtStore := adt.WrapStore(ctx, store)
var mf manifest.Manifest
if err := adtStore.Get(ctx, mfCid, &mf); err != nil {
return nil, xerrors.Errorf("error reading manifest (cid: %s): %w", mfCid, err)
}
if err := mf.Load(ctx, adtStore); err != nil {
return nil, xerrors.Errorf("error loading manifest (cid: %s): %w", mfCid, err)
}
actorKeys := GetBuiltinActorsKeys() // TODO: we should be able to enumerate manifests directly.
metadata := make(map[string]cid.Cid, len(actorKeys))
for _, name := range actorKeys {
if c, ok := mf.Get(name); ok {
metadata[name] = c
}
}
return metadata, nil
}
// GetActorCodeID looks up a builtin actor's code CID by actor version and canonical actor name name.
func GetActorCodeID(av Version, name string) (cid.Cid, bool) {
manifestMx.RLock()
defer manifestMx.RUnlock()
c, ok := manifests[av][name]
return c, ok
}
func GetActorMetaByCode(c cid.Cid) (string, Version, bool) {
manifestMx.RLock()
defer manifestMx.RUnlock()
entry, ok := actorMeta[c]
if !ok {
return "", -1, false
}
return entry.name, entry.version, true
}
func CanonicalName(name string) string {
idx := strings.LastIndex(name, "/")
if idx >= 0 {
return name[idx+1:]
}
return name
}