package callback import ( "errors" "fmt" "strings" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) // MethodCallback represents callback for contract method. type MethodCallback struct { contract *state.Contract method *manifest.Method } var _ Callback = (*MethodCallback)(nil) // ArgCount implements Callback interface. func (s *MethodCallback) ArgCount() int { return len(s.method.Parameters) } // LoadContext implements Callback interface. func (s *MethodCallback) LoadContext(v *vm.VM, args []stackitem.Item) { v.Estack().PushVal(args) v.Estack().PushVal(s.method.Name) v.Estack().PushVal(s.contract.Hash.BytesBE()) } // CreateFromMethod creates callback for a contract method. func CreateFromMethod(ic *interop.Context) error { rawHash := ic.VM.Estack().Pop().Bytes() h, err := util.Uint160DecodeBytesBE(rawHash) if err != nil { return err } cs, err := ic.GetContract(h) if err != nil { return fmt.Errorf("contract not found: %w", err) } method := string(ic.VM.Estack().Pop().Bytes()) if strings.HasPrefix(method, "_") { return errors.New("invalid method name") } currCs, err := ic.GetContract(ic.VM.GetCurrentScriptHash()) if err == nil && !currCs.Manifest.CanCall(h, &cs.Manifest, method) { return errors.New("method call is not allowed") } md := cs.Manifest.ABI.GetMethod(method) ic.VM.Estack().PushVal(stackitem.NewInterop(&MethodCallback{ contract: cs, method: md, })) return nil }