2019-09-06 06:26:02 +00:00
package stmgr
import (
"context"
2023-02-27 17:27:48 +00:00
"fmt"
2023-03-29 09:38:26 +00:00
"os"
"strconv"
2019-09-06 20:03:28 +00:00
"sync"
2021-05-30 18:54:09 +00:00
2023-11-21 14:02:09 +00:00
"github.com/hashicorp/golang-lru/arc/v2"
2020-09-14 11:45:20 +00:00
"github.com/ipfs/go-cid"
2023-02-27 17:27:48 +00:00
dstore "github.com/ipfs/go-datastore"
2020-09-14 11:45:20 +00:00
cbor "github.com/ipfs/go-ipld-cbor"
2023-03-07 19:35:40 +00:00
ipld "github.com/ipfs/go-ipld-format"
2020-09-14 11:45:20 +00:00
logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors"
2020-09-07 20:01:09 +00:00
2020-09-14 11:45:20 +00:00
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
2021-09-18 17:57:04 +00:00
"github.com/filecoin-project/go-state-types/crypto"
2020-09-14 11:45:20 +00:00
"github.com/filecoin-project/go-state-types/network"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/specs-actors/v8/actors/migration/nv16"
2020-08-06 17:09:03 +00:00
2020-02-08 02:18:32 +00:00
"github.com/filecoin-project/lotus/api"
2020-07-17 17:49:55 +00:00
"github.com/filecoin-project/lotus/build"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/lotus/chain/actors/adt"
2022-04-14 21:30:07 +00:00
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
2020-09-16 04:06:04 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
2021-07-27 13:15:50 +00:00
"github.com/filecoin-project/lotus/chain/actors/policy"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/lotus/chain/beacon"
2023-03-12 13:25:07 +00:00
"github.com/filecoin-project/lotus/chain/index"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/lotus/chain/rand"
2019-10-18 04:47:41 +00:00
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
2021-12-20 01:44:19 +00:00
// Used for genesis.
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
2019-09-06 06:26:02 +00:00
)
2021-04-05 11:23:46 +00:00
const LookbackNoLimit = api . LookbackNoLimit
2021-01-16 04:12:31 +00:00
const ReceiptAmtBitwidth = 3
2020-10-02 14:14:30 +00:00
2023-05-04 17:10:26 +00:00
var execTraceCacheSize = 16
2019-09-09 16:18:27 +00:00
var log = logging . Logger ( "statemgr" )
2019-09-06 06:26:02 +00:00
2020-09-29 15:25:45 +00:00
type StateManagerAPI interface {
2020-10-09 11:41:09 +00:00
Call ( ctx context . Context , msg * types . Message , ts * types . TipSet ) ( * api . InvocResult , error )
GetPaychState ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( * types . Actor , paych . State , error )
2020-09-29 15:25:45 +00:00
LoadActorTsk ( ctx context . Context , addr address . Address , tsk types . TipSetKey ) ( * types . Actor , error )
2020-09-30 14:36:16 +00:00
LookupID ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( address . Address , error )
2023-01-13 19:11:13 +00:00
ResolveToDeterministicAddress ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( address . Address , error )
2020-09-29 15:25:45 +00:00
}
2020-10-03 00:09:56 +00:00
type versionSpec struct {
networkVersion network . Version
atOrBelow abi . ChainEpoch
}
2021-01-26 20:46:57 +00:00
type migration struct {
2023-03-07 19:35:40 +00:00
upgrade MigrationFunc
preMigrations [ ] PreMigration
cache * nv16 . MemMigrationCache
migrationResultCache * migrationResultCache
2023-02-27 17:27:48 +00:00
}
2023-03-07 19:35:40 +00:00
type migrationResultCache struct {
2023-02-27 17:27:48 +00:00
ds dstore . Batching
keyPrefix string
}
2023-03-07 19:35:40 +00:00
func ( m * migrationResultCache ) keyForMigration ( root cid . Cid ) dstore . Key {
kStr := fmt . Sprintf ( "%s/%s" , m . keyPrefix , root )
return dstore . NewKey ( kStr )
}
2023-02-27 17:27:48 +00:00
2023-03-29 09:38:26 +00:00
func init ( ) {
2023-05-04 17:10:26 +00:00
if s := os . Getenv ( "LOTUS_EXEC_TRACE_CACHE_SIZE" ) ; s != "" {
2023-03-29 09:38:26 +00:00
letc , err := strconv . Atoi ( s )
if err != nil {
2023-05-04 17:10:26 +00:00
log . Errorf ( "failed to parse 'LOTUS_EXEC_TRACE_CACHE_SIZE' env var: %s" , err )
2023-03-29 15:30:00 +00:00
} else {
2023-05-04 17:10:26 +00:00
execTraceCacheSize = letc
2023-03-29 09:38:26 +00:00
}
}
}
2023-03-07 19:35:40 +00:00
func ( m * migrationResultCache ) Get ( ctx context . Context , root cid . Cid ) ( cid . Cid , bool , error ) {
k := m . keyForMigration ( root )
2023-02-27 17:27:48 +00:00
bs , err := m . ds . Get ( ctx , k )
2023-03-07 19:35:40 +00:00
if ipld . IsNotFound ( err ) {
return cid . Undef , false , nil
} else if err != nil {
2023-02-27 17:27:48 +00:00
return cid . Undef , false , xerrors . Errorf ( "error loading migration result: %w" , err )
}
c , err := cid . Parse ( bs )
if err != nil {
return cid . Undef , false , xerrors . Errorf ( "error parsing migration result: %w" , err )
}
return c , true , nil
}
2023-03-07 19:35:40 +00:00
func ( m * migrationResultCache ) Store ( ctx context . Context , root cid . Cid , resultCid cid . Cid ) error {
k := m . keyForMigration ( root )
2023-02-27 17:27:48 +00:00
if err := m . ds . Put ( ctx , k , resultCid . Bytes ( ) ) ; err != nil {
return err
}
return nil
2021-01-26 20:46:57 +00:00
}
2021-09-02 16:07:23 +00:00
type Executor interface {
NewActorRegistry ( ) * vm . ActorRegistry
2022-07-14 19:09:31 +00:00
ExecuteTipSet ( ctx context . Context , sm * StateManager , ts * types . TipSet , em ExecMonitor , vmTracing bool ) ( stateroot cid . Cid , rectsroot cid . Cid , err error )
2021-09-02 16:07:23 +00:00
}
2019-09-06 06:26:02 +00:00
type StateManager struct {
cs * store . ChainStore
2019-09-06 20:03:28 +00:00
2021-01-26 23:11:31 +00:00
cancel context . CancelFunc
shutdown chan struct { }
2021-01-26 20:46:57 +00:00
2020-10-03 00:09:56 +00:00
// Determines the network version at any given epoch.
networkVersions [ ] versionSpec
latestVersion network . Version
2021-01-26 20:46:57 +00:00
// Maps chain epochs to migrations.
stateMigrations map [ abi . ChainEpoch ] * migration
2020-10-07 23:14:11 +00:00
// A set of potentially expensive/time consuming upgrades. Explicit
// calls for, e.g., gas estimation fail against this epoch with
// ErrExpensiveFork.
expensiveUpgrades map [ abi . ChainEpoch ] struct { }
2020-10-01 22:02:40 +00:00
2020-11-13 08:25:29 +00:00
stCache map [ string ] [ ] cid . Cid
2021-05-31 22:12:42 +00:00
tCache treeCache
2020-11-13 08:25:29 +00:00
compWait map [ string ] chan struct { }
stlk sync . Mutex
genesisMsigLk sync . Mutex
2022-03-15 22:46:56 +00:00
newVM func ( context . Context , * vm . VMOpts ) ( vm . Interface , error )
2021-09-02 16:07:23 +00:00
Syscalls vm . SyscallBuilder
2020-11-13 08:25:29 +00:00
preIgnitionVesting [ ] msig0 . State
postIgnitionVesting [ ] msig0 . State
postCalicoVesting [ ] msig0 . State
2023-03-23 19:56:59 +00:00
genesisPledge abi . TokenAmount
2021-06-04 00:44:38 +00:00
2021-09-02 16:07:23 +00:00
tsExec Executor
2021-06-04 00:44:38 +00:00
tsExecMonitor ExecMonitor
2021-09-18 17:57:04 +00:00
beacon beacon . Schedule
2023-03-12 13:25:07 +00:00
msgIndex index . MsgIndex
2023-03-20 15:17:27 +00:00
// We keep a small cache for calls to ExecutionTrace which helps improve
// performance for node operators like exchanges and block explorers
2023-11-21 14:02:09 +00:00
execTraceCache * arc . ARCCache [ types . TipSetKey , tipSetCacheEntry ]
2023-03-25 12:07:37 +00:00
// We need a lock while making the copy as to prevent other callers
// overwrite the cache while making the copy
2023-03-23 13:14:49 +00:00
execTraceCacheLock sync . Mutex
2019-09-06 06:26:02 +00:00
}
2021-05-31 22:12:42 +00:00
// Caches a single state tree
type treeCache struct {
root cid . Cid
tree * state . StateTree
}
2023-03-20 15:17:27 +00:00
type tipSetCacheEntry struct {
2023-03-23 13:14:49 +00:00
postStateRoot cid . Cid
invocTrace [ ] * api . InvocResult
2023-03-20 15:17:27 +00:00
}
2023-03-12 13:25:07 +00:00
func NewStateManager ( cs * store . ChainStore , exec Executor , sys vm . SyscallBuilder , us UpgradeSchedule , beacon beacon . Schedule , metadataDs dstore . Batching , msgIndex index . MsgIndex ) ( * StateManager , error ) {
2020-10-03 00:09:56 +00:00
// If we have upgrades, make sure they're in-order and make sense.
if err := us . Validate ( ) ; err != nil {
return nil , err
}
2020-10-01 22:02:40 +00:00
2021-01-26 20:46:57 +00:00
stateMigrations := make ( map [ abi . ChainEpoch ] * migration , len ( us ) )
2020-10-07 23:14:11 +00:00
expensiveUpgrades := make ( map [ abi . ChainEpoch ] struct { } , len ( us ) )
2020-10-03 00:09:56 +00:00
var networkVersions [ ] versionSpec
2021-10-02 16:20:09 +00:00
lastVersion := build . GenesisNetworkVersion
2020-10-03 00:09:56 +00:00
if len ( us ) > 0 {
// If we have any upgrades, process them and create a version
// schedule.
for _ , upgrade := range us {
2021-01-26 23:15:14 +00:00
if upgrade . Migration != nil || upgrade . PreMigrations != nil {
2021-01-26 20:46:57 +00:00
migration := & migration {
upgrade : upgrade . Migration ,
2021-01-26 23:15:14 +00:00
preMigrations : upgrade . PreMigrations ,
2022-04-04 09:03:48 +00:00
cache : nv16 . NewMemMigrationCache ( ) ,
2023-03-07 19:35:40 +00:00
migrationResultCache : & migrationResultCache {
keyPrefix : fmt . Sprintf ( "/migration-cache/nv%d" , upgrade . Network ) ,
2023-02-27 17:27:48 +00:00
ds : metadataDs ,
} ,
2021-01-26 20:46:57 +00:00
}
2023-02-27 17:27:48 +00:00
2021-01-26 20:46:57 +00:00
stateMigrations [ upgrade . Height ] = migration
2020-10-03 00:09:56 +00:00
}
2020-10-07 23:14:11 +00:00
if upgrade . Expensive {
expensiveUpgrades [ upgrade . Height ] = struct { } { }
}
2023-02-27 17:27:48 +00:00
2020-10-03 00:09:56 +00:00
networkVersions = append ( networkVersions , versionSpec {
networkVersion : lastVersion ,
atOrBelow : upgrade . Height ,
} )
lastVersion = upgrade . Network
2020-10-01 22:02:40 +00:00
}
}
2023-05-04 17:10:26 +00:00
log . Debugf ( "execTraceCache size: %d" , execTraceCacheSize )
2023-11-21 14:02:09 +00:00
var execTraceCache * arc . ARCCache [ types . TipSetKey , tipSetCacheEntry ]
2023-03-29 09:38:26 +00:00
var err error
2023-05-04 17:10:26 +00:00
if execTraceCacheSize > 0 {
2023-11-21 14:02:09 +00:00
execTraceCache , err = arc . NewARC [ types . TipSetKey , tipSetCacheEntry ] ( execTraceCacheSize )
2023-03-29 09:38:26 +00:00
if err != nil {
return nil , err
}
2023-03-20 15:17:27 +00:00
}
2019-09-06 20:03:28 +00:00
return & StateManager {
2020-10-07 23:14:11 +00:00
networkVersions : networkVersions ,
latestVersion : lastVersion ,
stateMigrations : stateMigrations ,
expensiveUpgrades : expensiveUpgrades ,
2022-02-23 03:43:14 +00:00
newVM : vm . NewVM ,
2021-09-02 16:07:23 +00:00
Syscalls : sys ,
2020-10-07 23:14:11 +00:00
cs : cs ,
2021-09-02 16:07:23 +00:00
tsExec : exec ,
2020-10-07 23:14:11 +00:00
stCache : make ( map [ string ] [ ] cid . Cid ) ,
2021-09-18 17:57:04 +00:00
beacon : beacon ,
2021-05-31 22:12:42 +00:00
tCache : treeCache {
root : cid . Undef ,
tree : nil ,
} ,
2023-03-20 15:17:27 +00:00
compWait : make ( map [ string ] chan struct { } ) ,
msgIndex : msgIndex ,
execTraceCache : execTraceCache ,
2020-10-03 00:09:56 +00:00
} , nil
2019-09-06 20:03:28 +00:00
}
2023-03-12 13:25:07 +00:00
func NewStateManagerWithUpgradeScheduleAndMonitor ( cs * store . ChainStore , exec Executor , sys vm . SyscallBuilder , us UpgradeSchedule , b beacon . Schedule , em ExecMonitor , metadataDs dstore . Batching , msgIndex index . MsgIndex ) ( * StateManager , error ) {
sm , err := NewStateManager ( cs , exec , sys , us , b , metadataDs , msgIndex )
2021-06-04 00:44:38 +00:00
if err != nil {
return nil , err
}
sm . tsExecMonitor = em
return sm , nil
}
2019-09-06 20:03:28 +00:00
func cidsToKey ( cids [ ] cid . Cid ) string {
var out string
for _ , c := range cids {
out += c . KeyString ( )
}
return out
2019-09-06 06:26:02 +00:00
}
2021-01-26 20:46:57 +00:00
// Start starts the state manager's optional background processes. At the moment, this schedules
// pre-migration functions to run ahead of network upgrades.
//
2021-01-27 23:41:26 +00:00
// This method is not safe to invoke from multiple threads or concurrently with Stop.
2021-01-26 20:46:57 +00:00
func ( sm * StateManager ) Start ( context . Context ) error {
2021-01-26 23:11:31 +00:00
var ctx context . Context
ctx , sm . cancel = context . WithCancel ( context . Background ( ) )
sm . shutdown = make ( chan struct { } )
go sm . preMigrationWorker ( ctx )
2021-01-26 20:46:57 +00:00
return nil
}
// Stop starts the state manager's background processes.
//
2021-01-27 23:41:26 +00:00
// This method is not safe to invoke concurrently with Start.
2021-01-26 23:11:31 +00:00
func ( sm * StateManager ) Stop ( ctx context . Context ) error {
2021-01-26 20:46:57 +00:00
if sm . cancel != nil {
sm . cancel ( )
2021-01-26 23:11:31 +00:00
select {
case <- sm . shutdown :
case <- ctx . Done ( ) :
return ctx . Err ( )
}
2021-01-26 20:46:57 +00:00
}
return nil
}
2019-09-06 06:26:02 +00:00
func ( sm * StateManager ) ChainStore ( ) * store . ChainStore {
return sm . cs
}
2021-09-18 17:57:04 +00:00
func ( sm * StateManager ) Beacon ( ) beacon . Schedule {
return sm . beacon
}
2023-01-13 19:11:13 +00:00
// ResolveToDeterministicAddress is similar to `vm.ResolveToDeterministicAddr` but does not allow `Actor` type of addresses.
2020-06-02 14:29:39 +00:00
// Uses the `TipSet` `ts` to generate the VM state.
2023-01-13 19:11:13 +00:00
func ( sm * StateManager ) ResolveToDeterministicAddress ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( address . Address , error ) {
2019-10-09 02:58:49 +00:00
switch addr . Protocol ( ) {
2023-01-13 19:11:13 +00:00
case address . BLS , address . SECP256K1 , address . Delegated :
2019-10-09 02:58:49 +00:00
return addr , nil
case address . Actor :
return address . Undef , xerrors . New ( "cannot resolve actor address to key address" )
default :
}
if ts == nil {
ts = sm . cs . GetHeaviestTipSet ( )
}
2021-02-28 22:48:36 +00:00
cst := cbor . NewCborStore ( sm . cs . StateBlockstore ( ) )
2021-01-28 00:37:32 +00:00
// First try to resolve the actor in the parent state, so we don't have to compute anything.
tree , err := state . LoadStateTree ( cst , ts . ParentState ( ) )
if err != nil {
2021-07-29 00:50:22 +00:00
return address . Undef , xerrors . Errorf ( "failed to load parent state tree at tipset %s: %w" , ts . Parents ( ) , err )
2021-01-28 00:37:32 +00:00
}
2023-01-13 19:11:13 +00:00
resolved , err := vm . ResolveToDeterministicAddr ( tree , cst , addr )
2021-01-28 00:37:32 +00:00
if err == nil {
return resolved , nil
}
// If that fails, compute the tip-set and try again.
2019-10-10 11:13:26 +00:00
st , _ , err := sm . TipSetState ( ctx , ts )
2019-10-09 02:58:49 +00:00
if err != nil {
2021-07-29 00:50:22 +00:00
return address . Undef , xerrors . Errorf ( "resolve address failed to get tipset %s state: %w" , ts , err )
2019-10-09 02:58:49 +00:00
}
2021-01-28 00:37:32 +00:00
tree , err = state . LoadStateTree ( cst , st )
2019-10-09 02:58:49 +00:00
if err != nil {
2021-07-29 00:50:22 +00:00
return address . Undef , xerrors . Errorf ( "failed to load state tree at tipset %s: %w" , ts , err )
2019-10-09 02:58:49 +00:00
}
2023-01-13 19:11:13 +00:00
return vm . ResolveToDeterministicAddr ( tree , cst , addr )
2019-10-09 02:58:49 +00:00
}
2023-01-13 19:11:13 +00:00
// ResolveToDeterministicAddressAtFinality is similar to stmgr.ResolveToDeterministicAddress but fails if the ID address being resolved isn't reorg-stable yet.
2021-05-30 18:54:09 +00:00
// It should not be used for consensus-critical subsystems.
2023-01-13 19:11:13 +00:00
func ( sm * StateManager ) ResolveToDeterministicAddressAtFinality ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( address . Address , error ) {
2021-05-30 18:54:09 +00:00
switch addr . Protocol ( ) {
2023-01-13 19:11:13 +00:00
case address . BLS , address . SECP256K1 , address . Delegated :
2021-05-30 18:54:09 +00:00
return addr , nil
case address . Actor :
return address . Undef , xerrors . New ( "cannot resolve actor address to key address" )
default :
}
if ts == nil {
ts = sm . cs . GetHeaviestTipSet ( )
}
2021-05-31 22:12:42 +00:00
var err error
2021-05-30 18:54:09 +00:00
if ts . Height ( ) > policy . ChainFinality {
ts , err = sm . ChainStore ( ) . GetTipsetByHeight ( ctx , ts . Height ( ) - policy . ChainFinality , ts , true )
if err != nil {
return address . Undef , xerrors . Errorf ( "failed to load lookback tipset: %w" , err )
}
}
cst := cbor . NewCborStore ( sm . cs . StateBlockstore ( ) )
2021-05-31 22:12:42 +00:00
tree := sm . tCache . tree
2021-05-30 18:54:09 +00:00
2021-05-31 22:12:42 +00:00
if tree == nil || sm . tCache . root != ts . ParentState ( ) {
tree , err = state . LoadStateTree ( cst , ts . ParentState ( ) )
if err != nil {
return address . Undef , xerrors . Errorf ( "failed to load parent state tree: %w" , err )
}
sm . tCache = treeCache {
root : ts . ParentState ( ) ,
tree : tree ,
}
2021-05-30 18:54:09 +00:00
}
2023-01-13 19:11:13 +00:00
resolved , err := vm . ResolveToDeterministicAddr ( tree , cst , addr )
2021-05-30 18:54:09 +00:00
if err == nil {
return resolved , nil
}
return address . Undef , xerrors . New ( "ID address not found in lookback state" )
}
2020-07-26 01:38:18 +00:00
func ( sm * StateManager ) GetBlsPublicKey ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( pubk [ ] byte , err error ) {
2023-01-13 19:11:13 +00:00
kaddr , err := sm . ResolveToDeterministicAddress ( ctx , addr , ts )
2019-10-09 02:58:49 +00:00
if err != nil {
return pubk , xerrors . Errorf ( "failed to resolve address to key address: %w" , err )
}
if kaddr . Protocol ( ) != address . BLS {
return pubk , xerrors . Errorf ( "address must be BLS address to load bls public key" )
}
2020-07-26 01:38:18 +00:00
return kaddr . Payload ( ) , nil
2019-10-09 02:58:49 +00:00
}
2019-10-08 05:51:34 +00:00
2020-02-23 15:50:36 +00:00
func ( sm * StateManager ) LookupID ( ctx context . Context , addr address . Address , ts * types . TipSet ) ( address . Address , error ) {
2021-02-28 22:48:36 +00:00
cst := cbor . NewCborStore ( sm . cs . StateBlockstore ( ) )
2020-09-14 22:43:12 +00:00
state , err := state . LoadStateTree ( cst , sm . parentState ( ts ) )
2020-02-23 15:50:36 +00:00
if err != nil {
return address . Undef , xerrors . Errorf ( "load state tree: %w" , err )
}
return state . LookupID ( addr )
}
2022-04-14 21:30:07 +00:00
func ( sm * StateManager ) LookupRobustAddress ( ctx context . Context , idAddr address . Address , ts * types . TipSet ) ( address . Address , error ) {
idAddrDecoded , err := address . IDFromAddress ( idAddr )
if err != nil {
return address . Undef , xerrors . Errorf ( "failed to decode provided address as id addr: %w" , err )
}
cst := cbor . NewCborStore ( sm . cs . StateBlockstore ( ) )
wrapStore := adt . WrapStore ( ctx , cst )
stateTree , err := state . LoadStateTree ( cst , sm . parentState ( ts ) )
if err != nil {
return address . Undef , xerrors . Errorf ( "load state tree: %w" , err )
}
initActor , err := stateTree . GetActor ( _init . Address )
if err != nil {
return address . Undef , xerrors . Errorf ( "load init actor: %w" , err )
}
initState , err := _init . Load ( wrapStore , initActor )
if err != nil {
return address . Undef , xerrors . Errorf ( "load init state: %w" , err )
}
robustAddr := address . Undef
err = initState . ForEachActor ( func ( id abi . ActorID , addr address . Address ) error {
if uint64 ( id ) == idAddrDecoded {
robustAddr = addr
// Hacky way to early return from ForEach
return xerrors . New ( "robust address found" )
}
return nil
} )
if robustAddr == address . Undef {
if err == nil {
return address . Undef , xerrors . Errorf ( "Address %s not found" , idAddr . String ( ) )
}
return address . Undef , xerrors . Errorf ( "finding address: %w" , err )
}
return robustAddr , nil
}
2020-01-21 01:53:55 +00:00
func ( sm * StateManager ) ValidateChain ( ctx context . Context , ts * types . TipSet ) error {
tschain := [ ] * types . TipSet { ts }
for ts . Height ( ) != 0 {
2021-12-11 21:03:00 +00:00
next , err := sm . cs . LoadTipSet ( ctx , ts . Parents ( ) )
2020-01-21 01:53:55 +00:00
if err != nil {
return err
}
tschain = append ( tschain , next )
ts = next
}
lastState := tschain [ len ( tschain ) - 1 ] . ParentState ( )
for i := len ( tschain ) - 1 ; i >= 0 ; i -- {
cur := tschain [ i ]
log . Infof ( "computing state (height: %d, ts=%s)" , cur . Height ( ) , cur . Cids ( ) )
if cur . ParentState ( ) != lastState {
return xerrors . Errorf ( "tipset chain had state mismatch at height %d" , cur . Height ( ) )
}
st , _ , err := sm . TipSetState ( ctx , cur )
if err != nil {
return err
}
lastState = st
}
return nil
}
2020-01-31 23:51:15 +00:00
2022-03-15 22:46:56 +00:00
func ( sm * StateManager ) SetVMConstructor ( nvm func ( context . Context , * vm . VMOpts ) ( vm . Interface , error ) ) {
2020-01-31 23:51:15 +00:00
sm . newVM = nvm
}
2020-07-25 22:29:33 +00:00
2022-03-15 22:46:56 +00:00
func ( sm * StateManager ) VMConstructor ( ) func ( context . Context , * vm . VMOpts ) ( vm . Interface , error ) {
return func ( ctx context . Context , opts * vm . VMOpts ) ( vm . Interface , error ) {
2021-09-02 16:07:23 +00:00
return sm . newVM ( ctx , opts )
}
}
2021-12-17 23:43:39 +00:00
func ( sm * StateManager ) GetNetworkVersion ( ctx context . Context , height abi . ChainEpoch ) network . Version {
2020-10-01 22:33:32 +00:00
// The epochs here are the _last_ epoch for every version, or -1 if the
// version is disabled.
2020-10-03 00:09:56 +00:00
for _ , spec := range sm . networkVersions {
if height <= spec . atOrBelow {
return spec . networkVersion
2020-10-01 22:02:40 +00:00
}
2020-09-28 22:58:07 +00:00
}
2020-10-03 00:09:56 +00:00
return sm . latestVersion
2020-09-07 20:01:09 +00:00
}
2021-07-27 13:49:01 +00:00
func ( sm * StateManager ) VMSys ( ) vm . SyscallBuilder {
2021-09-02 16:07:23 +00:00
return sm . Syscalls
2021-07-27 13:49:01 +00:00
}
2021-09-18 17:57:04 +00:00
func ( sm * StateManager ) GetRandomnessFromBeacon ( ctx context . Context , personalization crypto . DomainSeparationTag , randEpoch abi . ChainEpoch , entropy [ ] byte , tsk types . TipSetKey ) ( abi . Randomness , error ) {
2021-12-11 21:03:00 +00:00
pts , err := sm . ChainStore ( ) . GetTipSetFromKey ( ctx , tsk )
2021-09-18 17:57:04 +00:00
if err != nil {
return nil , xerrors . Errorf ( "loading tipset %s: %w" , tsk , err )
}
2021-12-17 23:54:17 +00:00
r := rand . NewStateRand ( sm . ChainStore ( ) , pts . Cids ( ) , sm . beacon , sm . GetNetworkVersion )
2021-09-18 17:57:04 +00:00
2023-08-22 15:14:17 +00:00
digest , err := r . GetBeaconRandomness ( ctx , randEpoch )
if err != nil {
return nil , xerrors . Errorf ( "getting beacon randomness: %w" , err )
}
ret , err := rand . DrawRandomnessFromDigest ( digest , personalization , randEpoch , entropy )
if err != nil {
return nil , xerrors . Errorf ( "drawing beacon randomness: %w" , err )
}
return ret , nil
2021-09-18 17:57:04 +00:00
}
func ( sm * StateManager ) GetRandomnessFromTickets ( ctx context . Context , personalization crypto . DomainSeparationTag , randEpoch abi . ChainEpoch , entropy [ ] byte , tsk types . TipSetKey ) ( abi . Randomness , error ) {
2021-12-11 21:03:00 +00:00
pts , err := sm . ChainStore ( ) . LoadTipSet ( ctx , tsk )
2021-09-18 17:57:04 +00:00
if err != nil {
return nil , xerrors . Errorf ( "loading tipset key: %w" , err )
}
2021-12-17 23:54:17 +00:00
r := rand . NewStateRand ( sm . ChainStore ( ) , pts . Cids ( ) , sm . beacon , sm . GetNetworkVersion )
2021-09-18 17:57:04 +00:00
2023-08-22 15:14:17 +00:00
digest , err := r . GetChainRandomness ( ctx , randEpoch )
if err != nil {
return nil , xerrors . Errorf ( "getting chain randomness: %w" , err )
}
ret , err := rand . DrawRandomnessFromDigest ( digest , personalization , randEpoch , entropy )
if err != nil {
return nil , xerrors . Errorf ( "drawing chain randomness: %w" , err )
}
return ret , nil
2021-09-18 17:57:04 +00:00
}
2023-08-16 15:55:37 +00:00
func ( sm * StateManager ) GetRandomnessDigestFromBeacon ( ctx context . Context , randEpoch abi . ChainEpoch , tsk types . TipSetKey ) ( [ 32 ] byte , error ) {
pts , err := sm . ChainStore ( ) . GetTipSetFromKey ( ctx , tsk )
if err != nil {
return [ 32 ] byte { } , xerrors . Errorf ( "loading tipset %s: %w" , tsk , err )
}
r := rand . NewStateRand ( sm . ChainStore ( ) , pts . Cids ( ) , sm . beacon , sm . GetNetworkVersion )
return r . GetBeaconRandomness ( ctx , randEpoch )
}
func ( sm * StateManager ) GetRandomnessDigestFromTickets ( ctx context . Context , randEpoch abi . ChainEpoch , tsk types . TipSetKey ) ( [ 32 ] byte , error ) {
pts , err := sm . ChainStore ( ) . LoadTipSet ( ctx , tsk )
if err != nil {
return [ 32 ] byte { } , xerrors . Errorf ( "loading tipset key: %w" , err )
}
r := rand . NewStateRand ( sm . ChainStore ( ) , pts . Cids ( ) , sm . beacon , sm . GetNetworkVersion )
return r . GetChainRandomness ( ctx , randEpoch )
}