Skip to content

Commit

Permalink
address review
Browse files Browse the repository at this point in the history
  • Loading branch information
arajasek committed Jun 29, 2022
1 parent a52d584 commit f9cf25f
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 79 deletions.
11 changes: 5 additions & 6 deletions chain/actors/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,19 @@ func ReadManifest(ctx context.Context, store cbor.IpldStore, mfCid cid.Cid) (map
return metadata, nil
}

// Given a Manifest CID (NOT the ManifestData CID), load the underlying ManifestData
func LoadManifestData(ctx context.Context, mfCid cid.Cid, adtStore adt.Store) (*manifest.ManifestData, error) {
// Given a Manifest CID, get the manifest from the store and Load data into its entries
func LoadManifest(ctx context.Context, mfCid cid.Cid, adtStore adt.Store) (*manifest.Manifest, error) {
var mf manifest.Manifest
var mfData manifest.ManifestData

if err := adtStore.Get(ctx, mfCid, &mf); err != nil {
return nil, xerrors.Errorf("error reading manifest: %w", err)
}

if err := adtStore.Get(ctx, mf.Data, &mfData); err != nil {
return nil, xerrors.Errorf("error fetching data: %w", err)
if err := mf.Load(ctx, adtStore); err != nil {
return nil, xerrors.Errorf("error loading manifest entries data: %w", err)
}

return &mfData, nil
return &mf, nil
}

// GetActorCodeID looks up a builtin actor's code CID by actor version and canonical actor name.
Expand Down
20 changes: 15 additions & 5 deletions chain/consensus/filcns/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -1483,13 +1483,18 @@ func LiteMigration(ctx context.Context, bstore blockstore.Blockstore, newActorsM
}

// load new manifest
newManifest := manifest.Manifest{}
var newManifest manifest.Manifest
if err := store.Get(ctx, newActorsManifestCid, &newManifest); err != nil {
return cid.Undef, xerrors.Errorf("error getting new manifest: %w", err)
}

// populate the entries field of the manifest
if err = newManifest.Load(ctx, store); err != nil {
return cid.Undef, xerrors.Errorf("error loading new manifest: %w", err)
}

newManifestData, err := actors.LoadManifestData(ctx, newActorsManifestCid, store)
if err != nil {
var newManifestData manifest.ManifestData
if err := store.Get(ctx, newManifest.Data, &newManifestData); err != nil {
return cid.Undef, xerrors.Errorf("error loading new manifest data: %w", err)
}

Expand All @@ -1503,8 +1508,13 @@ func LiteMigration(ctx context.Context, bstore blockstore.Blockstore, newActorsM
// Maps prior version code CIDs to migration functions.
migrations := make(map[cid.Cid]cid.Cid)

for i, entry := range newManifestData.Entries {
migrations[oldManifestData.Entries[i].Code] = entry.Code
for _, entry := range oldManifestData.Entries {
newCodeCid, ok := newManifest.Get(entry.Name)
if !ok {
return cid.Undef, xerrors.Errorf("code cid for %s actor not found in new manifest", entry.Name)
}

migrations[entry.Code] = newCodeCid
}

startTime := time.Now()
Expand Down
125 changes: 64 additions & 61 deletions chain/vm/fvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (

var _ Interface = (*FVM)(nil)
var _ ffi_cgo.Externs = (*FvmExtern)(nil)
var debugBundleV8path = os.Getenv("LOTUS_FVM_DEBUG_BUNDLE_V8")

type FvmExtern struct {
Rand
Expand Down Expand Up @@ -255,18 +256,18 @@ type FVM struct {
fvm *ffi.FVM
}

func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) {
state, err := state.LoadStateTree(cbor.NewCborStore(opts.Bstore), opts.StateBase)
if err != nil {
return nil, err
return nil, xerrors.Errorf("loading state tree: %w", err)
}

circToReport, err := opts.CircSupplyCalc(ctx, opts.Epoch, state)
if err != nil {
return nil, err
return nil, xerrors.Errorf("calculating circ supply: %w", err)
}

fvmopts := &ffi.FVMOpts{
return &ffi.FVMOpts{
FVMVersion: 0,
Externs: &FvmExtern{
Rand: opts.Rand,
Expand All @@ -281,6 +282,14 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
NetworkVersion: opts.NetworkVersion,
StateBase: opts.StateBase,
Tracing: EnableDetailedTracing,
}, nil

}

func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
fvmOpts, err := defaultFVMOpts(ctx, opts)
if err != nil {
return nil, xerrors.Errorf("creating fvm opts: %w", err)
}

if os.Getenv("LOTUS_USE_FVM_CUSTOM_BUNDLE") == "1" {
Expand All @@ -294,10 +303,10 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
return nil, xerrors.Errorf("no manifest for custom bundle (actors version %d)", av)
}

fvmopts.Manifest = c
fvmOpts.Manifest = c
}

fvm, err := ffi.CreateFVM(fvmopts)
fvm, err := ffi.CreateFVM(fvmOpts)

if err != nil {
return nil, err
Expand All @@ -309,39 +318,19 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
}

func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
state, err := state.LoadStateTree(cbor.NewCborStore(opts.Bstore), opts.StateBase)
if err != nil {
return nil, err
}

circToReport, err := opts.CircSupplyCalc(ctx, opts.Epoch, state)
if err != nil {
return nil, err
}

baseBstore := opts.Bstore
overlayBstore := blockstore.NewMemorySync()
cborStore := cbor.NewCborStore(overlayBstore)
vmBstore := blockstore.NewTieredBstore(overlayBstore, baseBstore)

fvmopts := &ffi.FVMOpts{
FVMVersion: 0,
Externs: &FvmExtern{
Rand: opts.Rand,
Blockstore: vmBstore,
lbState: opts.LookbackState,
base: opts.StateBase,
epoch: opts.Epoch,
},
Epoch: opts.Epoch,
BaseFee: opts.BaseFee,
BaseCircSupply: circToReport,
NetworkVersion: opts.NetworkVersion,
StateBase: opts.StateBase,
Tracing: EnableDetailedTracing,
Debug: true,
opts.Bstore = vmBstore
fvmOpts, err := defaultFVMOpts(ctx, opts)
if err != nil {
return nil, xerrors.Errorf("creating fvm opts: %w", err)
}

fvmOpts.Debug = true

putMapping := func(ar map[cid.Cid]cid.Cid) (cid.Cid, error) {
var mapping xMapping

Expand All @@ -362,47 +351,61 @@ func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
return mappingCid, nil
}

av, err := actors.VersionForNetwork(opts.NetworkVersion)
if err != nil {
return nil, xerrors.Errorf("error determining actors version for network version %d: %w", opts.NetworkVersion, err)
}
createMapping := func(debugBundlePath string) error {
mfCid, err := bundle.LoadBundleFromFile(ctx, overlayBstore, debugBundlePath)
if err != nil {
return xerrors.Errorf("loading debug bundle: %w", err)
}

switch av {
case actors.Version8:
if bundlePath := os.Getenv("LOTUS_FVM_DEBUG_BUNDLE_V8"); bundlePath != "" {
mfCid, err := bundle.LoadBundleFromFile(ctx, overlayBstore, bundlePath)
if err != nil {
return nil, err
mf, err := actors.LoadManifest(ctx, mfCid, adt.WrapStore(ctx, cborStore))
if err != nil {
return xerrors.Errorf("loading debug manifest: %w", err)
}

// create actor redirect mapping
actorRedirect := make(map[cid.Cid]cid.Cid)
for _, key := range actors.GetBuiltinActorsKeys() {
from, ok := actors.GetActorCodeID(actors.Version8, key)
if !ok {
log.Warnf("actor missing in the from manifest %s", key)
continue
}

mf, err := actors.LoadManifestData(ctx, mfCid, adt.WrapStore(ctx, cborStore))
if err != nil {
return nil, err
to, ok := mf.Get(key)
if !ok {
log.Warnf("actor missing in the to manifest %s", key)
continue
}

// create actor redirect mapping
actorRedirect := make(map[cid.Cid]cid.Cid)
for _, e := range mf.Entries {
from, ok := actors.GetActorCodeID(actors.Version8, e.Name)
if !ok {
log.Warnf("unknown actor %s", e.Name)
continue
}
actorRedirect[from] = to
}

actorRedirect[from] = e.Code
if len(actorRedirect) > 0 {
mappingCid, err := putMapping(actorRedirect)
if err != nil {
return xerrors.Errorf("error writing redirect mapping: %w", err)
}
fvmOpts.ActorRedirect = mappingCid
}

return nil
}

if len(actorRedirect) > 0 {
mappingCid, err := putMapping(actorRedirect)
if err != nil {
return nil, xerrors.Errorf("error writing redirect mapping: %w", err)
}
fvmopts.ActorRedirect = mappingCid
av, err := actors.VersionForNetwork(opts.NetworkVersion)
if err != nil {
return nil, xerrors.Errorf("error determining actors version for network version %d: %w", opts.NetworkVersion, err)
}

switch av {
case actors.Version8:
if debugBundleV8path != "" {
if err := createMapping(debugBundleV8path); err != nil {
log.Errorf("failed to create v8 debug mapping")
}
}
}

fvm, err := ffi.CreateFVM(fvmopts)
fvm, err := ffi.CreateFVM(fvmOpts)

if err != nil {
return nil, err
Expand Down
10 changes: 8 additions & 2 deletions chain/vm/vmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,23 @@ type Interface interface {

var useFvmForMainnetV15 = os.Getenv("LOTUS_USE_FVM_TO_SYNC_MAINNET_V15") == "1"

// WARNING: You will not affect your node's execution by misusing this feature, but you will confuse yourself thoroughly!
// An envvar that allows the user to specify debug actors bundles to be used by the FVM
// alongside regular execution. This is basically only to be used to print out specific logging information.
// Message failures, unexpected terminations,gas costs, etc. should all be ignored.
var useFvmDebug = os.Getenv("LOTUS_FVM_DEVELOPER_DEBUG") == "1"

func NewVM(ctx context.Context, opts *VMOpts) (Interface, error) {
if opts.NetworkVersion >= network.Version16 {
if os.Getenv("LOTUS_FVM_DEBUG") == "1" {
if useFvmDebug {
return NewDualExecutionFVM(ctx, opts)
}
return NewFVM(ctx, opts)
}

// Remove after v16 upgrade, this is only to support testing and validation of the FVM
if useFvmForMainnetV15 && opts.NetworkVersion >= network.Version15 {
if os.Getenv("LOTUS_FVM_DEBUG") == "1" {
if useFvmDebug {
return NewDualExecutionFVM(ctx, opts)
}
return NewFVM(ctx, opts)
Expand Down
24 changes: 19 additions & 5 deletions itests/lite_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import (
"github.com/stretchr/testify/require"

"github.com/filecoin-project/go-address"
system8 "github.com/filecoin-project/go-state-types/builtin/v8/system"
"github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/go-state-types/network"
gstStore "github.com/filecoin-project/go-state-types/store"
"github.com/filecoin-project/specs-actors/v8/actors/util/adt"

"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
Expand Down Expand Up @@ -50,9 +52,12 @@ func TestLiteMigration(t *testing.T) {
oldManifestData, err := stmgr.GetManifestData(ctx, oldStateTree)
require.NoError(t, err)
newManifestCid := makeTestManifest(t, ctxStore)
// Use the Cid we generated to get the new manifest instead of loading it from the state tree, because that would not test that we have the correct manifest in the state
newManifestData, err := actors.LoadManifestData(ctx, newManifestCid, ctxStore)
require.NoError(t, err)
// Use the Cid we generated to get the new manifest instead of loading it from the store, so as to confirm it's in the store
var newManifest manifest.Manifest
require.NoError(t, ctxStore.Get(ctx, newManifestCid, &newManifest), "error getting new manifest")

// populate the entries field of the manifest
require.NoError(t, newManifest.Load(ctx, ctxStore), "error loading new manifest")

newStateRoot, err := filcns.LiteMigration(ctx, bs, newManifestCid, stateRoot, actors.Version8, types.StateTreeVersion4, types.StateTreeVersion4)
require.NoError(t, err)
Expand All @@ -61,8 +66,10 @@ func TestLiteMigration(t *testing.T) {
require.NoError(t, err)

migrations := make(map[cid.Cid]cid.Cid)
for i, entry := range newManifestData.Entries {
migrations[oldManifestData.Entries[i].Code] = entry.Code
for _, entry := range oldManifestData.Entries {
newCodeCid, ok := newManifest.Get(entry.Name)
require.True(t, ok)
migrations[entry.Code] = newCodeCid
}

err = newStateTree.ForEach(func(addr address.Address, newActorState *types.Actor) error {
Expand All @@ -71,6 +78,13 @@ func TestLiteMigration(t *testing.T) {
newCodeCid, ok := migrations[oldActor.Code]
require.True(t, ok)
require.Equal(t, newCodeCid, newActorState.Code)

if addr == system.Address {
var systemSt system8.State
require.NoError(t, ctxStore.Get(ctx, newActorState.Head, &systemSt))
require.Equal(t, systemSt.BuiltinActors, newManifest.Data)
}

return nil
})
require.NoError(t, err)
Expand Down

0 comments on commit f9cf25f

Please sign in to comment.