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:
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -2,4 +2,3 @@ package dtypes
|
||||
|
||||
type NetworkName string
|
||||
type AfterGenesisSet struct{}
|
||||
type BuiltinActorsLoaded struct{}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user