core/native: untangle native contracts initialization

The notion of NativeContractState shouldn't ever existed, native contract is a
contract and its state is saved as regular contract state which is critical
because we'll have MPT calculations over this state soon.

Initial minting should be done in Neo.Native.Deploy because it generates
notification that should have proper transaction context.

RegisterNative() shouldn't exist as a public method, native contracts are only
registered at block 0 and they can do it internally, no outside user should be
able to mess with it.

Move some structures from `native` package to `interop` also to avoid circular
references as interop.Context has to have a list of native contracts (exposing
them via Blockchainer is again too dangerous, it's too powerful tool).
This commit is contained in:
Roman Khimov 2020-04-22 23:00:18 +03:00
parent 869c7d6afa
commit 30836ca69b
10 changed files with 171 additions and 216 deletions

View file

@ -208,10 +208,6 @@ func (bc *Blockchain) init() error {
// and the genesis block as first block.
bc.log.Info("restoring blockchain", zap.String("version", version))
if err = bc.registerNative(); err != nil {
return err
}
bHeight, err := bc.dao.GetCurrentBlockHeight()
if err != nil {
return err
@ -273,34 +269,6 @@ func (bc *Blockchain) init() error {
return nil
}
func (bc *Blockchain) registerNative() error {
gas := native.NewGAS()
neo := native.NewNEO()
neo.GAS = gas
gas.NEO = neo
data, err := bc.dao.GetNativeContractState(gas.Hash)
if err != nil {
return err
}
if err = gas.InitFromStore(data); err != nil {
return err
}
data, err = bc.dao.GetNativeContractState(neo.Hash)
if err != nil {
return err
}
if err = neo.InitFromStore(data); err != nil {
return err
}
bc.contracts.SetGAS(gas)
bc.contracts.SetNEO(neo)
return nil
}
// Run runs chain loop.
func (bc *Blockchain) Run() {
persistTimer := time.NewTimer(persistInterval)
@ -855,11 +823,6 @@ func (bc *Blockchain) LastBatch() *storage.MemBatch {
return bc.lastBatch
}
// RegisterNative registers native contract in the blockchain.
func (bc *Blockchain) RegisterNative(c native.Contract) {
bc.contracts.Add(c)
}
// processOutputs processes transaction outputs.
func processOutputs(tx *transaction.Transaction, dao *dao.Cached) error {
for index, output := range tx.Outputs {
@ -2065,7 +2028,7 @@ func (bc *Blockchain) secondsPerBlock() int {
}
func (bc *Blockchain) newInteropContext(trigger trigger.Type, d dao.DAO, block *block.Block, tx *transaction.Transaction) *interop.Context {
ic := interop.NewContext(trigger, bc, d, block, tx, bc.log)
ic := interop.NewContext(trigger, bc, d, bc.contracts.Contracts, block, tx, bc.log)
switch {
case tx != nil:
ic.Container = tx

View file

@ -32,7 +32,6 @@ type DAO interface {
GetCurrentBlockHeight() (uint32, error)
GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error)
GetHeaderHashes() ([]util.Uint256, error)
GetNativeContractState(h util.Uint160) ([]byte, error)
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error)
GetNextBlockValidators() (keys.PublicKeys, error)
@ -55,7 +54,6 @@ type DAO interface {
PutAssetState(as *state.Asset) error
PutContractState(cs *state.Contract) error
PutCurrentHeader(hashAndIndex []byte) error
PutNativeContractState(h util.Uint160, value []byte) error
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error
PutNextBlockValidators(keys.PublicKeys) error
@ -211,18 +209,6 @@ func (dao *Simple) DeleteContractState(hash util.Uint160) error {
return dao.Store.Delete(key)
}
// GetNativeContractState retrieves native contract state from the store.
func (dao *Simple) GetNativeContractState(h util.Uint160) ([]byte, error) {
key := storage.AppendPrefix(storage.STNativeContract, h.BytesBE())
return dao.Store.Get(key)
}
// PutNativeContractState puts native contract state into the store.
func (dao *Simple) PutNativeContractState(h util.Uint160, value []byte) error {
key := storage.AppendPrefix(storage.STNativeContract, h.BytesBE())
return dao.Store.Put(key, value)
}
// -- end contracts.
// -- start nep5 balances.

View file

@ -7,8 +7,14 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto"
"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"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"go.uber.org/zap"
)
@ -16,6 +22,7 @@ import (
type Context struct {
Chain blockchainer.Blockchainer
Container crypto.Verifiable
Natives []Contract
Trigger trigger.Type
Block *block.Block
Tx *transaction.Transaction
@ -25,11 +32,12 @@ type Context struct {
}
// NewContext returns new interop context.
func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO, block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO, natives []Contract, block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
dao := dao.NewCached(d)
nes := make([]state.NotificationEvent, 0)
return &Context{
Chain: bc,
Natives: natives,
Trigger: trigger,
Block: block,
Tx: tx,
@ -48,3 +56,64 @@ type Function struct {
Func func(*Context, *vm.VM) error
Price int
}
// 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
}
// 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,
})
}

View file

@ -4,80 +4,20 @@ import (
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"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"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/pkg/errors"
)
// Method is a signature for a native method.
type Method = func(ic *interop.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 {
Metadata() *ContractMD
OnPersist(*interop.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
}
// Contracts is a set of registered native contracts.
type Contracts struct {
NEO *NEO
GAS *GAS
Contracts []Contract
}
// SetGAS sets GAS native contract.
func (cs *Contracts) SetGAS(g *GAS) {
cs.GAS = g
cs.Contracts = append(cs.Contracts, g)
}
// SetNEO sets NEO native contract.
func (cs *Contracts) SetNEO(n *NEO) {
cs.NEO = n
cs.Contracts = append(cs.Contracts, n)
}
// 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
Contracts []interop.Contract
}
// ByHash returns native contract with the specified hash.
func (cs *Contracts) ByHash(h util.Uint160) Contract {
func (cs *Contracts) ByHash(h util.Uint160) interop.Contract {
for _, ctr := range cs.Contracts {
if ctr.Metadata().Hash.Equals(h) {
return ctr
@ -87,7 +27,7 @@ func (cs *Contracts) ByHash(h util.Uint160) Contract {
}
// ByID returns native contract with the specified id.
func (cs *Contracts) ByID(id uint32) Contract {
func (cs *Contracts) ByID(id uint32) interop.Contract {
for _, ctr := range cs.Contracts {
if ctr.Metadata().ServiceID == id {
return ctr
@ -96,33 +36,21 @@ func (cs *Contracts) ByID(id uint32) Contract {
return nil
}
// 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,
})
}
// NewContracts returns new empty set of native contracts.
// NewContracts returns new set of native contracts with new GAS and NEO
// contracts.
func NewContracts() *Contracts {
return &Contracts{
Contracts: []Contract{},
}
}
cs := new(Contracts)
// Add adds new native contracts to the list.
func (cs *Contracts) Add(c Contract) {
cs.Contracts = append(cs.Contracts, c)
gas := NewGAS()
neo := NewNEO()
neo.GAS = gas
gas.NEO = neo
cs.GAS = gas
cs.Contracts = append(cs.Contracts, gas)
cs.NEO = neo
cs.Contracts = append(cs.Contracts, neo)
return cs
}
// GetNativeInterop returns an interop getter for a given set of contracts.
@ -139,7 +67,7 @@ func (cs *Contracts) GetNativeInterop(ic *interop.Context) func(uint32) *vm.Inte
}
// getNativeInterop returns native contract interop.
func getNativeInterop(ic *interop.Context, c Contract) func(v *vm.VM) error {
func getNativeInterop(ic *interop.Context, c interop.Contract) func(v *vm.VM) error {
return func(v *vm.VM) error {
h := v.GetContextScriptHash(0)
if !h.Equals(c.Metadata().Hash) {

View file

@ -13,16 +13,12 @@ func Deploy(ic *interop.Context, _ *vm.VM) error {
if ic.Block.Index != 0 {
return errors.New("native contracts can be deployed only at 0 block")
}
gas := NewGAS()
neo := NewNEO()
neo.GAS = gas
gas.NEO = neo
if err := gas.Initialize(ic); err != nil {
return fmt.Errorf("can't initialize GAS native contract: %v", err)
}
if err := neo.Initialize(ic); err != nil {
return fmt.Errorf("can't initialize NEO native contract: %v", err)
for _, native := range ic.Natives {
if err := native.Initialize(ic); err != nil {
md := native.Metadata()
return fmt.Errorf("initializing %s native contract: %v", md.ServiceName, err)
}
}
return nil
}

View file

@ -6,14 +6,12 @@ import (
"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/core/storage"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"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/emit"
)
// GAS represents GAS native contract.
@ -24,13 +22,17 @@ type GAS struct {
const gasSyscallName = "Neo.Native.Tokens.GAS"
// GASFactor is a divisor for finding GAS integral value.
const GASFactor = NEOTotalSupply
const initialGAS = 30000000
// NewGAS returns GAS native contract.
func NewGAS() *GAS {
nep5 := newNEP5Native(gasSyscallName)
nep5.name = "GAS"
nep5.symbol = "gas"
nep5.decimals = 8
nep5.factor = 100000000
nep5.factor = GASFactor
g := &GAS{nep5TokenNative: *nep5}
@ -44,16 +46,6 @@ func NewGAS() *GAS {
return g
}
// initFromStore initializes variable contract parameters from the store.
func (g *GAS) InitFromStore(data []byte) error {
g.totalSupply = *emit.BytesToInt(data)
return nil
}
func (g *GAS) serializeState() []byte {
return emit.IntToBytes(&g.totalSupply)
}
func (g *GAS) increaseBalance(_ *interop.Context, acc *state.Account, amount *big.Int) error {
if sign := amount.Sign(); sign == 0 {
return nil
@ -66,22 +58,18 @@ func (g *GAS) increaseBalance(_ *interop.Context, acc *state.Account, amount *bi
// Initialize initializes GAS contract.
func (g *GAS) Initialize(ic *interop.Context) error {
data, err := ic.DAO.GetNativeContractState(g.Hash)
if err == nil {
return g.InitFromStore(data)
} else if err != storage.ErrKeyNotFound {
if err := g.nep5TokenNative.Initialize(ic); err != nil {
return err
}
if err := g.nep5TokenNative.Initialize(); err != nil {
return err
if g.nep5TokenNative.getTotalSupply(ic).Sign() != 0 {
return errors.New("already initialized")
}
h, _, err := getStandbyValidatorsHash(ic)
if err != nil {
return err
}
g.mint(ic, h, big.NewInt(30000000*g.factor))
return ic.DAO.PutNativeContractState(g.Hash, g.serializeState())
g.mint(ic, h, big.NewInt(initialGAS*GASFactor))
return nil
}
// OnPersist implements Contract interface.
@ -95,7 +83,7 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
// netFee += tx.NetworkFee
//}
//g.mint(ic, <primary>, netFee)
return ic.DAO.PutNativeContractState(g.Hash, g.serializeState())
return nil
}
func (g *GAS) getSysFeeAmount(ic *interop.Context, args []vm.StackItem) vm.StackItem {

View file

@ -15,7 +15,6 @@ import (
"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/emit"
"github.com/pkg/errors"
)
@ -27,6 +26,9 @@ type NEO struct {
const neoSyscallName = "Neo.Native.Tokens.NEO"
// NEOTotalSupply is the total amount of NEO in the system.
const NEOTotalSupply = 100000000
// NewNEO returns NEO native contract.
func NewNEO() *NEO {
nep5 := newNEP5Native(neoSyscallName)
@ -74,22 +76,19 @@ func NewNEO() *NEO {
// Initialize initializes NEO contract.
func (n *NEO) Initialize(ic *interop.Context) error {
data, err := ic.DAO.GetNativeContractState(n.Hash)
if err == nil {
return n.InitFromStore(data)
} else if err != storage.ErrKeyNotFound {
if err := n.nep5TokenNative.Initialize(ic); err != nil {
return err
}
if err := n.nep5TokenNative.Initialize(); err != nil {
return err
if n.nep5TokenNative.getTotalSupply(ic).Sign() != 0 {
return errors.New("already initialized")
}
h, vs, err := getStandbyValidatorsHash(ic)
if err != nil {
return err
}
n.mint(ic, h, big.NewInt(100000000*n.factor))
n.mint(ic, h, big.NewInt(NEOTotalSupply))
for i := range vs {
if err := n.registerValidatorInternal(ic, vs[i]); err != nil {
@ -97,19 +96,9 @@ func (n *NEO) Initialize(ic *interop.Context) error {
}
}
return ic.DAO.PutNativeContractState(n.Hash, n.serializeState())
}
// initFromStore initializes variable contract parameters from the store.
func (n *NEO) InitFromStore(data []byte) error {
n.totalSupply = *emit.BytesToInt(data)
return nil
}
func (n *NEO) serializeState() []byte {
return emit.IntToBytes(&n.totalSupply)
}
// OnPersist implements Contract interface.
func (n *NEO) OnPersist(ic *interop.Context) error {
pubs, err := n.GetValidatorsInternal(ic.Chain, ic.DAO)
@ -119,7 +108,7 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
if err := ic.DAO.PutNextBlockValidators(pubs); err != nil {
return err
}
return ic.DAO.PutNativeContractState(n.Hash, n.serializeState())
return nil
}
func (n *NEO) increaseBalance(ic *interop.Context, acc *state.Account, amount *big.Int) error {

View file

@ -10,28 +10,31 @@ import (
"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/emit"
)
// nep5TokenNative represents NEP-5 token contract.
type nep5TokenNative struct {
ContractMD
name string
symbol string
decimals int64
factor int64
totalSupply big.Int
onPersist func(*interop.Context) error
incBalance func(*interop.Context, *state.Account, *big.Int) error
interop.ContractMD
name string
symbol string
decimals int64
factor int64
onPersist func(*interop.Context) error
incBalance func(*interop.Context, *state.Account, *big.Int) error
}
func (c *nep5TokenNative) Metadata() *ContractMD {
// totalSupplyKey is the key used to store totalSupply value.
var totalSupplyKey = []byte{11}
func (c *nep5TokenNative) Metadata() *interop.ContractMD {
return &c.ContractMD
}
var _ Contract = (*nep5TokenNative)(nil)
var _ interop.Contract = (*nep5TokenNative)(nil)
func newNEP5Native(name string) *nep5TokenNative {
n := &nep5TokenNative{ContractMD: *NewContractMD(name)}
n := &nep5TokenNative{ContractMD: *interop.NewContractMD(name)}
desc := newDescriptor("name", smartcontract.StringType)
md := newMethodAndPrice(n.Name, 1, smartcontract.NoneFlag)
@ -45,6 +48,10 @@ func newNEP5Native(name string) *nep5TokenNative {
md = newMethodAndPrice(n.Decimals, 1, smartcontract.NoneFlag)
n.AddMethod(md, desc, true)
desc = newDescriptor("totalSupply", smartcontract.IntegerType)
md = newMethodAndPrice(n.TotalSupply, 1, smartcontract.NoneFlag)
n.AddMethod(md, desc, true)
desc = newDescriptor("balanceOf", smartcontract.IntegerType,
manifest.NewParameter("account", smartcontract.Hash160Type))
md = newMethodAndPrice(n.balanceOf, 1, smartcontract.NoneFlag)
@ -63,7 +70,7 @@ func newNEP5Native(name string) *nep5TokenNative {
return n
}
func (c *nep5TokenNative) Initialize() error {
func (c *nep5TokenNative) Initialize(_ *interop.Context) error {
return nil
}
@ -79,6 +86,23 @@ func (c *nep5TokenNative) Decimals(_ *interop.Context, _ []vm.StackItem) vm.Stac
return vm.NewBigIntegerItem(big.NewInt(c.decimals))
}
func (c *nep5TokenNative) TotalSupply(ic *interop.Context, _ []vm.StackItem) vm.StackItem {
return vm.NewBigIntegerItem(c.getTotalSupply(ic))
}
func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
si := ic.DAO.GetStorageItem(c.Hash, totalSupplyKey)
if si == nil {
return big.NewInt(0)
}
return emit.BytesToInt(si.Value)
}
func (c *nep5TokenNative) saveTotalSupply(ic *interop.Context, supply *big.Int) error {
si := &state.StorageItem{Value: emit.IntToBytes(supply)}
return ic.DAO.PutStorageItem(c.Hash, totalSupplyKey, si)
}
func (c *nep5TokenNative) Transfer(ic *interop.Context, args []vm.StackItem) vm.StackItem {
from := toUint160(args[0])
to := toUint160(args[1])
@ -185,7 +209,12 @@ func (c *nep5TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount
panic(err)
}
c.totalSupply.Add(&c.totalSupply, amount)
supply := c.getTotalSupply(ic)
supply.Add(supply, amount)
err = c.saveTotalSupply(ic, supply)
if err != nil {
panic(err)
}
}
func (c *nep5TokenNative) OnPersist(ic *interop.Context) error {
@ -200,8 +229,8 @@ func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Para
}
}
func newMethodAndPrice(f Method, price int64, flags smartcontract.CallFlag) *MethodAndPrice {
return &MethodAndPrice{
func newMethodAndPrice(f interop.Method, price int64, flags smartcontract.CallFlag) *interop.MethodAndPrice {
return &interop.MethodAndPrice{
Func: f,
Price: price,
RequiredFlags: flags,

View file

@ -6,7 +6,6 @@ import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
@ -17,11 +16,15 @@ import (
)
type testNative struct {
meta native.ContractMD
meta interop.ContractMD
blocks chan uint32
}
func (tn *testNative) Metadata() *native.ContractMD {
func (tn *testNative) Initialize(_ *interop.Context) error {
return nil
}
func (tn *testNative) Metadata() *interop.ContractMD {
return &tn.meta
}
@ -34,11 +37,16 @@ func (tn *testNative) OnPersist(ic *interop.Context) error {
}
}
var _ native.Contract = (*testNative)(nil)
var _ interop.Contract = (*testNative)(nil)
// registerNative registers native contract in the blockchain.
func (bc *Blockchain) registerNative(c interop.Contract) {
bc.contracts.Contracts = append(bc.contracts.Contracts, c)
}
func newTestNative() *testNative {
tn := &testNative{
meta: *native.NewContractMD("Test.Native.Sum"),
meta: *interop.NewContractMD("Test.Native.Sum"),
blocks: make(chan uint32, 1),
}
desc := &manifest.Method{
@ -49,7 +57,7 @@ func newTestNative() *testNative {
},
ReturnType: smartcontract.IntegerType,
}
md := &native.MethodAndPrice{
md := &interop.MethodAndPrice{
Func: tn.sum,
Price: 1,
RequiredFlags: smartcontract.NoneFlag,
@ -76,7 +84,7 @@ func TestNativeContract_Invoke(t *testing.T) {
defer chain.Close()
tn := newTestNative()
chain.RegisterNative(tn)
chain.registerNative(tn)
w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "sum", int64(14), int64(28))

View file

@ -17,7 +17,6 @@ const (
STAsset KeyPrefix = 0x4c
STNotification KeyPrefix = 0x4d
STContract KeyPrefix = 0x50
STNativeContract KeyPrefix = 0x51
STStorage KeyPrefix = 0x70
STNEP5Transfers KeyPrefix = 0x72
STNEP5Balances KeyPrefix = 0x73