// stm: #unit package vm import ( "fmt" "io" "testing" cbor "github.com/ipfs/go-ipld-cbor" "github.com/stretchr/testify/assert" cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/network" runtime2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" ) type basicContract struct{} type basicParams struct { B byte } func (b *basicParams) MarshalCBOR(w io.Writer) error { _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(b.B))) return err } func (b *basicParams) UnmarshalCBOR(r io.Reader) error { maj, val, err := cbg.CborReadHeader(r) if err != nil { return err } if maj != cbg.MajUnsignedInt { return fmt.Errorf("bad cbor type") } b.B = byte(val) return nil } func init() { cbor.RegisterCborType(basicParams{}) } func (b basicContract) Exports() map[uint64]interface{} { return map[uint64]interface{}{ 0: b.InvokeSomething0, 1: b.BadParam, 2: nil, 3: nil, 4: nil, 5: nil, 6: nil, 7: nil, 8: nil, 9: nil, 10: b.InvokeSomething10, } } func (basicContract) InvokeSomething0(rt runtime2.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(exitcode.ExitCode(params.B), "params.B") return nil } func (basicContract) BadParam(rt runtime2.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(255, "bad params") return nil } func (basicContract) InvokeSomething10(rt runtime2.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(exitcode.ExitCode(params.B+10), "params.B") return nil } type basicRtMessage struct{} var _ runtime2.Message = (*basicRtMessage)(nil) func (*basicRtMessage) Caller() address.Address { a, err := address.NewIDAddress(0) if err != nil { panic(err) } return a } func (*basicRtMessage) Receiver() address.Address { a, err := address.NewIDAddress(1) if err != nil { panic(err) } return a } func (*basicRtMessage) ValueReceived() abi.TokenAmount { return big.NewInt(0) } func TestInvokerBasic(t *testing.T) { //stm: @INVOKER_TRANSFORM_001 inv := ActorRegistry{} code, err := inv.transform(basicContract{}) assert.NoError(t, err) { bParam, err := actors.SerializeParams(&basicParams{B: 1}) assert.NoError(t, err) _, aerr := code[0](&Runtime{Message: &basicRtMessage{}}, bParam) assert.Equal(t, exitcode.ExitCode(1), aerrors.RetCode(aerr), "return code should be 1") if aerrors.IsFatal(aerr) { t.Fatal("err should not be fatal") } } { bParam, err := actors.SerializeParams(&basicParams{B: 2}) assert.NoError(t, err) _, aerr := code[10](&Runtime{Message: &basicRtMessage{}}, bParam) assert.Equal(t, exitcode.ExitCode(12), aerrors.RetCode(aerr), "return code should be 12") if aerrors.IsFatal(aerr) { t.Fatal("err should not be fatal") } } { _, aerr := code[1](&Runtime{ vm: &LegacyVM{networkVersion: network.Version0}, Message: &basicRtMessage{}, }, []byte{99}) if aerrors.IsFatal(aerr) { t.Fatal("err should not be fatal") } assert.Equal(t, exitcode.ExitCode(1), aerrors.RetCode(aerr), "return code should be 1") } { _, aerr := code[1](&Runtime{ vm: &LegacyVM{networkVersion: network.Version7}, Message: &basicRtMessage{}, }, []byte{99}) if aerrors.IsFatal(aerr) { t.Fatal("err should not be fatal") } assert.Equal(t, exitcode.ErrSerialization, aerrors.RetCode(aerr), "return code should be %s", 1) } }