diff --git a/go.sum b/go.sum index c2ab42816..3e052b212 100644 --- a/go.sum +++ b/go.sum @@ -1346,6 +1346,7 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= github.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df h1:vdYtBU6zvL7v+Tr+0xFM/qhahw/EvY8DMMunZHKH6eE= diff --git a/lens/carrepo/carrepo.go b/lens/carrepo/carrepo.go index ff29f1551..939713d23 100644 --- a/lens/carrepo/carrepo.go +++ b/lens/carrepo/carrepo.go @@ -32,5 +32,6 @@ func NewAPIOpener(c *cli.Context) (lens.APIOpener, lens.APICloser, error) { tsk := types.NewTipSetKey(c...) return &tsk, nil } + return util.NewAPIOpener(c, cacheDB, h) } diff --git a/lens/lotus/api.go b/lens/lotus/api.go index 3ac205e05..cf2d52969 100644 --- a/lens/lotus/api.go +++ b/lens/lotus/api.go @@ -132,7 +132,10 @@ func (aw *APIWrapper) StateGetActor(ctx context.Context, actor address.Address, ctx, _ = tag.New(ctx, tag.Upsert(metrics.API, "StateGetActor")) stop := metrics.Timer(ctx, metrics.LensRequestDuration) defer stop() - return aw.FullNode.StateGetActor(ctx, actor, tsk) + + //return aw.FullNode.StateGetActor(ctx, actor, tsk) + // TODO idk how to get a store.ChainStore here + return lens.OptimizedStateGetActorWithFallback(ctx, aw.Store(), aw.FullNode, aw.FullNode, actor, tsk) } func (aw *APIWrapper) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { diff --git a/lens/lotusrepo/repo.go b/lens/lotusrepo/repo.go index 747a190d1..7a959ec73 100644 --- a/lens/lotusrepo/repo.go +++ b/lens/lotusrepo/repo.go @@ -126,6 +126,11 @@ func (ra *RepoAPI) Store() adt.Store { return adtStore } +// TODO: Remove. See https://github.com/filecoin-project/sentinel-visor/issues/196 +func (ra *RepoAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + return lens.OptimizedStateGetActorWithFallback(ctx, ra.ChainAPI.Chain.Store(ctx), ra.ChainAPI, ra.StateAPI, actor, tsk) +} + func (ra *RepoAPI) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) { return nil, fmt.Errorf("unsupported") } diff --git a/lens/util.go b/lens/util.go new file mode 100644 index 000000000..4667b585a --- /dev/null +++ b/lens/util.go @@ -0,0 +1,58 @@ +package lens + +import ( + "context" + "errors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/impl/full" + cbor "github.com/ipfs/go-ipld-cbor" + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" +) + +var logger = logging.Logger("visor/lens/lotus") + +// OptimizedStateGetActorWithFallback is a helper to obtain an actor in the +// state of the current tipset without recomputing the full tipset. It does +// this by obtaining the child tipset (current height+1) and using the +// pre-computed ParentState(). +// +// TODO: Remove. See: https://github.com/filecoin-project/sentinel-visor/issues/196 +func OptimizedStateGetActorWithFallback(ctx context.Context, store cbor.IpldStore, chainAPI full.ChainModuleAPI, fallback full.StateModuleAPI, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + act, err := efficientStateGetActorFromChainStore(ctx, store, chainAPI, actor, tsk) + if err != nil { + logger.Warnf("Optimized StateGetActorError: %s. Falling back to default StateGetActor().", err) + return fallback.StateGetActor(ctx, actor, tsk) + } + return act, nil +} + +func efficientStateGetActorFromChainStore(ctx context.Context, store cbor.IpldStore, chainAPI full.ChainModuleAPI, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + ts, err := chainAPI.ChainGetTipSet(ctx, tsk) + if err != nil { + return nil, xerrors.Errorf("Failed to load tipset: %w", err) + } + + // heaviest tipset means look on the main chain and false means return tipset following null round. + head, err := chainAPI.ChainHead(ctx) + if err != nil { + return nil, xerrors.Errorf("Failed to get chain head: %w", err) + } + child, err := chainAPI.ChainGetTipSetByHeight(ctx, ts.Height()+1, head.Key()) + if err != nil { + return nil, xerrors.Errorf("load child tipset: %w", err) + } + + if !types.CidArrsEqual(child.Parents().Cids(), ts.Cids()) { + return nil, errors.New("child is not on the same chain") + } + + st, err := state.LoadStateTree(store, child.ParentState()) + if err != nil { + return nil, xerrors.Errorf("load state tree: %w", err) + } + return st.GetActor(actor) +} diff --git a/lens/util/repo.go b/lens/util/repo.go index 0050b81dd..292f47551 100644 --- a/lens/util/repo.go +++ b/lens/util/repo.go @@ -104,6 +104,11 @@ type LensAPI struct { cs *store.ChainStore } +// TODO: Remove. See https://github.com/filecoin-project/sentinel-visor/issues/196 +func (ra *LensAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + return lens.OptimizedStateGetActorWithFallback(ctx, ra.cs.Store(ctx), ra.FullNodeAPI.ChainAPI, ra.FullNodeAPI.StateAPI, actor, tsk) +} + func (ra *LensAPI) ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) vm.GasOutputs { return vm.ComputeGasOutputs(gasUsed, gasLimit, baseFee, feeCap, gasPremium) }