2019-09-06 06:26:02 +00:00
package stmgr
import (
"context"
2022-11-14 19:06:55 +00:00
"errors"
2020-09-04 03:28:42 +00:00
"fmt"
2020-07-03 16:57:58 +00:00
"reflect"
2020-04-17 23:36:54 +00:00
2021-07-27 13:43:03 +00:00
"github.com/ipfs/go-cid"
2020-04-20 17:43:02 +00:00
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
2021-07-27 13:43:03 +00:00
"github.com/filecoin-project/go-state-types/big"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/go-state-types/manifest"
gstStore "github.com/filecoin-project/go-state-types/store"
2019-10-18 04:47:41 +00:00
"github.com/filecoin-project/lotus/api"
2020-09-14 22:43:12 +00:00
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
2022-06-07 03:14:16 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
2020-10-08 20:32:54 +00:00
"github.com/filecoin-project/lotus/chain/actors/policy"
2022-06-07 03:14:16 +00:00
"github.com/filecoin-project/lotus/chain/rand"
2020-03-31 23:13:37 +00:00
"github.com/filecoin-project/lotus/chain/state"
2020-01-17 02:33:43 +00:00
"github.com/filecoin-project/lotus/chain/store"
2019-10-18 04:47:41 +00:00
"github.com/filecoin-project/lotus/chain/types"
2020-01-17 02:33:43 +00:00
"github.com/filecoin-project/lotus/chain/vm"
2020-03-31 23:13:37 +00:00
"github.com/filecoin-project/lotus/node/modules/dtypes"
2019-09-06 06:26:02 +00:00
)
2022-11-14 19:06:55 +00:00
var ErrMetadataNotFound = errors . New ( "actor metadata not found" )
2021-07-27 13:43:03 +00:00
func GetReturnType ( ctx context . Context , sm * StateManager , to address . Address , method abi . MethodNum , ts * types . TipSet ) ( cbg . CBORUnmarshaler , error ) {
act , err := sm . LoadActor ( ctx , to , ts )
2020-04-21 14:32:17 +00:00
if err != nil {
2022-09-09 20:42:55 +00:00
return nil , xerrors . Errorf ( "(get sset) failed to load actor: %w" , err )
2020-03-02 01:09:38 +00:00
}
2020-04-16 20:52:40 +00:00
2021-09-02 16:07:23 +00:00
m , found := sm . tsExec . NewActorRegistry ( ) . Methods [ act . Code ] [ method ]
2021-07-27 13:43:03 +00:00
if ! found {
2022-11-14 19:06:55 +00:00
return nil , fmt . Errorf ( "unknown method %d for actor %s: %w" , method , act . Code , ErrMetadataNotFound )
2020-03-02 01:09:38 +00:00
}
2022-09-09 20:42:55 +00:00
2021-07-27 13:43:03 +00:00
return reflect . New ( m . Ret . Elem ( ) ) . Interface ( ) . ( cbg . CBORUnmarshaler ) , nil
2019-11-15 01:01:53 +00:00
}
2021-09-02 16:07:23 +00:00
func GetParamType ( ar * vm . ActorRegistry , actCode cid . Cid , method abi . MethodNum ) ( cbg . CBORUnmarshaler , error ) {
m , found := ar . Methods [ actCode ] [ method ]
2020-05-06 00:04:25 +00:00
if ! found {
2022-11-14 19:06:55 +00:00
return nil , fmt . Errorf ( "unknown method %d for actor %s: %w" , method , actCode , ErrMetadataNotFound )
2020-05-06 00:04:25 +00:00
}
2021-07-27 13:43:03 +00:00
return reflect . New ( m . Params . Elem ( ) ) . Interface ( ) . ( cbg . CBORUnmarshaler ) , nil
2019-11-07 07:57:10 +00:00
}
2021-07-27 13:43:03 +00:00
func GetNetworkName ( ctx context . Context , sm * StateManager , st cid . Cid ) ( dtypes . NetworkName , error ) {
act , err := sm . LoadActorRaw ( ctx , init_ . Address , st )
2020-09-15 11:04:45 +00:00
if err != nil {
2021-07-27 13:43:03 +00:00
return "" , err
2020-09-15 11:04:45 +00:00
}
2021-07-27 13:43:03 +00:00
ias , err := init_ . Load ( sm . cs . ActorStore ( ctx ) , act )
2020-09-15 11:04:45 +00:00
if err != nil {
2021-07-27 13:43:03 +00:00
return "" , err
2019-12-17 06:51:41 +00:00
}
2021-07-27 13:43:03 +00:00
return ias . NetworkName ( )
2019-09-17 22:43:47 +00:00
}
2020-01-17 02:33:43 +00:00
2020-03-08 02:31:36 +00:00
func ComputeState ( ctx context . Context , sm * StateManager , height abi . ChainEpoch , msgs [ ] * types . Message , ts * types . TipSet ) ( cid . Cid , [ ] * api . InvocResult , error ) {
2020-01-17 02:33:43 +00:00
if ts == nil {
ts = sm . cs . GetHeaviestTipSet ( )
}
2020-03-08 02:31:36 +00:00
base , trace , err := sm . ExecutionTrace ( ctx , ts )
2020-01-17 02:33:43 +00:00
if err != nil {
2020-03-08 02:31:36 +00:00
return cid . Undef , nil , err
2020-01-17 02:33:43 +00:00
}
2020-09-24 21:30:11 +00:00
for i := ts . Height ( ) ; i < height ; i ++ {
2021-08-27 00:23:04 +00:00
// Technically, the tipset we're passing in here should be ts+1, but that may not exist.
2021-09-02 16:07:23 +00:00
base , err = sm . HandleStateForks ( ctx , base , i , & InvocationTracer { trace : & trace } , ts )
2020-09-24 21:30:11 +00:00
if err != nil {
return cid . Undef , nil , xerrors . Errorf ( "error handling state forks: %w" , err )
}
2021-08-27 00:23:04 +00:00
// We intentionally don't run cron here, as we may be trying to look into the
// future. It's not guaranteed to be accurate... but that's fine.
2020-09-24 21:30:11 +00:00
}
2021-12-17 23:54:17 +00:00
r := rand . NewStateRand ( sm . cs , ts . Cids ( ) , sm . beacon , sm . GetNetworkVersion )
2020-08-06 17:09:03 +00:00
vmopt := & vm . VMOpts {
2020-08-09 22:49:38 +00:00
StateBase : base ,
Epoch : height ,
2022-10-03 19:05:46 +00:00
Timestamp : ts . MinTimestamp ( ) ,
2020-08-09 22:49:38 +00:00
Rand : r ,
2021-02-28 22:48:36 +00:00
Bstore : sm . cs . StateBlockstore ( ) ,
2021-09-02 16:07:23 +00:00
Actors : sm . tsExec . NewActorRegistry ( ) ,
Syscalls : sm . Syscalls ,
2020-10-11 22:17:28 +00:00
CircSupplyCalc : sm . GetVMCirculatingSupply ,
2021-12-18 00:05:59 +00:00
NetworkVersion : sm . GetNetworkVersion ( ctx , height ) ,
2020-08-09 22:49:38 +00:00
BaseFee : ts . Blocks ( ) [ 0 ] . ParentBaseFee ,
2020-10-24 09:57:17 +00:00
LookbackState : LookbackStateGetterForTipset ( sm , ts ) ,
2022-11-22 17:41:03 +00:00
TipSetGetter : TipSetGetterForTipset ( sm . cs , ts ) ,
2022-07-14 19:09:31 +00:00
Tracing : true ,
2020-08-06 17:09:03 +00:00
}
2020-10-07 22:26:08 +00:00
vmi , err := sm . newVM ( ctx , vmopt )
2020-01-17 02:33:43 +00:00
if err != nil {
2020-03-08 02:31:36 +00:00
return cid . Undef , nil , err
2020-01-17 02:33:43 +00:00
}
for i , msg := range msgs {
2020-03-25 11:29:35 +00:00
// TODO: Use the signed message length for secp messages
2020-03-25 19:13:09 +00:00
ret , err := vmi . ApplyMessage ( ctx , msg )
2020-01-17 02:33:43 +00:00
if err != nil {
2020-03-08 02:31:36 +00:00
return cid . Undef , nil , xerrors . Errorf ( "applying message %s: %w" , msg . Cid ( ) , err )
2020-01-17 02:33:43 +00:00
}
if ret . ExitCode != 0 {
2020-01-17 06:14:00 +00:00
log . Infof ( "compute state apply message %d failed (exit: %d): %s" , i , ret . ExitCode , ret . ActorErr )
2020-01-17 02:33:43 +00:00
}
}
2020-03-08 02:31:36 +00:00
root , err := vmi . Flush ( ctx )
if err != nil {
return cid . Undef , nil , err
}
return root , trace , nil
2020-01-17 02:33:43 +00:00
}
2020-04-02 01:10:28 +00:00
2020-10-24 09:57:17 +00:00
func LookbackStateGetterForTipset ( sm * StateManager , ts * types . TipSet ) vm . LookbackStateGetter {
return func ( ctx context . Context , round abi . ChainEpoch ) ( * state . StateTree , error ) {
_ , st , err := GetLookbackTipSetForRound ( ctx , sm , ts , round )
if err != nil {
return nil , err
}
return sm . StateTree ( st )
}
}
2022-11-22 17:41:03 +00:00
func TipSetGetterForTipset ( cs * store . ChainStore , ts * types . TipSet ) vm . TipSetGetter {
return func ( ctx context . Context , round abi . ChainEpoch ) ( types . TipSetKey , error ) {
ts , err := cs . GetTipsetByHeight ( ctx , round , ts , true )
if err != nil {
return types . EmptyTSK , err
}
return ts . Key ( ) , nil
}
}
2020-10-23 21:52:26 +00:00
func GetLookbackTipSetForRound ( ctx context . Context , sm * StateManager , ts * types . TipSet , round abi . ChainEpoch ) ( * types . TipSet , cid . Cid , error ) {
2020-04-17 23:36:54 +00:00
var lbr abi . ChainEpoch
2021-12-17 23:43:39 +00:00
lb := policy . GetWinningPoStSectorSetLookback ( sm . GetNetworkVersion ( ctx , round ) )
2020-10-06 09:26:25 +00:00
if round > lb {
lbr = round - lb
2020-04-17 23:36:54 +00:00
}
// more null blocks than our lookback
2020-10-23 21:52:26 +00:00
if lbr >= ts . Height ( ) {
// This should never happen at this point, but may happen before
// network version 3 (where the lookback was only 10 blocks).
st , _ , err := sm . TipSetState ( ctx , ts )
if err != nil {
return nil , cid . Undef , err
}
return ts , st , nil
}
// Get the tipset after the lookback tipset, or the next non-null one.
nextTs , err := sm . ChainStore ( ) . GetTipsetByHeight ( ctx , lbr + 1 , ts , false )
if err != nil {
return nil , cid . Undef , xerrors . Errorf ( "failed to get lookback tipset+1: %w" , err )
}
if lbr > nextTs . Height ( ) {
return nil , cid . Undef , xerrors . Errorf ( "failed to find non-null tipset %s (%d) which is known to exist, found %s (%d)" , ts . Key ( ) , ts . Height ( ) , nextTs . Key ( ) , nextTs . Height ( ) )
2020-04-17 23:36:54 +00:00
}
2021-12-11 21:03:00 +00:00
lbts , err := sm . ChainStore ( ) . GetTipSetFromKey ( ctx , nextTs . Parents ( ) )
2020-04-17 23:36:54 +00:00
if err != nil {
2020-10-23 21:52:26 +00:00
return nil , cid . Undef , xerrors . Errorf ( "failed to resolve lookback tipset: %w" , err )
2020-04-17 23:36:54 +00:00
}
2020-10-23 21:52:26 +00:00
return lbts , nextTs . ParentState ( ) , nil
2020-04-17 23:36:54 +00:00
}
2021-07-27 13:30:23 +00:00
func CheckTotalFIL ( ctx context . Context , cs * store . ChainStore , ts * types . TipSet ) ( abi . TokenAmount , error ) {
str , err := state . LoadStateTree ( cs . ActorStore ( ctx ) , ts . ParentState ( ) )
2020-08-12 22:20:32 +00:00
if err != nil {
return abi . TokenAmount { } , err
}
sum := types . NewInt ( 0 )
err = str . ForEach ( func ( a address . Address , act * types . Actor ) error {
sum = types . BigAdd ( sum , act . Balance )
return nil
} )
if err != nil {
return abi . TokenAmount { } , err
}
return sum , nil
}
2020-10-15 22:48:51 +00:00
func MakeMsgGasCost ( msg * types . Message , ret * vm . ApplyRet ) api . MsgGasCost {
return api . MsgGasCost {
Message : msg . Cid ( ) ,
GasUsed : big . NewInt ( ret . GasUsed ) ,
BaseFeeBurn : ret . GasCosts . BaseFeeBurn ,
OverEstimationBurn : ret . GasCosts . OverEstimationBurn ,
MinerPenalty : ret . GasCosts . MinerPenalty ,
MinerTip : ret . GasCosts . MinerTip ,
Refund : ret . GasCosts . Refund ,
TotalCost : big . Sub ( msg . RequiredFunds ( ) , ret . GasCosts . Refund ) ,
}
}
2021-07-27 13:15:50 +00:00
func ( sm * StateManager ) ListAllActors ( ctx context . Context , ts * types . TipSet ) ( [ ] address . Address , error ) {
stateTree , err := sm . StateTree ( sm . parentState ( ts ) )
if err != nil {
return nil , err
}
var out [ ] address . Address
err = stateTree . ForEach ( func ( addr address . Address , act * types . Actor ) error {
out = append ( out , addr )
return nil
} )
if err != nil {
return nil , err
}
return out , nil
}
2022-06-07 03:14:16 +00:00
2022-06-28 22:42:58 +00:00
func GetManifestData ( ctx context . Context , st * state . StateTree ) ( * manifest . ManifestData , error ) {
2022-06-07 03:14:16 +00:00
wrapStore := gstStore . WrapStore ( ctx , st . Store )
systemActor , err := st . GetActor ( system . Address )
if err != nil {
return nil , fmt . Errorf ( "failed to get system actor: %w" , err )
}
systemActorState , err := system . Load ( wrapStore , systemActor )
if err != nil {
return nil , xerrors . Errorf ( "failed to load system actor state: %w" , err )
}
2022-06-28 22:42:58 +00:00
actorsManifestDataCid := systemActorState . GetBuiltinActors ( )
2022-06-07 03:14:16 +00:00
2022-06-28 22:42:58 +00:00
var mfData manifest . ManifestData
if err := wrapStore . Get ( ctx , actorsManifestDataCid , & mfData ) ; err != nil {
return nil , xerrors . Errorf ( "error fetching data: %w" , err )
2022-06-07 03:14:16 +00:00
}
2022-06-28 22:42:58 +00:00
return & mfData , nil
2022-06-07 03:14:16 +00:00
}