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

     1  package mock
     2  
     3  import (
     4  	"io"
     5  	"testing"
     6  
     7  	"github.com/filecoin-project/go-state-types/abi"
     8  	"github.com/filecoin-project/go-state-types/cbor"
     9  	"github.com/filecoin-project/go-state-types/exitcode"
    10  	"github.com/ipfs/go-cid"
    11  	mh "github.com/multiformats/go-multihash"
    12  	cbg "github.com/whyrusleeping/cbor-gen"
    13  
    14  	"github.com/filecoin-project/specs-actors/v4/actors/builtin"
    15  	"github.com/filecoin-project/specs-actors/v4/actors/runtime"
    16  	tutil "github.com/filecoin-project/specs-actors/v4/support/testing"
    17  )
    18  
    19  type FakeActor struct{}
    20  
    21  func (a FakeActor) Exports() []interface{} {
    22  	return []interface{}{
    23  		1: a.Constructor,
    24  		2: a.ReadOnlyState,
    25  		3: a.TransactionState,
    26  		4: a.TransactionStateTwice,
    27  	}
    28  }
    29  
    30  func (a FakeActor) Code() cid.Cid {
    31  	builder := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY}
    32  	c, err := builder.Sum([]byte("fake"))
    33  	if err != nil {
    34  		panic(err)
    35  	}
    36  	return c
    37  }
    38  
    39  func (a FakeActor) State() cbor.Er {
    40  	return new(State)
    41  }
    42  
    43  type State struct {
    44  	Value int64
    45  }
    46  
    47  func (s State) MarshalCBOR(w io.Writer) error {
    48  	cint := cbg.CborInt(s.Value)
    49  	return cint.MarshalCBOR(w)
    50  }
    51  
    52  func (s State) UnmarshalCBOR(r io.Reader) error {
    53  	var cint cbg.CborInt
    54  	err := cint.UnmarshalCBOR(r)
    55  	s.Value = int64(cint)
    56  	return err
    57  }
    58  
    59  var _ runtime.VMActor = FakeActor{}
    60  
    61  func (a FakeActor) Constructor(rt runtime.Runtime, mutate *cbg.CborBool) *abi.EmptyValue {
    62  	st := State{Value: 0}
    63  	rt.StateCreate(&st)
    64  	if *mutate {
    65  		st.Value = 1
    66  	}
    67  	return nil
    68  }
    69  
    70  func (a FakeActor) ReadOnlyState(rt runtime.Runtime, mutate *cbg.CborBool) *abi.EmptyValue {
    71  	rt.ValidateImmediateCallerAcceptAny()
    72  	var st State
    73  	rt.StateReadonly(&st)
    74  	if *mutate {
    75  		// Illegal mutation of read-only state
    76  		st.Value = st.Value + 1
    77  	}
    78  	return nil
    79  }
    80  
    81  func (a FakeActor) TransactionState(rt runtime.Runtime, mutate *cbg.CborBool) *abi.EmptyValue {
    82  	rt.ValidateImmediateCallerAcceptAny()
    83  	var st State
    84  	rt.StateTransaction(&st, func() {
    85  		st.Value = st.Value + 1
    86  	})
    87  	if *mutate {
    88  		// Illegal mutation of state outside transaction.
    89  		st.Value = st.Value + 1
    90  	}
    91  	return nil
    92  }
    93  
    94  func (a FakeActor) TransactionStateTwice(rt runtime.Runtime, mutate *cbg.CborBool) *abi.EmptyValue {
    95  	rt.ValidateImmediateCallerAcceptAny()
    96  	var st State
    97  	rt.StateTransaction(&st, func() {
    98  		st.Value = st.Value + 1
    99  	})
   100  	if *mutate {
   101  		// Illegal mutation of state outside transaction.
   102  		st.Value = st.Value + 1
   103  	}
   104  	rt.StateTransaction(&st, func() {
   105  		if *mutate {
   106  			panic("Can't get here")
   107  		}
   108  	})
   109  	return nil
   110  }
   111  
   112  func TestIllegalStateModifications(t *testing.T) {
   113  	actor := FakeActor{}
   114  	receiver := tutil.NewIDAddr(t, 100)
   115  	builder := NewBuilder(receiver).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID)
   116  
   117  	t.Run("construction", func(t *testing.T) {
   118  		rt := builder.Build(t)
   119  		mutate := cbg.CborBool(false)
   120  		rt.Call(actor.Constructor, &mutate)
   121  	})
   122  
   123  	t.Run("mutation after construction forbidden", func(t *testing.T) {
   124  		rt := builder.Build(t)
   125  		mutate := cbg.CborBool(true)
   126  		rt.ExpectAbort(exitcode.SysErrorIllegalActor, func() {
   127  			rt.Call(actor.Constructor, &mutate)
   128  		})
   129  	})
   130  
   131  	t.Run("readonly", func(t *testing.T) {
   132  		rt := builder.Build(t)
   133  		mutate := cbg.CborBool(false)
   134  		rt.Call(actor.Constructor, &mutate)
   135  
   136  		rt.ExpectValidateCallerAny()
   137  		rt.Call(actor.ReadOnlyState, &mutate)
   138  
   139  		mutate = true
   140  		rt.ExpectValidateCallerAny()
   141  		rt.ExpectAbort(exitcode.SysErrorIllegalActor, func() {
   142  			rt.Call(actor.ReadOnlyState, &mutate)
   143  		})
   144  	})
   145  
   146  	t.Run("transaction", func(t *testing.T) {
   147  		rt := builder.Build(t)
   148  		mutate := cbg.CborBool(false)
   149  		rt.Call(actor.Constructor, &mutate)
   150  
   151  		rt.ExpectValidateCallerAny()
   152  		rt.Call(actor.TransactionState, &mutate)
   153  
   154  		mutate = true
   155  		rt.ExpectValidateCallerAny()
   156  		rt.ExpectAbort(exitcode.SysErrorIllegalActor, func() {
   157  			rt.Call(actor.TransactionState, &mutate)
   158  		})
   159  	})
   160  
   161  	t.Run("transaction twice", func(t *testing.T) {
   162  		rt := builder.Build(t)
   163  		mutate := cbg.CborBool(false)
   164  		rt.Call(actor.Constructor, &mutate)
   165  
   166  		rt.ExpectValidateCallerAny()
   167  		rt.Call(actor.TransactionStateTwice, &mutate)
   168  
   169  		mutate = true
   170  		rt.ExpectValidateCallerAny()
   171  		rt.ExpectAbort(exitcode.SysErrorIllegalActor, func() {
   172  			rt.Call(actor.TransactionStateTwice, &mutate)
   173  		})
   174  	})
   175  }