neoneo-go/pkg/core/native/interop.go

72 lines
1.8 KiB
Go
Raw Normal View History

2020-03-19 15:52:37 +00:00
package native
import (
"errors"
"fmt"
2020-03-19 15:52:37 +00:00
"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"
2020-03-19 15:52:37 +00:00
)
// Deploy deploys native contract.
2020-08-07 11:37:49 +00:00
func Deploy(ic *interop.Context) error {
if ic.Block == nil || ic.Block.Index != 0 {
2020-03-19 15:52:37 +00:00
return errors.New("native contracts can be deployed only at 0 block")
}
for _, native := range ic.Natives {
md := native.Metadata()
cs := &state.Contract{
2020-06-09 09:12:56 +00:00
ID: md.ContractID,
Script: md.Script,
Manifest: md.Manifest,
}
if err := ic.DAO.PutContractState(cs); err != nil {
return err
}
if err := native.Initialize(ic); err != nil {
return fmt.Errorf("initializing %s native contract: %w", md.Name, err)
}
}
2020-03-19 15:52:37 +00:00
return nil
}
// Call calls specified native contract method.
2020-08-07 11:37:49 +00:00
func Call(ic *interop.Context) error {
name := ic.VM.Estack().Pop().String()
var c interop.Contract
for _, ctr := range ic.Natives {
if ctr.Metadata().Name == name {
c = ctr
break
}
}
if c == nil {
return fmt.Errorf("native contract %s not found", name)
}
2020-08-07 11:37:49 +00:00
h := ic.VM.GetCurrentScriptHash()
if !h.Equals(c.Metadata().Hash) {
return errors.New("it is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used")
}
2020-08-07 11:37:49 +00:00
operation := ic.VM.Estack().Pop().String()
args := ic.VM.Estack().Pop().Array()
m, ok := c.Metadata().Methods[operation]
if !ok {
return fmt.Errorf("method %s not found", operation)
}
2020-08-07 11:37:49 +00:00
if !ic.VM.Context().GetCallFlags().Has(m.RequiredFlags) {
return errors.New("missing call flags")
}
2020-08-07 11:37:49 +00:00
if !ic.VM.AddGas(m.Price) {
return errors.New("gas limit exceeded")
}
ctx := ic.VM.Context()
result := m.Func(ic, args)
if m.MD.ReturnType != smartcontract.VoidType {
ctx.Estack().PushVal(result)
}
return nil
}