github.com/filecoin-project/specs-actors/v4@v4.0.2/support/vm/vm.go (about)

     1  package vm_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/filecoin-project/go-address"
     8  	"github.com/filecoin-project/go-state-types/abi"
     9  	"github.com/filecoin-project/go-state-types/big"
    10  	"github.com/filecoin-project/go-state-types/cbor"
    11  	"github.com/filecoin-project/go-state-types/exitcode"
    12  	"github.com/filecoin-project/go-state-types/network"
    13  	"github.com/filecoin-project/go-state-types/rt"
    14  	vm2 "github.com/filecoin-project/specs-actors/v2/support/vm"
    15  	"github.com/ipfs/go-cid"
    16  	"github.com/pkg/errors"
    17  
    18  	"github.com/filecoin-project/specs-actors/v4/actors/builtin"
    19  	init_ "github.com/filecoin-project/specs-actors/v4/actors/builtin/init"
    20  	"github.com/filecoin-project/specs-actors/v4/actors/runtime"
    21  	"github.com/filecoin-project/specs-actors/v4/actors/states"
    22  	"github.com/filecoin-project/specs-actors/v4/actors/util/adt"
    23  )
    24  
    25  // VM is a simplified message execution framework for the purposes of testing inter-actor communication.
    26  // The VM maintains actor state and can be used to simulate message validation for a single block or tipset.
    27  // The VM does not track gas charges, provide working syscalls, validate message nonces and many other things
    28  // that a compliant VM needs to do.
    29  type VM struct {
    30  	ctx   context.Context
    31  	store adt.Store
    32  
    33  	currentEpoch   abi.ChainEpoch
    34  	networkVersion network.Version
    35  
    36  	ActorImpls  ActorImplLookup
    37  	stateRoot   cid.Cid  // The last committed root.
    38  	actors      *adt.Map // The current (not necessarily committed) root node.
    39  	actorsDirty bool
    40  
    41  	emptyObject  cid.Cid
    42  	callSequence uint64
    43  
    44  	logs            []string
    45  	invocationStack []*Invocation
    46  	invocations     []*Invocation
    47  
    48  	statsSource   StatsSource
    49  	statsByMethod StatsByCall
    50  
    51  	circSupply abi.TokenAmount
    52  }
    53  
    54  // VM types
    55  
    56  // type ActorImplLookup map[cid.Cid]runtime.VMActor
    57  type ActorImplLookup vm2.ActorImplLookup
    58  
    59  type InternalMessage struct {
    60  	from   address.Address
    61  	to     address.Address
    62  	value  abi.TokenAmount
    63  	method abi.MethodNum
    64  	params interface{}
    65  }
    66  
    67  type Invocation struct {
    68  	Msg            *InternalMessage
    69  	Exitcode       exitcode.ExitCode
    70  	Ret            cbor.Marshaler
    71  	SubInvocations []*Invocation
    72  }
    73  
    74  // NewVM creates a new runtime for executing messages.
    75  func NewVM(ctx context.Context, actorImpls ActorImplLookup, store adt.Store) *VM {
    76  	actors, err := adt.MakeEmptyMap(store, builtin.DefaultHamtBitwidth)
    77  	if err != nil {
    78  		panic(err)
    79  	}
    80  	actorRoot, err := actors.Root()
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  
    85  	emptyObject, err := store.Put(context.TODO(), []struct{}{})
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  
    90  	return &VM{
    91  		ctx:            ctx,
    92  		ActorImpls:     actorImpls,
    93  		store:          store,
    94  		actors:         actors,
    95  		stateRoot:      actorRoot,
    96  		actorsDirty:    false,
    97  		emptyObject:    emptyObject,
    98  		networkVersion: network.VersionMax,
    99  		statsByMethod:  make(StatsByCall),
   100  		circSupply:     big.Mul(big.NewInt(1e9), big.NewInt(1e18)),
   101  	}
   102  }
   103  
   104  // NewVM creates a new runtime for executing messages.
   105  func NewVMAtEpoch(ctx context.Context, actorImpls ActorImplLookup, store adt.Store, stateRoot cid.Cid, epoch abi.ChainEpoch) (*VM, error) {
   106  	actors, err := adt.AsMap(store, stateRoot, builtin.DefaultHamtBitwidth)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	emptyObject, err := store.Put(context.TODO(), []struct{}{})
   112  	if err != nil {
   113  		panic(err)
   114  	}
   115  
   116  	return &VM{
   117  		ctx:            ctx,
   118  		ActorImpls:     actorImpls,
   119  		currentEpoch:   epoch,
   120  		store:          store,
   121  		actors:         actors,
   122  		stateRoot:      stateRoot,
   123  		actorsDirty:    false,
   124  		emptyObject:    emptyObject,
   125  		networkVersion: network.VersionMax,
   126  		statsByMethod:  make(StatsByCall),
   127  		circSupply:     big.Mul(big.NewInt(1e9), big.NewInt(1e18)),
   128  	}, nil
   129  }
   130  
   131  func (vm *VM) WithEpoch(epoch abi.ChainEpoch) (*VM, error) {
   132  	_, err := vm.checkpoint()
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	actors, err := adt.AsMap(vm.store, vm.stateRoot, builtin.DefaultHamtBitwidth)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	return &VM{
   143  		ctx:            vm.ctx,
   144  		ActorImpls:     vm.ActorImpls,
   145  		store:          vm.store,
   146  		actors:         actors,
   147  		stateRoot:      vm.stateRoot,
   148  		actorsDirty:    false,
   149  		emptyObject:    vm.emptyObject,
   150  		currentEpoch:   epoch,
   151  		networkVersion: vm.networkVersion,
   152  		statsSource:    vm.statsSource,
   153  		statsByMethod:  make(StatsByCall),
   154  		circSupply:     vm.circSupply,
   155  	}, nil
   156  }
   157  
   158  func (vm *VM) WithNetworkVersion(nv network.Version) (*VM, error) {
   159  	_, err := vm.checkpoint()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	actors, err := adt.AsMap(vm.store, vm.stateRoot, builtin.DefaultHamtBitwidth)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	return &VM{
   170  		ctx:            vm.ctx,
   171  		ActorImpls:     vm.ActorImpls,
   172  		store:          vm.store,
   173  		actors:         actors,
   174  		stateRoot:      vm.stateRoot,
   175  		actorsDirty:    false,
   176  		emptyObject:    vm.emptyObject,
   177  		currentEpoch:   vm.currentEpoch,
   178  		networkVersion: nv,
   179  		statsSource:    vm.statsSource,
   180  		statsByMethod:  make(StatsByCall),
   181  		circSupply:     vm.circSupply,
   182  	}, nil
   183  }
   184  
   185  func (vm *VM) rollback(root cid.Cid) error {
   186  	var err error
   187  	vm.actors, err = adt.AsMap(vm.store, root, builtin.DefaultHamtBitwidth)
   188  	if err != nil {
   189  		return errors.Wrapf(err, "failed to load node for %s", root)
   190  	}
   191  
   192  	// reset the root node
   193  	vm.stateRoot = root
   194  	vm.actorsDirty = false
   195  	return nil
   196  }
   197  
   198  func (vm *VM) GetActor(a address.Address) (*states.Actor, bool, error) {
   199  	na, found := vm.NormalizeAddress(a)
   200  	if !found {
   201  		return nil, false, nil
   202  	}
   203  	var act states.Actor
   204  	found, err := vm.actors.Get(abi.AddrKey(na), &act)
   205  	return &act, found, err
   206  }
   207  
   208  // SetActor sets the the actor to the given value whether it previously existed or not.
   209  //
   210  // This method will not check if the actor previously existed, it will blindly overwrite it.
   211  func (vm *VM) setActor(_ context.Context, key address.Address, a *states.Actor) error {
   212  	if err := vm.actors.Put(abi.AddrKey(key), a); err != nil {
   213  		return errors.Wrap(err, "setting actor in state tree failed")
   214  	}
   215  	vm.actorsDirty = true
   216  	return nil
   217  }
   218  
   219  // SetActorState stores the state and updates the addressed actor
   220  func (vm *VM) SetActorState(ctx context.Context, key address.Address, state cbor.Marshaler) error {
   221  	stateCid, err := vm.store.Put(ctx, state)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	a, found, err := vm.GetActor(key)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	if !found {
   230  		return errors.Errorf("could not find actor %s to set state", key)
   231  	}
   232  	a.Head = stateCid
   233  	return vm.setActor(ctx, key, a)
   234  }
   235  
   236  // deleteActor remove the actor from the storage.
   237  //
   238  // This method will NOT return an error if the actor was not found.
   239  // This behaviour is based on a principle that some store implementations might not be able to determine
   240  // whether something exists before deleting it.
   241  func (vm *VM) deleteActor(_ context.Context, key address.Address) error {
   242  	found, err := vm.actors.TryDelete(abi.AddrKey(key))
   243  	vm.actorsDirty = found
   244  	return err
   245  }
   246  
   247  func (vm *VM) checkpoint() (cid.Cid, error) {
   248  	// commit the vm state
   249  	root, err := vm.actors.Root()
   250  	if err != nil {
   251  		return cid.Undef, err
   252  	}
   253  	vm.stateRoot = root
   254  	vm.actorsDirty = false
   255  
   256  	return root, nil
   257  }
   258  
   259  func (vm *VM) NormalizeAddress(addr address.Address) (address.Address, bool) {
   260  	// short-circuit if the address is already an ID address
   261  	if addr.Protocol() == address.ID {
   262  		return addr, true
   263  	}
   264  
   265  	// resolve the target address via the InitActor, and attempt to load state.
   266  	initActorEntry, found, err := vm.GetActor(builtin.InitActorAddr)
   267  	if err != nil {
   268  		panic(errors.Wrapf(err, "failed to load init actor"))
   269  	}
   270  	if !found {
   271  		panic(errors.Wrapf(err, "no init actor"))
   272  	}
   273  
   274  	// get a view into the actor state
   275  	var state init_.State
   276  	if err := vm.store.Get(vm.ctx, initActorEntry.Head, &state); err != nil {
   277  		panic(err)
   278  	}
   279  
   280  	idAddr, found, err := state.ResolveAddress(vm.store, addr)
   281  	if err != nil {
   282  		panic(err)
   283  	}
   284  	return idAddr, found
   285  }
   286  
   287  // ApplyMessage applies the message to the current state.
   288  func (vm *VM) ApplyMessage(from, to address.Address, value abi.TokenAmount, method abi.MethodNum, params interface{}) (cbor.Marshaler, exitcode.ExitCode) {
   289  	// This method does not actually execute the message itself,
   290  	// but rather deals with the pre/post processing of a message.
   291  	// (see: `invocationContext.invoke()` for the dispatch and execution)
   292  
   293  	// load actor from global state
   294  	fromID, ok := vm.NormalizeAddress(from)
   295  	if !ok {
   296  		return nil, exitcode.SysErrSenderInvalid
   297  	}
   298  
   299  	fromActor, found, err := vm.GetActor(fromID)
   300  	if err != nil {
   301  		panic(err)
   302  	}
   303  	if !found {
   304  		// Execution error; sender does not exist at time of message execution.
   305  		return nil, exitcode.SysErrSenderInvalid
   306  	}
   307  
   308  	// checkpoint state
   309  	// Even if the message fails, the following accumulated changes will be applied:
   310  	// - CallSeqNumber increment
   311  	// - sender balance withheld
   312  	priorRoot, err := vm.checkpoint()
   313  	if err != nil {
   314  		panic(err)
   315  	}
   316  
   317  	// send
   318  	// 1. build internal message
   319  	// 2. build invocation context
   320  	// 3. process the msg
   321  
   322  	topLevel := topLevelContext{
   323  		originatorStableAddress: from,
   324  		// this should be nonce, but we only care that it creates a unique stable address
   325  		originatorCallSeq:    vm.callSequence,
   326  		newActorAddressCount: 0,
   327  		statsSource:          vm.statsSource,
   328  		circSupply:           vm.circSupply,
   329  	}
   330  	vm.callSequence++
   331  
   332  	// build internal msg
   333  	imsg := InternalMessage{
   334  		from:   fromID,
   335  		to:     to,
   336  		value:  value,
   337  		method: method,
   338  		params: params,
   339  	}
   340  
   341  	// build invocation context
   342  	ctx := newInvocationContext(vm, &topLevel, imsg, fromActor, vm.emptyObject)
   343  
   344  	// 3. invoke
   345  	ret, exitCode := ctx.invoke()
   346  
   347  	// record stats
   348  	vm.statsByMethod.MergeStats(ctx.toActor.Code, imsg.method, ctx.stats)
   349  
   350  	// Roll back all state if the receipt's exit code is not ok.
   351  	// This is required in addition to rollback within the invocation context since top level messages can fail for
   352  	// more reasons than internal ones. Invocation context still needs its own rollback so actors can recover and
   353  	// proceed from a nested call failure.
   354  	if exitCode != exitcode.Ok {
   355  		if err := vm.rollback(priorRoot); err != nil {
   356  			panic(err)
   357  		}
   358  	} else {
   359  		// persist changes from final invocation if call is ok
   360  		if _, err := vm.checkpoint(); err != nil {
   361  			panic(err)
   362  		}
   363  
   364  	}
   365  
   366  	return ret.inner, exitCode
   367  }
   368  
   369  func (vm *VM) StateRoot() cid.Cid {
   370  	return vm.stateRoot
   371  }
   372  
   373  func (vm *VM) GetState(addr address.Address, out cbor.Unmarshaler) error {
   374  	act, found, err := vm.GetActor(addr)
   375  	if err != nil {
   376  		return err
   377  	}
   378  	if !found {
   379  		return errors.Errorf("actor %v not found", addr)
   380  	}
   381  	return vm.store.Get(vm.ctx, act.Head, out)
   382  }
   383  
   384  func (vm *VM) GetStateTree() (*states.Tree, error) {
   385  	root, err := vm.checkpoint()
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	return states.LoadTree(vm.store, root)
   391  }
   392  
   393  func (vm *VM) GetTotalActorBalance() (abi.TokenAmount, error) {
   394  	tree, err := vm.GetStateTree()
   395  	if err != nil {
   396  		return big.Zero(), err
   397  	}
   398  	total := big.Zero()
   399  	err = tree.ForEach(func(_ address.Address, actor *states.Actor) error {
   400  		total = big.Add(total, actor.Balance)
   401  		return nil
   402  	})
   403  	if err != nil {
   404  		return big.Zero(), err
   405  	}
   406  	return total, nil
   407  }
   408  
   409  func (vm *VM) Store() adt.Store {
   410  	return vm.store
   411  }
   412  
   413  // Get the chain epoch for this vm
   414  func (vm *VM) GetEpoch() abi.ChainEpoch {
   415  	return vm.currentEpoch
   416  }
   417  
   418  // Get call stats
   419  func (vm *VM) GetCallStats() map[MethodKey]*CallStats {
   420  	return vm.statsByMethod
   421  }
   422  
   423  // Set the FIL circulating supply passed to actors through runtime
   424  func (vm *VM) SetCirculatingSupply(supply abi.TokenAmount) {
   425  	vm.circSupply = supply
   426  }
   427  
   428  // Set the FIL circulating supply passed to actors through runtime
   429  func (vm *VM) GetCirculatingSupply() abi.TokenAmount {
   430  	return vm.circSupply
   431  }
   432  
   433  func (vm *VM) GetActorImpls() map[cid.Cid]rt.VMActor {
   434  	return vm.ActorImpls
   435  }
   436  
   437  // transfer debits money from one account and credits it to another.
   438  // avoid calling this method with a zero amount else it will perform unnecessary actor loading.
   439  //
   440  // WARNING: this method will panic if the the amount is negative, accounts dont exist, or have inssuficient funds.
   441  //
   442  // Note: this is not idiomatic, it follows the Spec expectations for this method.
   443  func (vm *VM) transfer(debitFrom address.Address, creditTo address.Address, amount abi.TokenAmount) (*states.Actor, *states.Actor) {
   444  	// allow only for positive amounts
   445  	if amount.LessThan(abi.NewTokenAmount(0)) {
   446  		panic("unreachable: negative funds transfer not allowed")
   447  	}
   448  
   449  	ctx := context.Background()
   450  
   451  	// retrieve debit account
   452  	fromActor, found, err := vm.GetActor(debitFrom)
   453  	if err != nil {
   454  		panic(err)
   455  	}
   456  	if !found {
   457  		panic(fmt.Errorf("unreachable: debit account not found. %s", err))
   458  	}
   459  
   460  	// check that account has enough balance for transfer
   461  	if fromActor.Balance.LessThan(amount) {
   462  		panic("unreachable: insufficient balance on debit account")
   463  	}
   464  
   465  	// debit funds
   466  	fromActor.Balance = big.Sub(fromActor.Balance, amount)
   467  	if err := vm.setActor(ctx, debitFrom, fromActor); err != nil {
   468  		panic(err)
   469  	}
   470  
   471  	// retrieve credit account
   472  	toActor, found, err := vm.GetActor(creditTo)
   473  	if err != nil {
   474  		panic(err)
   475  	}
   476  	if !found {
   477  		panic(fmt.Errorf("unreachable: credit account not found. %s", err))
   478  	}
   479  
   480  	// credit funds
   481  	toActor.Balance = big.Add(toActor.Balance, amount)
   482  	if err := vm.setActor(ctx, creditTo, toActor); err != nil {
   483  		panic(err)
   484  	}
   485  	return toActor, fromActor
   486  }
   487  
   488  func (vm *VM) getActorImpl(code cid.Cid) runtime.VMActor {
   489  	actorImpl, ok := vm.ActorImpls[code]
   490  	if !ok {
   491  		vm.Abortf(exitcode.SysErrInvalidReceiver, "actor implementation not found for Exitcode %v", code)
   492  	}
   493  	return actorImpl
   494  }
   495  
   496  //
   497  // stats
   498  //
   499  
   500  func (vm *VM) SetStatsSource(s StatsSource) {
   501  	vm.statsSource = s
   502  }
   503  
   504  func (vm *VM) GetStatsSource() StatsSource {
   505  	return vm.statsSource
   506  }
   507  
   508  func (vm *VM) StoreReads() uint64 {
   509  	if vm.statsSource != nil {
   510  		return vm.statsSource.ReadCount()
   511  	}
   512  	return 0
   513  }
   514  
   515  func (vm *VM) StoreWrites() uint64 {
   516  	if vm.statsSource != nil {
   517  		return vm.statsSource.WriteCount()
   518  	}
   519  	return 0
   520  }
   521  
   522  func (vm *VM) StoreReadBytes() uint64 {
   523  	if vm.statsSource != nil {
   524  		return vm.statsSource.ReadSize()
   525  	}
   526  	return 0
   527  }
   528  
   529  func (vm *VM) StoreWriteBytes() uint64 {
   530  	if vm.statsSource != nil {
   531  		return vm.statsSource.WriteSize()
   532  	}
   533  	return 0
   534  }
   535  
   536  //
   537  // invocation tracking
   538  //
   539  
   540  func (vm *VM) startInvocation(msg *InternalMessage) {
   541  	invocation := Invocation{Msg: msg}
   542  	if len(vm.invocationStack) > 0 {
   543  		parent := vm.invocationStack[len(vm.invocationStack)-1]
   544  		parent.SubInvocations = append(parent.SubInvocations, &invocation)
   545  	} else {
   546  		vm.invocations = append(vm.invocations, &invocation)
   547  	}
   548  	vm.invocationStack = append(vm.invocationStack, &invocation)
   549  }
   550  
   551  func (vm *VM) endInvocation(code exitcode.ExitCode, ret cbor.Marshaler) {
   552  	curIndex := len(vm.invocationStack) - 1
   553  	current := vm.invocationStack[curIndex]
   554  	current.Exitcode = code
   555  	current.Ret = ret
   556  
   557  	vm.invocationStack = vm.invocationStack[:curIndex]
   558  }
   559  
   560  func (vm *VM) Invocations() []*Invocation {
   561  	return vm.invocations
   562  }
   563  
   564  func (vm *VM) LastInvocation() *Invocation {
   565  	return vm.invocations[len(vm.invocations)-1]
   566  }
   567  
   568  //
   569  // implement runtime.Runtime for VM
   570  //
   571  
   572  func (vm *VM) Log(_ rt.LogLevel, msg string, args ...interface{}) {
   573  	vm.logs = append(vm.logs, fmt.Sprintf(msg, args...))
   574  }
   575  
   576  func (vm *VM) GetLogs() []string {
   577  	return vm.logs
   578  }
   579  
   580  type abort struct {
   581  	code exitcode.ExitCode
   582  	msg  string
   583  }
   584  
   585  func (vm *VM) Abortf(errExitCode exitcode.ExitCode, msg string, args ...interface{}) {
   586  	panic(abort{errExitCode, fmt.Sprintf(msg, args...)})
   587  }
   588  
   589  //
   590  // implement runtime.MessageInfo for InternalMessage
   591  //
   592  
   593  var _ runtime.Message = (*InternalMessage)(nil)
   594  
   595  // ValueReceived implements runtime.MessageInfo.
   596  func (msg InternalMessage) ValueReceived() abi.TokenAmount {
   597  	return msg.value
   598  }
   599  
   600  // Caller implements runtime.MessageInfo.
   601  func (msg InternalMessage) Caller() address.Address {
   602  	return msg.from
   603  }
   604  
   605  // Receiver implements runtime.MessageInfo.
   606  func (msg InternalMessage) Receiver() address.Address {
   607  	return msg.to
   608  }