2020-04-08 10:35:39 +00:00
|
|
|
package interop
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2020-04-13 13:18:28 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
2020-04-22 20:00:18 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
2020-04-08 10:35:39 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
2020-04-22 20:00:18 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-04-08 10:35:39 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
2020-04-22 20:00:18 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
2020-04-08 10:35:39 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Context represents context in which interops are executed.
|
|
|
|
type Context struct {
|
|
|
|
Chain blockchainer.Blockchainer
|
2020-04-13 13:18:28 +00:00
|
|
|
Container crypto.Verifiable
|
2020-04-22 20:00:18 +00:00
|
|
|
Natives []Contract
|
2020-04-08 10:35:39 +00:00
|
|
|
Trigger trigger.Type
|
|
|
|
Block *block.Block
|
|
|
|
Tx *transaction.Transaction
|
|
|
|
DAO *dao.Cached
|
2020-05-17 20:58:23 +00:00
|
|
|
LowerDAO dao.DAO
|
2020-04-08 10:35:39 +00:00
|
|
|
Notifications []state.NotificationEvent
|
|
|
|
Log *zap.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewContext returns new interop context.
|
2020-04-22 20:00:18 +00:00
|
|
|
func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO, natives []Contract, block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
|
2020-04-08 10:35:39 +00:00
|
|
|
dao := dao.NewCached(d)
|
|
|
|
nes := make([]state.NotificationEvent, 0)
|
|
|
|
return &Context{
|
|
|
|
Chain: bc,
|
2020-04-22 20:00:18 +00:00
|
|
|
Natives: natives,
|
2020-04-08 10:35:39 +00:00
|
|
|
Trigger: trigger,
|
|
|
|
Block: block,
|
|
|
|
Tx: tx,
|
|
|
|
DAO: dao,
|
2020-05-17 20:58:23 +00:00
|
|
|
LowerDAO: d,
|
2020-04-08 10:35:39 +00:00
|
|
|
Notifications: nes,
|
|
|
|
Log: log,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function binds function name, id with the function itself and price,
|
|
|
|
// it's supposed to be inited once for all interopContexts, so it doesn't use
|
|
|
|
// vm.InteropFuncPrice directly.
|
|
|
|
type Function struct {
|
|
|
|
ID uint32
|
|
|
|
Name string
|
|
|
|
Func func(*Context, *vm.VM) error
|
|
|
|
Price int
|
|
|
|
}
|
2020-04-22 20:00:18 +00:00
|
|
|
|
|
|
|
// Method is a signature for a native method.
|
|
|
|
type Method = func(ic *Context, args []vm.StackItem) vm.StackItem
|
|
|
|
|
|
|
|
// MethodAndPrice is a native-contract method descriptor.
|
|
|
|
type MethodAndPrice struct {
|
|
|
|
Func Method
|
|
|
|
Price int64
|
|
|
|
RequiredFlags smartcontract.CallFlag
|
|
|
|
}
|
|
|
|
|
|
|
|
// Contract is an interface for all native contracts.
|
|
|
|
type Contract interface {
|
|
|
|
Initialize(*Context) error
|
|
|
|
Metadata() *ContractMD
|
|
|
|
OnPersist(*Context) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// ContractMD represents native contract instance.
|
|
|
|
type ContractMD struct {
|
|
|
|
Manifest manifest.Manifest
|
|
|
|
ServiceName string
|
|
|
|
ServiceID uint32
|
|
|
|
Script []byte
|
|
|
|
Hash util.Uint160
|
|
|
|
Methods map[string]MethodAndPrice
|
|
|
|
}
|
|
|
|
|
2020-05-07 11:11:59 +00:00
|
|
|
// GetContract returns script of the contract with the specified hash.
|
|
|
|
func (ic *Context) GetContract(h util.Uint160) ([]byte, bool) {
|
|
|
|
cs, err := ic.DAO.GetContractState(h)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
hasDynamicInvoke := (cs.Properties & smartcontract.HasDynamicInvoke) != 0
|
|
|
|
return cs.Script, hasDynamicInvoke
|
|
|
|
}
|
|
|
|
|
2020-04-22 20:00:18 +00:00
|
|
|
// NewContractMD returns Contract with the specified list of methods.
|
|
|
|
func NewContractMD(name string) *ContractMD {
|
|
|
|
c := &ContractMD{
|
|
|
|
ServiceName: name,
|
|
|
|
ServiceID: emit.InteropNameToID([]byte(name)),
|
|
|
|
Methods: make(map[string]MethodAndPrice),
|
|
|
|
}
|
|
|
|
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
emit.Syscall(w.BinWriter, c.ServiceName)
|
|
|
|
c.Script = w.Bytes()
|
|
|
|
c.Hash = hash.Hash160(c.Script)
|
|
|
|
c.Manifest = *manifest.DefaultManifest(c.Hash)
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddMethod adds new method to a native contract.
|
|
|
|
func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method, safe bool) {
|
|
|
|
c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, *desc)
|
|
|
|
c.Methods[desc.Name] = *md
|
|
|
|
if safe {
|
|
|
|
c.Manifest.SafeMethods.Add(desc.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddEvent adds new event to a native contract.
|
|
|
|
func (c *ContractMD) AddEvent(name string, ps ...manifest.Parameter) {
|
|
|
|
c.Manifest.ABI.Events = append(c.Manifest.ABI.Events, manifest.Event{
|
|
|
|
Name: name,
|
|
|
|
Parameters: ps,
|
|
|
|
})
|
|
|
|
}
|