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
|
|
|
|
2022-12-16 20:36:45 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
2020-03-19 15:52:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
2020-09-21 14:34:40 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
2022-12-16 20:36:45 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
2020-12-13 18:36:06 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
2020-12-29 10:44:07 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2020-03-19 15:52:37 +00:00
|
|
|
)
|
|
|
|
|
2022-04-20 18:30:09 +00:00
|
|
|
// Call calls the specified native contract method.
|
2020-08-07 11:37:49 +00:00
|
|
|
func Call(ic *interop.Context) error {
|
2021-02-15 13:40:44 +00:00
|
|
|
version := ic.VM.Estack().Pop().BigInt().Int64()
|
|
|
|
if version != 0 {
|
|
|
|
return fmt.Errorf("native contract of version %d is not active", version)
|
|
|
|
}
|
2023-11-21 09:35:18 +00:00
|
|
|
var (
|
|
|
|
c interop.Contract
|
|
|
|
curr = ic.VM.GetCurrentScriptHash()
|
|
|
|
)
|
2020-07-22 16:03:05 +00:00
|
|
|
for _, ctr := range ic.Natives {
|
2023-11-21 09:35:18 +00:00
|
|
|
if ctr.Metadata().Hash == curr {
|
|
|
|
c = ctr
|
2020-07-22 16:03:05 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2023-11-21 09:35:18 +00:00
|
|
|
if c == nil {
|
2022-03-23 16:52:59 +00:00
|
|
|
return fmt.Errorf("native contract %s (version %d) not found", curr.StringLE(), version)
|
2020-07-22 16:03:05 +00:00
|
|
|
}
|
2023-11-21 09:35:18 +00:00
|
|
|
var (
|
|
|
|
meta = c.Metadata()
|
|
|
|
activeIn = c.ActiveIn()
|
|
|
|
)
|
|
|
|
if activeIn != nil {
|
|
|
|
height, ok := ic.Hardforks[activeIn.String()]
|
|
|
|
// Persisting block must not be taken into account, native contract can be called
|
|
|
|
// only AFTER its initialization block persist, thus, can't use ic.IsHardforkEnabled.
|
|
|
|
if !ok || ic.BlockHeight() < height {
|
|
|
|
return fmt.Errorf("native contract %s is active after hardfork %s", meta.Name, activeIn.String())
|
|
|
|
}
|
2021-03-11 11:39:51 +00:00
|
|
|
}
|
2022-12-16 20:48:04 +00:00
|
|
|
m, ok := meta.GetMethodByOffset(ic.VM.Context().IP())
|
2020-07-22 16:03:05 +00:00
|
|
|
if !ok {
|
2021-02-15 13:40:44 +00:00
|
|
|
return fmt.Errorf("method not found")
|
2020-07-22 16:03:05 +00:00
|
|
|
}
|
2022-12-16 20:36:45 +00:00
|
|
|
reqFlags := m.RequiredFlags
|
2022-12-16 20:48:04 +00:00
|
|
|
if !ic.IsHardforkEnabled(config.HFAspidochelone) && meta.ID == ManagementContractID &&
|
2022-12-16 20:36:45 +00:00
|
|
|
(m.MD.Name == "deploy" || m.MD.Name == "update") {
|
|
|
|
reqFlags &= callflag.States | callflag.AllowNotify
|
|
|
|
}
|
|
|
|
if !ic.VM.Context().GetCallFlags().Has(reqFlags) {
|
2021-02-15 13:40:44 +00:00
|
|
|
return fmt.Errorf("missing call flags for native %d `%s` operation call: %05b vs %05b",
|
2022-12-16 20:36:45 +00:00
|
|
|
version, m.MD.Name, ic.VM.Context().GetCallFlags(), reqFlags)
|
2020-07-22 16:03:05 +00:00
|
|
|
}
|
2022-04-08 09:31:55 +00:00
|
|
|
invokeFee := m.CPUFee*ic.BaseExecFee() +
|
2022-04-08 09:27:25 +00:00
|
|
|
m.StorageFee*ic.BaseStorageFee()
|
2021-03-05 11:53:46 +00:00
|
|
|
if !ic.VM.AddGas(invokeFee) {
|
2020-07-22 16:03:05 +00:00
|
|
|
return errors.New("gas limit exceeded")
|
|
|
|
}
|
2020-11-19 15:02:21 +00:00
|
|
|
ctx := ic.VM.Context()
|
2020-12-29 10:44:07 +00:00
|
|
|
args := make([]stackitem.Item, len(m.MD.Parameters))
|
|
|
|
for i := range args {
|
2022-05-16 06:38:39 +00:00
|
|
|
args[i] = ic.VM.Estack().Peek(i).Item()
|
2020-12-29 10:44:07 +00:00
|
|
|
}
|
2020-07-22 16:03:05 +00:00
|
|
|
result := m.Func(ic, args)
|
2022-05-16 06:38:39 +00:00
|
|
|
for range m.MD.Parameters {
|
|
|
|
ic.VM.Estack().Pop()
|
|
|
|
}
|
2020-09-21 14:34:40 +00:00
|
|
|
if m.MD.ReturnType != smartcontract.VoidType {
|
2021-08-30 20:43:17 +00:00
|
|
|
ctx.Estack().PushItem(result)
|
2020-09-21 14:34:40 +00:00
|
|
|
}
|
2020-07-22 16:03:05 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-12-13 18:36:06 +00:00
|
|
|
|
|
|
|
// OnPersist calls OnPersist methods for all native contracts.
|
|
|
|
func OnPersist(ic *interop.Context) error {
|
|
|
|
if ic.Trigger != trigger.OnPersist {
|
|
|
|
return errors.New("onPersist must be trigered by system")
|
|
|
|
}
|
|
|
|
for _, c := range ic.Natives {
|
2023-11-21 09:35:18 +00:00
|
|
|
activeIn := c.ActiveIn()
|
|
|
|
if !(activeIn == nil || ic.IsHardforkEnabled(*activeIn)) {
|
2021-03-11 11:39:51 +00:00
|
|
|
continue
|
|
|
|
}
|
2020-12-13 18:36:06 +00:00
|
|
|
err := c.OnPersist(ic)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PostPersist calls PostPersist methods for all native contracts.
|
|
|
|
func PostPersist(ic *interop.Context) error {
|
|
|
|
if ic.Trigger != trigger.PostPersist {
|
|
|
|
return errors.New("postPersist must be trigered by system")
|
|
|
|
}
|
|
|
|
for _, c := range ic.Natives {
|
2023-11-21 09:35:18 +00:00
|
|
|
activeIn := c.ActiveIn()
|
|
|
|
if !(activeIn == nil || ic.IsHardforkEnabled(*activeIn)) {
|
2021-03-11 11:39:51 +00:00
|
|
|
continue
|
|
|
|
}
|
2020-12-13 18:36:06 +00:00
|
|
|
err := c.PostPersist(ic)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|