2020-03-19 15:52:37 +00:00
|
|
|
package native
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2020-04-20 17:38:47 +00:00
|
|
|
"fmt"
|
2020-03-19 15:52:37 +00:00
|
|
|
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
2020-05-07 11:03:14 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
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 {
|
2020-07-22 09:36:28 +00:00
|
|
|
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")
|
|
|
|
}
|
2020-04-20 17:38:47 +00:00
|
|
|
|
2020-04-22 20:00:18 +00:00
|
|
|
for _, native := range ic.Natives {
|
2020-05-07 11:03:14 +00:00
|
|
|
md := native.Metadata()
|
|
|
|
|
|
|
|
cs := &state.Contract{
|
2020-06-09 09:12:56 +00:00
|
|
|
ID: md.ContractID,
|
|
|
|
Script: md.Script,
|
|
|
|
Manifest: md.Manifest,
|
2020-05-07 11:03:14 +00:00
|
|
|
}
|
|
|
|
if err := ic.DAO.PutContractState(cs); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-04-22 20:00:18 +00:00
|
|
|
if err := native.Initialize(ic); err != nil {
|
2020-08-06 16:09:57 +00:00
|
|
|
return fmt.Errorf("initializing %s native contract: %w", md.Name, err)
|
2020-04-22 20:00:18 +00:00
|
|
|
}
|
2020-04-20 17:38:47 +00:00
|
|
|
}
|
2020-03-19 15:52:37 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-07-22 16:03:05 +00:00
|
|
|
|
|
|
|
// 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()
|
2020-07-22 16:03:05 +00:00
|
|
|
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()
|
2020-07-22 16:03:05 +00:00
|
|
|
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()
|
2020-07-22 16:03:05 +00:00
|
|
|
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) {
|
2020-07-22 16:03:05 +00:00
|
|
|
return errors.New("missing call flags")
|
|
|
|
}
|
2020-08-07 11:37:49 +00:00
|
|
|
if !ic.VM.AddGas(m.Price) {
|
2020-07-22 16:03:05 +00:00
|
|
|
return errors.New("gas limit exceeded")
|
|
|
|
}
|
|
|
|
result := m.Func(ic, args)
|
2020-08-07 11:37:49 +00:00
|
|
|
ic.VM.Estack().PushVal(result)
|
2020-07-22 16:03:05 +00:00
|
|
|
return nil
|
|
|
|
}
|