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 }