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
This commit is contained in:
Steven Allen
2022-06-13 10:15:00 -07:00
committed by GitHub
parent 1cd94f598d
commit 30981d0fdd
52 changed files with 669 additions and 854 deletions
-177
View File
@@ -1,177 +0,0 @@
package modules
import (
"fmt"
"os"
"sync"
"go.uber.org/fx"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/node/bundle"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/modules/helpers"
"github.com/filecoin-project/lotus/node/repo"
cid "github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore"
cbor "github.com/ipfs/go-ipld-cbor"
)
func LoadBuiltinActors(lc fx.Lifecycle, mctx helpers.MetricsCtx, r repo.LockedRepo, bs dtypes.UniversalBlockstore, ds dtypes.MetadataDS) (result dtypes.BuiltinActorsLoaded, err error) {
ctx := helpers.LifecycleCtx(mctx, lc)
// We can't put it as a dep in inputs causes a stack overflow in DI from circular dependency
// So we pass it through ldflags instead
netw := build.NetworkBundle
for av, bd := range build.BuiltinActorReleases {
// first check to see if we know this release
key := dstore.NewKey(fmt.Sprintf("/builtin-actors/v%d/%s/%s", av, bd.Release, netw))
data, err := ds.Get(ctx, key)
switch err {
case nil:
// ok, we do, this should be the manifest cid
mfCid, err := cid.Cast(data)
if err != nil {
return result, xerrors.Errorf("error parsing cid for %s: %w", key, err)
}
// check the blockstore for existence of the manifest
has, err := bs.Has(ctx, mfCid)
if err != nil {
return result, xerrors.Errorf("error checking blockstore for manifest cid %s: %w", mfCid, err)
}
if has {
// it's there, no need to reload the bundle to the blockstore; just add it to the manifest list.
if val, ok := build.ActorsCIDs[av]; ok {
if val != mfCid {
return result, xerrors.Errorf("actors V%d manifest CID %s did not match CID given in params file: %s", av, mfCid, val)
}
}
actors.AddManifest(av, mfCid)
continue
}
// we have a release key but don't have the manifest in the blockstore; maybe the user
// nuked his blockstore to restart from a snapshot. So fallthrough to refetch (if necessary)
// and reload the bundle.
case dstore.ErrNotFound:
// we don't have a release key, we need to load the bundle
default:
return result, xerrors.Errorf("error loading %s from datastore: %w", key, err)
}
// we haven't recorded it in the datastore, so we need to load it
envvar := fmt.Sprintf("LOTUS_BUILTIN_ACTORS_V%d_BUNDLE", av)
var mfCid cid.Cid
switch {
case os.Getenv(envvar) != "":
path := os.Getenv(envvar)
mfCid, err = bundle.LoadBundle(ctx, bs, path, av)
if err != nil {
return result, err
}
case bd.Path[netw] != "":
// this is a local bundle, load it directly from the filessystem
mfCid, err = bundle.LoadBundle(ctx, bs, bd.Path[netw], av)
if err != nil {
return result, err
}
case bd.URL[netw].URL != "":
// fetch it from the specified URL
mfCid, err = bundle.FetchAndLoadBundleFromURL(ctx, r.Path(), bs, av, bd.Release, netw, bd.URL[netw].URL, bd.URL[netw].Checksum)
if err != nil {
return result, err
}
case bd.Release != "":
// fetch it and add it to the blockstore
mfCid, err = bundle.FetchAndLoadBundleFromRelease(ctx, r.Path(), bs, av, bd.Release, netw)
if err != nil {
return result, err
}
default:
return result, xerrors.Errorf("no release or path specified for version %d bundle", av)
}
if bd.Development || bd.Release == "" {
// don't store the release key so that we always load development bundles
continue
}
// add the release key with the manifest to avoid reloading it in next restart.
if err := ds.Put(ctx, key, mfCid.Bytes()); err != nil {
return result, xerrors.Errorf("error storing manifest CID for builtin-actors vrsion %d to the datastore: %w", av, err)
}
}
// we've loaded all the bundles, now load the manifests to get actor code CIDs.
cborStore := cbor.NewCborStore(bs)
if err := actors.LoadManifests(ctx, cborStore); err != nil {
return result, xerrors.Errorf("error loading actor manifests: %w", err)
}
return result, nil
}
// for itests
var testingBundleMx sync.Mutex
func LoadBuiltinActorsTesting(lc fx.Lifecycle, mctx helpers.MetricsCtx, bs dtypes.UniversalBlockstore) (result dtypes.BuiltinActorsLoaded, err error) {
ctx := helpers.LifecycleCtx(mctx, lc)
var netw string
if build.InsecurePoStValidation {
netw = "testing-fake-proofs"
} else {
netw = "testing"
}
testingBundleMx.Lock()
defer testingBundleMx.Unlock()
// don't clobber the bundle during migration
build.NetworkBundle = netw
const basePath = "/tmp/lotus-testing"
for av, bd := range build.BuiltinActorReleases {
switch {
case bd.Path[netw] != "":
if _, err := bundle.LoadBundle(ctx, bs, bd.Path[netw], av); err != nil {
return result, xerrors.Errorf("error loading testing bundle for builtin-actors version %d/%s: %w", av, netw, err)
}
case bd.URL[netw].URL != "":
// fetch it from the specified URL
if _, err := bundle.FetchAndLoadBundleFromURL(ctx, basePath, bs, av, bd.Release, netw, bd.URL[netw].URL, bd.URL[netw].Checksum); err != nil {
return result, err
}
case bd.Release != "":
if _, err := bundle.FetchAndLoadBundleFromRelease(ctx, basePath, bs, av, bd.Release, netw); err != nil {
return result, xerrors.Errorf("error loading testing bundle for builtin-actors version %d/%s: %w", av, netw, err)
}
default:
return result, xerrors.Errorf("no path or release specified for version %d testing bundle", av)
}
}
cborStore := cbor.NewCborStore(bs)
if err := actors.LoadManifests(ctx, cborStore); err != nil {
return result, xerrors.Errorf("error loading actor manifests: %w", err)
}
return result, nil
}
+1 -1
View File
@@ -178,6 +178,6 @@ func NewSlashFilter(ds dtypes.MetadataDS) *slashfilter.SlashFilter {
return slashfilter.New(ds)
}
func UpgradeSchedule(_ dtypes.BuiltinActorsLoaded) stmgr.UpgradeSchedule {
func UpgradeSchedule() stmgr.UpgradeSchedule {
return filcns.DefaultUpgradeSchedule()
}
-1
View File
@@ -2,4 +2,3 @@ package dtypes
type NetworkName string
type AfterGenesisSet struct{}
type BuiltinActorsLoaded struct{}
+3 -3
View File
@@ -22,8 +22,8 @@ func ErrorGenesis() Genesis {
}
}
func LoadGenesis(genBytes []byte) func(fx.Lifecycle, helpers.MetricsCtx, dtypes.ChainBlockstore, dtypes.BuiltinActorsLoaded) Genesis {
return func(lc fx.Lifecycle, mctx helpers.MetricsCtx, bs dtypes.ChainBlockstore, _ dtypes.BuiltinActorsLoaded) Genesis {
func LoadGenesis(genBytes []byte) func(fx.Lifecycle, helpers.MetricsCtx, dtypes.ChainBlockstore) Genesis {
return func(lc fx.Lifecycle, mctx helpers.MetricsCtx, bs dtypes.ChainBlockstore) Genesis {
return func() (header *types.BlockHeader, e error) {
ctx := helpers.LifecycleCtx(mctx, lc)
c, err := car.LoadCar(ctx, bs, bytes.NewReader(genBytes))
@@ -49,7 +49,7 @@ func LoadGenesis(genBytes []byte) func(fx.Lifecycle, helpers.MetricsCtx, dtypes.
func DoSetGenesis(_ dtypes.AfterGenesisSet) {}
func SetGenesis(lc fx.Lifecycle, mctx helpers.MetricsCtx, cs *store.ChainStore, g Genesis, _ dtypes.BuiltinActorsLoaded) (dtypes.AfterGenesisSet, error) {
func SetGenesis(lc fx.Lifecycle, mctx helpers.MetricsCtx, cs *store.ChainStore, g Genesis) (dtypes.AfterGenesisSet, error) {
ctx := helpers.LifecycleCtx(mctx, lc)
genFromRepo, err := cs.GetGenesis(ctx)
if err == nil {
-2
View File
@@ -219,8 +219,6 @@ type StorageMinerParams struct {
Journal journal.Journal
AddrSel *storage.AddressSelector
Maddr dtypes.MinerAddress
ManifestLoaded dtypes.BuiltinActorsLoaded
}
func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*storage.Miner, error) {
+4 -4
View File
@@ -30,8 +30,8 @@ import (
var glog = logging.Logger("genesis")
func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal, _ dtypes.BuiltinActorsLoaded) modules.Genesis {
return func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal, _ dtypes.BuiltinActorsLoaded) modules.Genesis {
func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal) modules.Genesis {
return func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal) modules.Genesis {
return func() (*types.BlockHeader, error) {
glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network")
b, err := genesis2.MakeGenesisBlock(context.TODO(), j, bs, syscalls, template)
@@ -51,8 +51,8 @@ func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.Cha
}
}
func MakeGenesis(outFile, genesisTemplate string) func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal, _ dtypes.BuiltinActorsLoaded) modules.Genesis {
return func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal, _ dtypes.BuiltinActorsLoaded) modules.Genesis {
func MakeGenesis(outFile, genesisTemplate string) func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal) modules.Genesis {
return func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder, j journal.Journal) modules.Genesis {
return func() (*types.BlockHeader, error) {
glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network")
genesisTemplate, err := homedir.Expand(genesisTemplate)