diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index 25b16b7c7..e22deaf8f 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -12,6 +12,7 @@ import ( "github.com/nspcc-dev/dbft/payload" "github.com/nspcc-dev/neo-go/pkg/core" coreb "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/mempool" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -77,7 +78,7 @@ type Config struct { // about the new block that needs to be broadcasted. RelayBlock func(b *coreb.Block) // Chain is a core.Blockchainer instance. - Chain core.Blockchainer + Chain blockchainer.Blockchainer // RequestTx is a callback to which will be called // when a node lacks transactions present in a block. RequestTx func(h ...util.Uint256) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index c9e82bf3e..e02d96d77 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -12,6 +12,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/dao" + "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/storage" @@ -446,7 +447,7 @@ func (bc *Blockchain) processHeader(h *block.Header, batch storage.Batch, header return nil } -// bc.GetHeaderHash(int(endHeight)) returns sum of all system fees for blocks up to h. +// getSystemFeeAmount returns sum of all system fees for blocks up to h. // and 0 if no such block exists. func (bc *Blockchain) getSystemFeeAmount(h util.Uint256) uint32 { _, sf, _ := bc.dao.GetBlock(h) @@ -657,7 +658,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { } case *transaction.InvocationTX: systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx) - v := systemInterop.SpawnVM() + v := SpawnVM(systemInterop) v.SetCheckedHash(tx.VerificationHash().BytesBE()) v.LoadScript(t.Script) v.SetPriceGetter(getPrice) @@ -667,11 +668,11 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { err := v.Run() if !v.HasFailed() { - _, err := systemInterop.dao.Persist() + _, err := systemInterop.DAO.Persist() if err != nil { return errors.Wrap(err, "failed to persist invocation results") } - for _, note := range systemInterop.notifications { + for _, note := range systemInterop.Notifications { arr, ok := note.Item.Value().([]vm.StackItem) if !ok || len(arr) != 4 { continue @@ -710,7 +711,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error { VMState: v.State(), GasConsumed: v.GasConsumed(), Stack: v.Estack().ToContractParameters(), - Events: systemInterop.notifications, + Events: systemInterop.Notifications, } err = cache.PutAppExecResult(aer) if err != nil { @@ -2002,7 +2003,7 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([ // GetTestVM returns a VM and a Store setup for a test run of some sort of code. func (bc *Blockchain) GetTestVM() *vm.VM { systemInterop := bc.newInteropContext(trigger.Application, bc.dao, nil, nil) - vm := systemInterop.SpawnVM() + vm := SpawnVM(systemInterop) vm.SetPriceGetter(getPrice) return vm } @@ -2024,13 +2025,13 @@ func ScriptFromWitness(hash util.Uint160, witness *transaction.Witness) ([]byte, } // verifyHashAgainstScript verifies given hash against the given witness. -func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, checkedHash util.Uint256, interopCtx *interopContext, useKeys bool) error { +func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transaction.Witness, checkedHash util.Uint256, interopCtx *interop.Context, useKeys bool) error { verification, err := ScriptFromWitness(hash, witness) if err != nil { return err } - vm := interopCtx.SpawnVM() + vm := SpawnVM(interopCtx) vm.SetCheckedHash(checkedHash.BytesBE()) vm.LoadScript(verification) vm.LoadScript(witness.InvocationScript) @@ -2124,6 +2125,6 @@ func (bc *Blockchain) secondsPerBlock() int { return bc.config.SecondsPerBlock } -func (bc *Blockchain) newInteropContext(trigger trigger.Type, d dao.DAO, block *block.Block, tx *transaction.Transaction) *interopContext { - return newInteropContext(trigger, bc, d, block, tx, bc.log) +func (bc *Blockchain) newInteropContext(trigger trigger.Type, d dao.DAO, block *block.Block, tx *transaction.Transaction) *interop.Context { + return interop.NewContext(trigger, bc, d, block, tx, bc.log) } diff --git a/pkg/core/blockchainer.go b/pkg/core/blockchainer/blockchainer.go similarity index 99% rename from pkg/core/blockchainer.go rename to pkg/core/blockchainer/blockchainer.go index a633bb523..1e368f90f 100644 --- a/pkg/core/blockchainer.go +++ b/pkg/core/blockchainer/blockchainer.go @@ -1,4 +1,4 @@ -package core +package blockchainer import ( "github.com/nspcc-dev/neo-go/pkg/config" diff --git a/pkg/core/gas_price_test.go b/pkg/core/gas_price_test.go index a8bc2a52b..ba802f6f5 100644 --- a/pkg/core/gas_price_test.go +++ b/pkg/core/gas_price_test.go @@ -19,7 +19,7 @@ func TestGetPrice(t *testing.T) { sdao := dao.NewSimple(storage.NewMemoryStore()) systemInterop := bc.newInteropContext(trigger.Application, sdao, nil, nil) - v := systemInterop.SpawnVM() + v := SpawnVM(systemInterop) v.SetPriceGetter(getPrice) t.Run("Neo.Asset.Create", func(t *testing.T) { diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go new file mode 100644 index 000000000..6f9cfafc3 --- /dev/null +++ b/pkg/core/interop/context.go @@ -0,0 +1,48 @@ +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" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" + "github.com/nspcc-dev/neo-go/pkg/vm" + "go.uber.org/zap" +) + +// Context represents context in which interops are executed. +type Context struct { + Chain blockchainer.Blockchainer + Trigger trigger.Type + Block *block.Block + Tx *transaction.Transaction + DAO *dao.Cached + Notifications []state.NotificationEvent + Log *zap.Logger +} + +// 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 { + dao := dao.NewCached(d) + nes := make([]state.NotificationEvent, 0) + return &Context{ + Chain: bc, + Trigger: trigger, + Block: block, + Tx: tx, + DAO: dao, + 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 +} diff --git a/pkg/core/interop/enumerator/interop.go b/pkg/core/interop/enumerator/interop.go new file mode 100644 index 000000000..ecd90efad --- /dev/null +++ b/pkg/core/interop/enumerator/interop.go @@ -0,0 +1,27 @@ +package enumerator + +import ( + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/vm" +) + +// Concat concatenates 2 enumerators into a single one. +func Concat(_ *interop.Context, v *vm.VM) error { + return vm.EnumeratorConcat(v) +} + +// Create creates an enumerator from an array-like stack item. +func Create(_ *interop.Context, v *vm.VM) error { + return vm.EnumeratorCreate(v) +} + +// Next advances the enumerator, pushes true if is it was successful +// and false otherwise. +func Next(_ *interop.Context, v *vm.VM) error { + return vm.EnumeratorNext(v) +} + +// Value returns the current value of the enumerator. +func Value(_ *interop.Context, v *vm.VM) error { + return vm.EnumeratorValue(v) +} diff --git a/pkg/core/interop/iterator/interop.go b/pkg/core/interop/iterator/interop.go new file mode 100644 index 000000000..f04dfa942 --- /dev/null +++ b/pkg/core/interop/iterator/interop.go @@ -0,0 +1,31 @@ +package iterator + +import ( + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/vm" +) + +// Concat concatenates 2 iterators into a single one. +func Concat(_ *interop.Context, v *vm.VM) error { + return vm.IteratorConcat(v) +} + +// Create creates an iterator from array-like or map stack item. +func Create(_ *interop.Context, v *vm.VM) error { + return vm.IteratorCreate(v) +} + +// Key returns current iterator key. +func Key(_ *interop.Context, v *vm.VM) error { + return vm.IteratorKey(v) +} + +// Keys returns keys of the iterator. +func Keys(_ *interop.Context, v *vm.VM) error { + return vm.IteratorKeys(v) +} + +// Values returns values of the iterator. +func Values(_ *interop.Context, v *vm.VM) error { + return vm.IteratorValues(v) +} diff --git a/pkg/core/interop_neo.go b/pkg/core/interop_neo.go index 277e06620..378214447 100644 --- a/pkg/core/interop_neo.go +++ b/pkg/core/interop_neo.go @@ -6,6 +6,7 @@ import ( "math" "strings" + "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/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -37,7 +38,7 @@ const ( ) // headerGetVersion returns version from the header. -func (ic *interopContext) headerGetVersion(v *vm.VM) error { +func headerGetVersion(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -47,7 +48,7 @@ func (ic *interopContext) headerGetVersion(v *vm.VM) error { } // headerGetConsensusData returns consensus data from the header. -func (ic *interopContext) headerGetConsensusData(v *vm.VM) error { +func headerGetConsensusData(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -57,7 +58,7 @@ func (ic *interopContext) headerGetConsensusData(v *vm.VM) error { } // headerGetMerkleRoot returns version from the header. -func (ic *interopContext) headerGetMerkleRoot(v *vm.VM) error { +func headerGetMerkleRoot(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -67,7 +68,7 @@ func (ic *interopContext) headerGetMerkleRoot(v *vm.VM) error { } // headerGetNextConsensus returns version from the header. -func (ic *interopContext) headerGetNextConsensus(v *vm.VM) error { +func headerGetNextConsensus(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -77,7 +78,7 @@ func (ic *interopContext) headerGetNextConsensus(v *vm.VM) error { } // txGetAttributes returns current transaction attributes. -func (ic *interopContext) txGetAttributes(v *vm.VM) error { +func txGetAttributes(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -95,7 +96,7 @@ func (ic *interopContext) txGetAttributes(v *vm.VM) error { } // txGetInputs returns current transaction inputs. -func (ic *interopContext) txGetInputs(v *vm.VM) error { +func txGetInputs(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -113,7 +114,7 @@ func (ic *interopContext) txGetInputs(v *vm.VM) error { } // txGetOutputs returns current transaction outputs. -func (ic *interopContext) txGetOutputs(v *vm.VM) error { +func txGetOutputs(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -131,13 +132,13 @@ func (ic *interopContext) txGetOutputs(v *vm.VM) error { } // txGetReferences returns current transaction references. -func (ic *interopContext) txGetReferences(v *vm.VM) error { +func txGetReferences(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { return fmt.Errorf("type mismatch: %T is not a Transaction", txInterface) } - refs, err := ic.bc.References(tx) + refs, err := ic.Chain.References(tx) if err != nil { return err } @@ -159,7 +160,7 @@ func (ic *interopContext) txGetReferences(v *vm.VM) error { } // txGetType returns current transaction type. -func (ic *interopContext) txGetType(v *vm.VM) error { +func txGetType(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -170,13 +171,13 @@ func (ic *interopContext) txGetType(v *vm.VM) error { } // txGetUnspentCoins returns current transaction unspent coins. -func (ic *interopContext) txGetUnspentCoins(v *vm.VM) error { +func txGetUnspentCoins(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { return errors.New("value is not a transaction") } - ucs, err := ic.dao.GetUnspentCoinState(tx.Hash()) + ucs, err := ic.DAO.GetUnspentCoinState(tx.Hash()) if err != nil { return errors.New("no unspent coin state found") } @@ -185,7 +186,7 @@ func (ic *interopContext) txGetUnspentCoins(v *vm.VM) error { } // txGetWitnesses returns current transaction witnesses. -func (ic *interopContext) txGetWitnesses(v *vm.VM) error { +func txGetWitnesses(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -203,7 +204,7 @@ func (ic *interopContext) txGetWitnesses(v *vm.VM) error { } // invocationTx_GetScript returns invocation script from the current transaction. -func (ic *interopContext) invocationTxGetScript(v *vm.VM) error { +func invocationTxGetScript(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -221,7 +222,7 @@ func (ic *interopContext) invocationTxGetScript(v *vm.VM) error { } // witnessGetVerificationScript returns current witness' script. -func (ic *interopContext) witnessGetVerificationScript(v *vm.VM) error { +func witnessGetVerificationScript(ic *interop.Context, v *vm.VM) error { witInterface := v.Estack().Pop().Value() wit, ok := witInterface.(*transaction.Witness) if !ok { @@ -235,8 +236,8 @@ func (ic *interopContext) witnessGetVerificationScript(v *vm.VM) error { } // bcGetValidators returns validators. -func (ic *interopContext) bcGetValidators(v *vm.VM) error { - validators := ic.dao.GetValidators() +func bcGetValidators(ic *interop.Context, v *vm.VM) error { + validators := ic.DAO.GetValidators() v.Estack().PushVal(validators) return nil } @@ -256,7 +257,7 @@ func popInputFromVM(v *vm.VM) (*transaction.Input, error) { } // inputGetHash returns hash from the given input. -func (ic *interopContext) inputGetHash(v *vm.VM) error { +func inputGetHash(ic *interop.Context, v *vm.VM) error { input, err := popInputFromVM(v) if err != nil { return err @@ -266,7 +267,7 @@ func (ic *interopContext) inputGetHash(v *vm.VM) error { } // inputGetIndex returns index from the given input. -func (ic *interopContext) inputGetIndex(v *vm.VM) error { +func inputGetIndex(ic *interop.Context, v *vm.VM) error { input, err := popInputFromVM(v) if err != nil { return err @@ -290,7 +291,7 @@ func popOutputFromVM(v *vm.VM) (*transaction.Output, error) { } // outputGetAssetId returns asset ID from the given output. -func (ic *interopContext) outputGetAssetID(v *vm.VM) error { +func outputGetAssetID(ic *interop.Context, v *vm.VM) error { output, err := popOutputFromVM(v) if err != nil { return err @@ -300,7 +301,7 @@ func (ic *interopContext) outputGetAssetID(v *vm.VM) error { } // outputGetScriptHash returns scripthash from the given output. -func (ic *interopContext) outputGetScriptHash(v *vm.VM) error { +func outputGetScriptHash(ic *interop.Context, v *vm.VM) error { output, err := popOutputFromVM(v) if err != nil { return err @@ -310,7 +311,7 @@ func (ic *interopContext) outputGetScriptHash(v *vm.VM) error { } // outputGetValue returns value (amount) from the given output. -func (ic *interopContext) outputGetValue(v *vm.VM) error { +func outputGetValue(ic *interop.Context, v *vm.VM) error { output, err := popOutputFromVM(v) if err != nil { return err @@ -320,7 +321,7 @@ func (ic *interopContext) outputGetValue(v *vm.VM) error { } // attrGetData returns tx attribute data. -func (ic *interopContext) attrGetData(v *vm.VM) error { +func attrGetData(ic *interop.Context, v *vm.VM) error { attrInterface := v.Estack().Pop().Value() attr, ok := attrInterface.(*transaction.Attribute) if !ok { @@ -331,7 +332,7 @@ func (ic *interopContext) attrGetData(v *vm.VM) error { } // attrGetData returns tx attribute usage field. -func (ic *interopContext) attrGetUsage(v *vm.VM) error { +func attrGetUsage(ic *interop.Context, v *vm.VM) error { attrInterface := v.Estack().Pop().Value() attr, ok := attrInterface.(*transaction.Attribute) if !ok { @@ -342,13 +343,13 @@ func (ic *interopContext) attrGetUsage(v *vm.VM) error { } // bcGetAccount returns or creates an account. -func (ic *interopContext) bcGetAccount(v *vm.VM) error { +func bcGetAccount(ic *interop.Context, v *vm.VM) error { accbytes := v.Estack().Pop().Bytes() acchash, err := util.Uint160DecodeBytesBE(accbytes) if err != nil { return err } - acc, err := ic.dao.GetAccountStateOrNew(acchash) + acc, err := ic.DAO.GetAccountStateOrNew(acchash) if err != nil { return err } @@ -357,13 +358,13 @@ func (ic *interopContext) bcGetAccount(v *vm.VM) error { } // bcGetAsset returns an asset. -func (ic *interopContext) bcGetAsset(v *vm.VM) error { +func bcGetAsset(ic *interop.Context, v *vm.VM) error { asbytes := v.Estack().Pop().Bytes() ashash, err := util.Uint256DecodeBytesBE(asbytes) if err != nil { return err } - as, err := ic.dao.GetAssetState(ashash) + as, err := ic.DAO.GetAssetState(ashash) if err != nil { return errors.New("asset not found") } @@ -372,7 +373,7 @@ func (ic *interopContext) bcGetAsset(v *vm.VM) error { } // accountGetBalance returns balance for a given account. -func (ic *interopContext) accountGetBalance(v *vm.VM) error { +func accountGetBalance(ic *interop.Context, v *vm.VM) error { accInterface := v.Estack().Pop().Value() acc, ok := accInterface.(*state.Account) if !ok { @@ -392,7 +393,7 @@ func (ic *interopContext) accountGetBalance(v *vm.VM) error { } // accountGetScriptHash returns script hash of a given account. -func (ic *interopContext) accountGetScriptHash(v *vm.VM) error { +func accountGetScriptHash(ic *interop.Context, v *vm.VM) error { accInterface := v.Estack().Pop().Value() acc, ok := accInterface.(*state.Account) if !ok { @@ -403,7 +404,7 @@ func (ic *interopContext) accountGetScriptHash(v *vm.VM) error { } // accountGetVotes returns votes of a given account. -func (ic *interopContext) accountGetVotes(v *vm.VM) error { +func accountGetVotes(ic *interop.Context, v *vm.VM) error { accInterface := v.Estack().Pop().Value() acc, ok := accInterface.(*state.Account) if !ok { @@ -421,31 +422,31 @@ func (ic *interopContext) accountGetVotes(v *vm.VM) error { } // accountIsStandard checks whether given account is standard. -func (ic *interopContext) accountIsStandard(v *vm.VM) error { +func accountIsStandard(ic *interop.Context, v *vm.VM) error { accbytes := v.Estack().Pop().Bytes() acchash, err := util.Uint160DecodeBytesBE(accbytes) if err != nil { return err } - contract, err := ic.dao.GetContractState(acchash) + contract, err := ic.DAO.GetContractState(acchash) res := err != nil || vm.IsStandardContract(contract.Script) v.Estack().PushVal(res) return nil } // storageFind finds stored key-value pair. -func (ic *interopContext) storageFind(v *vm.VM) error { +func storageFind(ic *interop.Context, v *vm.VM) error { stcInterface := v.Estack().Pop().Value() stc, ok := stcInterface.(*StorageContext) if !ok { return fmt.Errorf("%T is not a StorageContext", stcInterface) } - err := ic.checkStorageContext(stc) + err := checkStorageContext(ic, stc) if err != nil { return err } prefix := string(v.Estack().Pop().Bytes()) - siMap, err := ic.dao.GetStorageItems(stc.ScriptHash) + siMap, err := ic.DAO.GetStorageItems(stc.ScriptHash) if err != nil { return err } @@ -467,8 +468,8 @@ func (ic *interopContext) storageFind(v *vm.VM) error { // createContractStateFromVM pops all contract state elements from the VM // evaluation stack, does a lot of checks and returns Contract if it // succeeds. -func (ic *interopContext) createContractStateFromVM(v *vm.VM) (*state.Contract, error) { - if ic.trigger != trigger.Application { +func createContractStateFromVM(ic *interop.Context, v *vm.VM) (*state.Contract, error) { + if ic.Trigger != trigger.Application { return nil, errors.New("can't create contract when not triggered by an application") } script := v.Estack().Pop().Bytes() @@ -520,15 +521,15 @@ func (ic *interopContext) createContractStateFromVM(v *vm.VM) (*state.Contract, } // contractCreate creates a contract. -func (ic *interopContext) contractCreate(v *vm.VM) error { - newcontract, err := ic.createContractStateFromVM(v) +func contractCreate(ic *interop.Context, v *vm.VM) error { + newcontract, err := createContractStateFromVM(ic, v) if err != nil { return err } - contract, err := ic.dao.GetContractState(newcontract.ScriptHash()) + contract, err := ic.DAO.GetContractState(newcontract.ScriptHash()) if err != nil { contract = newcontract - err := ic.dao.PutContractState(contract) + err := ic.DAO.PutContractState(contract) if err != nil { return err } @@ -538,7 +539,7 @@ func (ic *interopContext) contractCreate(v *vm.VM) error { } // contractGetScript returns a script associated with a contract. -func (ic *interopContext) contractGetScript(v *vm.VM) error { +func contractGetScript(ic *interop.Context, v *vm.VM) error { csInterface := v.Estack().Pop().Value() cs, ok := csInterface.(*state.Contract) if !ok { @@ -549,7 +550,7 @@ func (ic *interopContext) contractGetScript(v *vm.VM) error { } // contractIsPayable returns whether contract is payable. -func (ic *interopContext) contractIsPayable(v *vm.VM) error { +func contractIsPayable(ic *interop.Context, v *vm.VM) error { csInterface := v.Estack().Pop().Value() cs, ok := csInterface.(*state.Contract) if !ok { @@ -560,27 +561,27 @@ func (ic *interopContext) contractIsPayable(v *vm.VM) error { } // contractMigrate migrates a contract. -func (ic *interopContext) contractMigrate(v *vm.VM) error { - newcontract, err := ic.createContractStateFromVM(v) +func contractMigrate(ic *interop.Context, v *vm.VM) error { + newcontract, err := createContractStateFromVM(ic, v) if err != nil { return err } - contract, err := ic.dao.GetContractState(newcontract.ScriptHash()) + contract, err := ic.DAO.GetContractState(newcontract.ScriptHash()) if err != nil { contract = newcontract - err := ic.dao.PutContractState(contract) + err := ic.DAO.PutContractState(contract) if err != nil { return err } if contract.HasStorage() { hash := getContextScriptHash(v, 0) - siMap, err := ic.dao.GetStorageItems(hash) + siMap, err := ic.DAO.GetStorageItems(hash) if err != nil { return err } for k, v := range siMap { v.IsConst = false - err = ic.dao.PutStorageItem(contract.ScriptHash(), []byte(k), v) + err = ic.DAO.PutStorageItem(contract.ScriptHash(), []byte(k), v) if err != nil { return err } @@ -588,12 +589,12 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error { } } v.Estack().PushVal(vm.NewInteropItem(contract)) - return ic.contractDestroy(v) + return contractDestroy(ic, v) } // assetCreate creates an asset. -func (ic *interopContext) assetCreate(v *vm.VM) error { - if ic.trigger != trigger.Application { +func assetCreate(ic *interop.Context, v *vm.VM) error { + if ic.Trigger != trigger.Application { return errors.New("can't create asset when not triggered by an application") } atype := transaction.AssetType(v.Estack().Pop().BigInt().Int64()) @@ -635,7 +636,7 @@ func (ic *interopContext) assetCreate(v *vm.VM) error { if owner.IsInfinity() { return errors.New("can't have infinity as an owner key") } - witnessOk, err := ic.checkKeyedWitness(owner) + witnessOk, err := checkKeyedWitness(ic, owner) if err != nil { return err } @@ -651,7 +652,7 @@ func (ic *interopContext) assetCreate(v *vm.VM) error { return gherr.Wrap(err, "failed to get issuer") } asset := &state.Asset{ - ID: ic.tx.Hash(), + ID: ic.Tx.Hash(), AssetType: atype, Name: name, Amount: amount, @@ -659,9 +660,9 @@ func (ic *interopContext) assetCreate(v *vm.VM) error { Owner: *owner, Admin: admin, Issuer: issuer, - Expiration: ic.bc.BlockHeight() + DefaultAssetLifetime, + Expiration: ic.Chain.BlockHeight() + DefaultAssetLifetime, } - err = ic.dao.PutAssetState(asset) + err = ic.DAO.PutAssetState(asset) if err != nil { return gherr.Wrap(err, "failed to Store asset") } @@ -670,7 +671,7 @@ func (ic *interopContext) assetCreate(v *vm.VM) error { } // assetGetAdmin returns asset admin. -func (ic *interopContext) assetGetAdmin(v *vm.VM) error { +func assetGetAdmin(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -681,7 +682,7 @@ func (ic *interopContext) assetGetAdmin(v *vm.VM) error { } // assetGetAmount returns the overall amount of asset available. -func (ic *interopContext) assetGetAmount(v *vm.VM) error { +func assetGetAmount(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -692,7 +693,7 @@ func (ic *interopContext) assetGetAmount(v *vm.VM) error { } // assetGetAssetId returns the id of an asset. -func (ic *interopContext) assetGetAssetID(v *vm.VM) error { +func assetGetAssetID(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -703,7 +704,7 @@ func (ic *interopContext) assetGetAssetID(v *vm.VM) error { } // assetGetAssetType returns type of an asset. -func (ic *interopContext) assetGetAssetType(v *vm.VM) error { +func assetGetAssetType(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -714,7 +715,7 @@ func (ic *interopContext) assetGetAssetType(v *vm.VM) error { } // assetGetAvailable returns available (not yet issued) amount of asset. -func (ic *interopContext) assetGetAvailable(v *vm.VM) error { +func assetGetAvailable(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -725,7 +726,7 @@ func (ic *interopContext) assetGetAvailable(v *vm.VM) error { } // assetGetIssuer returns issuer of an asset. -func (ic *interopContext) assetGetIssuer(v *vm.VM) error { +func assetGetIssuer(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -736,7 +737,7 @@ func (ic *interopContext) assetGetIssuer(v *vm.VM) error { } // assetGetOwner returns owner of an asset. -func (ic *interopContext) assetGetOwner(v *vm.VM) error { +func assetGetOwner(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -747,7 +748,7 @@ func (ic *interopContext) assetGetOwner(v *vm.VM) error { } // assetGetPrecision returns precision used to measure this asset. -func (ic *interopContext) assetGetPrecision(v *vm.VM) error { +func assetGetPrecision(ic *interop.Context, v *vm.VM) error { asInterface := v.Estack().Pop().Value() as, ok := asInterface.(*state.Asset) if !ok { @@ -758,8 +759,8 @@ func (ic *interopContext) assetGetPrecision(v *vm.VM) error { } // assetRenew updates asset expiration date. -func (ic *interopContext) assetRenew(v *vm.VM) error { - if ic.trigger != trigger.Application { +func assetRenew(ic *interop.Context, v *vm.VM) error { + if ic.Trigger != trigger.Application { return errors.New("can't create asset when not triggered by an application") } asInterface := v.Estack().Pop().Value() @@ -769,19 +770,19 @@ func (ic *interopContext) assetRenew(v *vm.VM) error { } years := byte(v.Estack().Pop().BigInt().Int64()) // Not sure why C# code regets an asset from the Store, but we also do it. - asset, err := ic.dao.GetAssetState(as.ID) + asset, err := ic.DAO.GetAssetState(as.ID) if err != nil { return errors.New("can't renew non-existent asset") } - if asset.Expiration < ic.bc.BlockHeight()+1 { - asset.Expiration = ic.bc.BlockHeight() + 1 + if asset.Expiration < ic.Chain.BlockHeight()+1 { + asset.Expiration = ic.Chain.BlockHeight() + 1 } expiration := uint64(asset.Expiration) + uint64(years)*BlocksPerYear if expiration > math.MaxUint32 { expiration = math.MaxUint32 } asset.Expiration = uint32(expiration) - err = ic.dao.PutAssetState(asset) + err = ic.DAO.PutAssetState(asset) if err != nil { return gherr.Wrap(err, "failed to Store asset") } @@ -790,57 +791,11 @@ func (ic *interopContext) assetRenew(v *vm.VM) error { } // runtimeSerialize serializes top stack item into a ByteArray. -func (ic *interopContext) runtimeSerialize(v *vm.VM) error { +func runtimeSerialize(_ *interop.Context, v *vm.VM) error { return vm.RuntimeSerialize(v) } // runtimeDeserialize deserializes ByteArray from a stack into an item. -func (ic *interopContext) runtimeDeserialize(v *vm.VM) error { +func runtimeDeserialize(_ *interop.Context, v *vm.VM) error { return vm.RuntimeDeserialize(v) } - -// enumeratorConcat concatenates 2 enumerators into a single one. -func (ic *interopContext) enumeratorConcat(v *vm.VM) error { - return vm.EnumeratorConcat(v) -} - -// enumeratorCreate creates an enumerator from an array-like stack item. -func (ic *interopContext) enumeratorCreate(v *vm.VM) error { - return vm.EnumeratorCreate(v) -} - -// enumeratorNext advances the enumerator, pushes true if is it was successful -// and false otherwise. -func (ic *interopContext) enumeratorNext(v *vm.VM) error { - return vm.EnumeratorNext(v) -} - -// enumeratorValue returns the current value of the enumerator. -func (ic *interopContext) enumeratorValue(v *vm.VM) error { - return vm.EnumeratorValue(v) -} - -// iteratorConcat concatenates 2 iterators into a single one. -func (ic *interopContext) iteratorConcat(v *vm.VM) error { - return vm.IteratorConcat(v) -} - -// iteratorCreate creates an iterator from array-like or map stack item. -func (ic *interopContext) iteratorCreate(v *vm.VM) error { - return vm.IteratorCreate(v) -} - -// iteratorKey returns current iterator key. -func (ic *interopContext) iteratorKey(v *vm.VM) error { - return vm.IteratorKey(v) -} - -// iteratorKeys returns keys of the iterator. -func (ic *interopContext) iteratorKeys(v *vm.VM) error { - return vm.IteratorKeys(v) -} - -// iteratorValues returns values of the iterator. -func (ic *interopContext) iteratorValues(v *vm.VM) error { - return vm.IteratorValues(v) -} diff --git a/pkg/core/interop_neo_test.go b/pkg/core/interop_neo_test.go index 135302927..26068690f 100644 --- a/pkg/core/interop_neo_test.go +++ b/pkg/core/interop_neo_test.go @@ -6,6 +6,9 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/dao" + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator" + "github.com/nspcc-dev/neo-go/pkg/core/interop/iterator" "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/core/transaction" @@ -39,7 +42,7 @@ import ( func TestGetTrigger(t *testing.T) { v, _, context, chain := createVMAndPushBlock(t) defer chain.Close() - require.NoError(t, context.runtimeGetTrigger(v)) + require.NoError(t, runtimeGetTrigger(context, v)) } func TestStorageFind(t *testing.T) { @@ -56,12 +59,12 @@ func TestStorageFind(t *testing.T) { }, } - require.NoError(t, context.dao.PutContractState(contractState)) + require.NoError(t, context.DAO.PutContractState(contractState)) scriptHash := contractState.ScriptHash() for i := range skeys { - err := context.dao.PutStorageItem(scriptHash, skeys[i], items[i]) + err := context.DAO.PutStorageItem(scriptHash, skeys[i], items[i]) require.NoError(t, err) } @@ -69,25 +72,25 @@ func TestStorageFind(t *testing.T) { v.Estack().PushVal([]byte{0x01}) v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: scriptHash})) - err := context.storageFind(v) + err := storageFind(context, v) require.NoError(t, err) var iter *vm.InteropItem require.NotPanics(t, func() { iter = v.Estack().Top().Interop() }) - require.NoError(t, context.enumeratorNext(v)) + require.NoError(t, enumerator.Next(context, v)) require.True(t, v.Estack().Pop().Bool()) v.Estack().PushVal(iter) - require.NoError(t, context.iteratorKey(v)) + require.NoError(t, iterator.Key(context, v)) require.Equal(t, []byte{0x01, 0x02}, v.Estack().Pop().Bytes()) v.Estack().PushVal(iter) - require.NoError(t, context.enumeratorValue(v)) + require.NoError(t, enumerator.Value(context, v)) require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, v.Estack().Pop().Bytes()) v.Estack().PushVal(iter) - require.NoError(t, context.enumeratorNext(v)) + require.NoError(t, enumerator.Next(context, v)) require.False(t, v.Estack().Pop().Bool()) }) @@ -95,7 +98,7 @@ func TestStorageFind(t *testing.T) { v.Estack().PushVal([]byte{0x01}) v.Estack().PushVal(vm.NewInteropItem(nil)) - require.Error(t, context.storageFind(v)) + require.Error(t, storageFind(context, v)) }) t.Run("invalid script hash", func(t *testing.T) { @@ -105,7 +108,7 @@ func TestStorageFind(t *testing.T) { v.Estack().PushVal([]byte{0x01}) v.Estack().PushVal(vm.NewInteropItem(&StorageContext{ScriptHash: invalidHash})) - require.Error(t, context.storageFind(v)) + require.Error(t, storageFind(context, v)) }) } @@ -113,7 +116,7 @@ func TestHeaderGetVersion(t *testing.T) { v, block, context, chain := createVMAndPushBlock(t) defer chain.Close() - err := context.headerGetVersion(v) + err := headerGetVersion(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().(*big.Int) require.Equal(t, uint64(block.Version), value.Uint64()) @@ -127,7 +130,7 @@ func TestHeaderGetVersion_Negative(t *testing.T) { context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), block, nil) v.Estack().PushVal(vm.NewBoolItem(false)) - err := context.headerGetVersion(v) + err := headerGetVersion(context, v) require.Errorf(t, err, "value is not a header or block") } @@ -135,7 +138,7 @@ func TestHeaderGetConsensusData(t *testing.T) { v, block, context, chain := createVMAndPushBlock(t) defer chain.Close() - err := context.headerGetConsensusData(v) + err := headerGetConsensusData(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().(*big.Int) require.Equal(t, block.ConsensusData, value.Uint64()) @@ -145,7 +148,7 @@ func TestHeaderGetMerkleRoot(t *testing.T) { v, block, context, chain := createVMAndPushBlock(t) defer chain.Close() - err := context.headerGetMerkleRoot(v) + err := headerGetMerkleRoot(context, v) require.NoError(t, err) value := v.Estack().Pop().Value() require.Equal(t, block.MerkleRoot.BytesBE(), value) @@ -155,7 +158,7 @@ func TestHeaderGetNextConsensus(t *testing.T) { v, block, context, chain := createVMAndPushBlock(t) defer chain.Close() - err := context.headerGetNextConsensus(v) + err := headerGetNextConsensus(context, v) require.NoError(t, err) value := v.Estack().Pop().Value() require.Equal(t, block.NextConsensus.BytesBE(), value) @@ -165,7 +168,7 @@ func TestTxGetAttributes(t *testing.T) { v, tx, context, chain := createVMAndPushTX(t) defer chain.Close() - err := context.txGetAttributes(v) + err := txGetAttributes(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().([]vm.StackItem) require.Equal(t, tx.Attributes[0].Usage, value[0].Value().(*transaction.Attribute).Usage) @@ -175,7 +178,7 @@ func TestTxGetInputs(t *testing.T) { v, tx, context, chain := createVMAndPushTX(t) defer chain.Close() - err := context.txGetInputs(v) + err := txGetInputs(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().([]vm.StackItem) require.Equal(t, tx.Inputs[0], *value[0].Value().(*transaction.Input)) @@ -185,7 +188,7 @@ func TestTxGetOutputs(t *testing.T) { v, tx, context, chain := createVMAndPushTX(t) defer chain.Close() - err := context.txGetOutputs(v) + err := txGetOutputs(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().([]vm.StackItem) require.Equal(t, tx.Outputs[0], *value[0].Value().(*transaction.Output)) @@ -195,7 +198,7 @@ func TestTxGetType(t *testing.T) { v, tx, context, chain := createVMAndPushTX(t) defer chain.Close() - err := context.txGetType(v) + err := txGetType(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().(*big.Int) require.Equal(t, big.NewInt(int64(tx.Type)), value) @@ -205,7 +208,7 @@ func TestInvocationTxGetScript(t *testing.T) { v, tx, context, chain := createVMAndPushTX(t) defer chain.Close() - err := context.invocationTxGetScript(v) + err := invocationTxGetScript(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().([]byte) inv := tx.Data.(*transaction.InvocationTX) @@ -222,7 +225,7 @@ func TestWitnessGetVerificationScript(t *testing.T) { context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), nil, nil) v.Estack().PushVal(vm.NewInteropItem(&witness)) - err := context.witnessGetVerificationScript(v) + err := witnessGetVerificationScript(context, v) require.NoError(t, err) value := v.Estack().Pop().Value().([]byte) require.Equal(t, witness.VerificationScript, value) @@ -243,7 +246,7 @@ func TestInputGetHash(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Inputs[0])) - err := context.inputGetHash(v) + err := inputGetHash(context, v) require.NoError(t, err) hash := v.Estack().Pop().Value() require.Equal(t, tx.Inputs[0].PrevHash.BytesBE(), hash) @@ -254,7 +257,7 @@ func TestInputGetIndex(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Inputs[0])) - err := context.inputGetIndex(v) + err := inputGetIndex(context, v) require.NoError(t, err) index := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(tx.Inputs[0].PrevIndex)), index) @@ -275,7 +278,7 @@ func TestOutputGetAssetID(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0])) - err := context.outputGetAssetID(v) + err := outputGetAssetID(context, v) require.NoError(t, err) assetID := v.Estack().Pop().Value() require.Equal(t, tx.Outputs[0].AssetID.BytesBE(), assetID) @@ -286,7 +289,7 @@ func TestOutputGetScriptHash(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0])) - err := context.outputGetScriptHash(v) + err := outputGetScriptHash(context, v) require.NoError(t, err) scriptHash := v.Estack().Pop().Value() require.Equal(t, tx.Outputs[0].ScriptHash.BytesBE(), scriptHash) @@ -297,7 +300,7 @@ func TestOutputGetValue(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0])) - err := context.outputGetValue(v) + err := outputGetValue(context, v) require.NoError(t, err) amount := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(tx.Outputs[0].Amount)), amount) @@ -308,7 +311,7 @@ func TestAttrGetData(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Attributes[0])) - err := context.attrGetData(v) + err := attrGetData(context, v) require.NoError(t, err) data := v.Estack().Pop().Value() require.Equal(t, tx.Attributes[0].Data, data) @@ -319,7 +322,7 @@ func TestAttrGetUsage(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(&tx.Attributes[0])) - err := context.attrGetUsage(v) + err := attrGetUsage(context, v) require.NoError(t, err) usage := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(tx.Attributes[0].Usage)), usage) @@ -330,7 +333,7 @@ func TestAccountGetScriptHash(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(accState)) - err := context.accountGetScriptHash(v) + err := accountGetScriptHash(context, v) require.NoError(t, err) hash := v.Estack().Pop().Value() require.Equal(t, accState.ScriptHash.BytesBE(), hash) @@ -341,7 +344,7 @@ func TestAccountGetVotes(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(accState)) - err := context.accountGetVotes(v) + err := accountGetVotes(context, v) require.NoError(t, err) votes := v.Estack().Pop().Value().([]vm.StackItem) require.Equal(t, vm.NewByteArrayItem(accState.Votes[0].Bytes()), votes[0]) @@ -352,7 +355,7 @@ func TestContractGetScript(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(contractState)) - err := context.contractGetScript(v) + err := contractGetScript(context, v) require.NoError(t, err) script := v.Estack().Pop().Value() require.Equal(t, contractState.Script, script) @@ -363,7 +366,7 @@ func TestContractIsPayable(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(contractState)) - err := context.contractIsPayable(v) + err := contractIsPayable(context, v) require.NoError(t, err) isPayable := v.Estack().Pop().Value() require.Equal(t, contractState.IsPayable(), isPayable) @@ -374,7 +377,7 @@ func TestAssetGetAdmin(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetAdmin(v) + err := assetGetAdmin(context, v) require.NoError(t, err) admin := v.Estack().Pop().Value() require.Equal(t, assetState.Admin.BytesBE(), admin) @@ -385,7 +388,7 @@ func TestAssetGetAmount(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetAmount(v) + err := assetGetAmount(context, v) require.NoError(t, err) amount := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(assetState.Amount)), amount) @@ -396,7 +399,7 @@ func TestAssetGetAssetID(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetAssetID(v) + err := assetGetAssetID(context, v) require.NoError(t, err) assetID := v.Estack().Pop().Value() require.Equal(t, assetState.ID.BytesBE(), assetID) @@ -407,7 +410,7 @@ func TestAssetGetAssetType(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetAssetType(v) + err := assetGetAssetType(context, v) require.NoError(t, err) assetType := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(assetState.AssetType)), assetType) @@ -418,7 +421,7 @@ func TestAssetGetAvailable(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetAvailable(v) + err := assetGetAvailable(context, v) require.NoError(t, err) available := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(assetState.Available)), available) @@ -429,7 +432,7 @@ func TestAssetGetIssuer(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetIssuer(v) + err := assetGetIssuer(context, v) require.NoError(t, err) issuer := v.Estack().Pop().Value() require.Equal(t, assetState.Issuer.BytesBE(), issuer) @@ -440,7 +443,7 @@ func TestAssetGetOwner(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetOwner(v) + err := assetGetOwner(context, v) require.NoError(t, err) owner := v.Estack().Pop().Value() require.Equal(t, assetState.Owner.Bytes(), owner) @@ -451,7 +454,7 @@ func TestAssetGetPrecision(t *testing.T) { defer chain.Close() v.Estack().PushVal(vm.NewInteropItem(assetState)) - err := context.assetGetPrecision(v) + err := assetGetPrecision(context, v) require.NoError(t, err) precision := v.Estack().Pop().Value() require.Equal(t, big.NewInt(int64(assetState.Precision)), precision) @@ -459,7 +462,7 @@ func TestAssetGetPrecision(t *testing.T) { // Helper functions to create VM, InteropContext, TX, Account, Contract, Asset. -func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interopContext, *Blockchain) { +func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) { v := vm.New() block := newDumbBlock() chain := newTestChain(t) @@ -468,13 +471,13 @@ func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interopContext, return v, block, context, chain } -func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interopContext, *Blockchain) { +func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop.Context, *Blockchain) { v, tx, context, chain := createVMAndTX(t) v.Estack().PushVal(vm.NewInteropItem(tx)) return v, tx, context, chain } -func createVMAndAssetState(t *testing.T) (*vm.VM, *state.Asset, *interopContext, *Blockchain) { +func createVMAndAssetState(t *testing.T) (*vm.VM, *state.Asset, *interop.Context, *Blockchain) { v := vm.New() assetState := &state.Asset{ ID: util.Uint256{}, @@ -497,7 +500,7 @@ func createVMAndAssetState(t *testing.T) (*vm.VM, *state.Asset, *interopContext, return v, assetState, context, chain } -func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interopContext, *Blockchain) { +func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) { v := vm.New() contractState := &state.Contract{ Script: []byte("testscript"), @@ -516,7 +519,7 @@ func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interopCo return v, contractState, context, chain } -func createVMAndAccState(t *testing.T) (*vm.VM, *state.Account, *interopContext, *Blockchain) { +func createVMAndAccState(t *testing.T) (*vm.VM, *state.Account, *interop.Context, *Blockchain) { v := vm.New() rawHash := "4d3b96ae1bcc5a585e075e3b81920210dec16302" hash, err := util.Uint160DecodeStringBE(rawHash) @@ -531,7 +534,7 @@ func createVMAndAccState(t *testing.T) (*vm.VM, *state.Account, *interopContext, return v, accountState, context, chain } -func createVMAndTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interopContext, *Blockchain) { +func createVMAndTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop.Context, *Blockchain) { v := vm.New() script := []byte{byte(opcode.PUSH1), byte(opcode.RET)} tx := transaction.NewInvocationTX(script, 0) diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index f07da9905..bb6816f97 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -6,7 +6,9 @@ import ( "math" "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/interop" "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/keys" @@ -32,7 +34,7 @@ type StorageContext struct { // getBlockHashFromElement converts given vm.Element to block hash using given // Blockchainer if needed. Interop functions accept both block numbers and // block hashes as parameters, thus this function is needed. -func getBlockHashFromElement(bc Blockchainer, element *vm.Element) (util.Uint256, error) { +func getBlockHashFromElement(bc blockchainer.Blockchainer, element *vm.Element) (util.Uint256, error) { var hash util.Uint256 hashbytes := element.Bytes() if len(hashbytes) <= 5 { @@ -48,12 +50,12 @@ func getBlockHashFromElement(bc Blockchainer, element *vm.Element) (util.Uint256 } // bcGetBlock returns current block. -func (ic *interopContext) bcGetBlock(v *vm.VM) error { - hash, err := getBlockHashFromElement(ic.bc, v.Estack().Pop()) +func bcGetBlock(ic *interop.Context, v *vm.VM) error { + hash, err := getBlockHashFromElement(ic.Chain, v.Estack().Pop()) if err != nil { return err } - block, err := ic.bc.GetBlock(hash) + block, err := ic.Chain.GetBlock(hash) if err != nil { v.Estack().PushVal([]byte{}) } else { @@ -63,13 +65,13 @@ func (ic *interopContext) bcGetBlock(v *vm.VM) error { } // bcGetContract returns contract. -func (ic *interopContext) bcGetContract(v *vm.VM) error { +func bcGetContract(ic *interop.Context, v *vm.VM) error { hashbytes := v.Estack().Pop().Bytes() hash, err := util.Uint160DecodeBytesBE(hashbytes) if err != nil { return err } - cs, err := ic.dao.GetContractState(hash) + cs, err := ic.DAO.GetContractState(hash) if err != nil { v.Estack().PushVal([]byte{}) } else { @@ -79,12 +81,12 @@ func (ic *interopContext) bcGetContract(v *vm.VM) error { } // bcGetHeader returns block header. -func (ic *interopContext) bcGetHeader(v *vm.VM) error { - hash, err := getBlockHashFromElement(ic.bc, v.Estack().Pop()) +func bcGetHeader(ic *interop.Context, v *vm.VM) error { + hash, err := getBlockHashFromElement(ic.Chain, v.Estack().Pop()) if err != nil { return err } - header, err := ic.bc.GetHeader(hash) + header, err := ic.Chain.GetHeader(hash) if err != nil { v.Estack().PushVal([]byte{}) } else { @@ -94,8 +96,8 @@ func (ic *interopContext) bcGetHeader(v *vm.VM) error { } // bcGetHeight returns blockchain height. -func (ic *interopContext) bcGetHeight(v *vm.VM) error { - v.Estack().PushVal(ic.bc.BlockHeight()) +func bcGetHeight(ic *interop.Context, v *vm.VM) error { + v.Estack().PushVal(ic.Chain.BlockHeight()) return nil } @@ -111,8 +113,8 @@ func getTransactionAndHeight(cd *dao.Cached, v *vm.VM) (*transaction.Transaction } // bcGetTransaction returns transaction. -func (ic *interopContext) bcGetTransaction(v *vm.VM) error { - tx, _, err := getTransactionAndHeight(ic.dao, v) +func bcGetTransaction(ic *interop.Context, v *vm.VM) error { + tx, _, err := getTransactionAndHeight(ic.DAO, v) if err != nil { return err } @@ -121,8 +123,8 @@ func (ic *interopContext) bcGetTransaction(v *vm.VM) error { } // bcGetTransactionHeight returns transaction height. -func (ic *interopContext) bcGetTransactionHeight(v *vm.VM) error { - _, h, err := getTransactionAndHeight(ic.dao, v) +func bcGetTransactionHeight(ic *interop.Context, v *vm.VM) error { + _, h, err := getTransactionAndHeight(ic.DAO, v) if err != nil { return err } @@ -147,7 +149,7 @@ func popHeaderFromVM(v *vm.VM) (*block.Header, error) { } // headerGetIndex returns block index from the header. -func (ic *interopContext) headerGetIndex(v *vm.VM) error { +func headerGetIndex(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -157,7 +159,7 @@ func (ic *interopContext) headerGetIndex(v *vm.VM) error { } // headerGetHash returns header hash of the passed header. -func (ic *interopContext) headerGetHash(v *vm.VM) error { +func headerGetHash(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -167,7 +169,7 @@ func (ic *interopContext) headerGetHash(v *vm.VM) error { } // headerGetPrevHash returns previous header hash of the passed header. -func (ic *interopContext) headerGetPrevHash(v *vm.VM) error { +func headerGetPrevHash(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -177,7 +179,7 @@ func (ic *interopContext) headerGetPrevHash(v *vm.VM) error { } // headerGetTimestamp returns timestamp of the passed header. -func (ic *interopContext) headerGetTimestamp(v *vm.VM) error { +func headerGetTimestamp(ic *interop.Context, v *vm.VM) error { header, err := popHeaderFromVM(v) if err != nil { return err @@ -187,7 +189,7 @@ func (ic *interopContext) headerGetTimestamp(v *vm.VM) error { } // blockGetTransactionCount returns transactions count in the given block. -func (ic *interopContext) blockGetTransactionCount(v *vm.VM) error { +func blockGetTransactionCount(ic *interop.Context, v *vm.VM) error { blockInterface := v.Estack().Pop().Value() block, ok := blockInterface.(*block.Block) if !ok { @@ -198,7 +200,7 @@ func (ic *interopContext) blockGetTransactionCount(v *vm.VM) error { } // blockGetTransactions returns transactions from the given block. -func (ic *interopContext) blockGetTransactions(v *vm.VM) error { +func blockGetTransactions(ic *interop.Context, v *vm.VM) error { blockInterface := v.Estack().Pop().Value() block, ok := blockInterface.(*block.Block) if !ok { @@ -217,7 +219,7 @@ func (ic *interopContext) blockGetTransactions(v *vm.VM) error { // blockGetTransaction returns transaction with the given number from the given // block. -func (ic *interopContext) blockGetTransaction(v *vm.VM) error { +func blockGetTransaction(ic *interop.Context, v *vm.VM) error { blockInterface := v.Estack().Pop().Value() block, ok := blockInterface.(*block.Block) if !ok { @@ -233,7 +235,7 @@ func (ic *interopContext) blockGetTransaction(v *vm.VM) error { } // txGetHash returns transaction's hash. -func (ic *interopContext) txGetHash(v *vm.VM) error { +func txGetHash(ic *interop.Context, v *vm.VM) error { txInterface := v.Estack().Pop().Value() tx, ok := txInterface.(*transaction.Transaction) if !ok { @@ -245,8 +247,8 @@ func (ic *interopContext) txGetHash(v *vm.VM) error { // engineGetScriptContainer returns transaction that contains the script being // run. -func (ic *interopContext) engineGetScriptContainer(v *vm.VM) error { - v.Estack().PushVal(vm.NewInteropItem(ic.tx)) +func engineGetScriptContainer(ic *interop.Context, v *vm.VM) error { + v.Estack().PushVal(vm.NewInteropItem(ic.Tx)) return nil } @@ -267,36 +269,36 @@ func pushContextScriptHash(v *vm.VM, n int) error { } // engineGetExecutingScriptHash returns executing script hash. -func (ic *interopContext) engineGetExecutingScriptHash(v *vm.VM) error { +func engineGetExecutingScriptHash(ic *interop.Context, v *vm.VM) error { return pushContextScriptHash(v, 0) } // engineGetCallingScriptHash returns calling script hash. -func (ic *interopContext) engineGetCallingScriptHash(v *vm.VM) error { +func engineGetCallingScriptHash(ic *interop.Context, v *vm.VM) error { return pushContextScriptHash(v, 1) } // engineGetEntryScriptHash returns entry script hash. -func (ic *interopContext) engineGetEntryScriptHash(v *vm.VM) error { +func engineGetEntryScriptHash(ic *interop.Context, v *vm.VM) error { return pushContextScriptHash(v, v.Istack().Len()-1) } // runtimePlatform returns the name of the platform. -func (ic *interopContext) runtimePlatform(v *vm.VM) error { +func runtimePlatform(ic *interop.Context, v *vm.VM) error { v.Estack().PushVal([]byte("NEO")) return nil } // runtimeGetTrigger returns the script trigger. -func (ic *interopContext) runtimeGetTrigger(v *vm.VM) error { - v.Estack().PushVal(byte(ic.trigger)) +func runtimeGetTrigger(ic *interop.Context, v *vm.VM) error { + v.Estack().PushVal(byte(ic.Trigger)) return nil } // checkHashedWitness checks given hash against current list of script hashes // for verifying in the interop context. -func (ic *interopContext) checkHashedWitness(hash util.Uint160) (bool, error) { - hashes, err := ic.bc.GetScriptHashesForVerifying(ic.tx) +func checkHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) { + hashes, err := ic.Chain.GetScriptHashesForVerifying(ic.Tx) if err != nil { return false, gherr.Wrap(err, "failed to get script hashes") } @@ -310,12 +312,12 @@ func (ic *interopContext) checkHashedWitness(hash util.Uint160) (bool, error) { // checkKeyedWitness checks hash of signature check contract with a given public // key against current list of script hashes for verifying in the interop context. -func (ic *interopContext) checkKeyedWitness(key *keys.PublicKey) (bool, error) { - return ic.checkHashedWitness(key.GetScriptHash()) +func checkKeyedWitness(ic *interop.Context, key *keys.PublicKey) (bool, error) { + return checkHashedWitness(ic, key.GetScriptHash()) } // runtimeCheckWitness checks witnesses. -func (ic *interopContext) runtimeCheckWitness(v *vm.VM) error { +func runtimeCheckWitness(ic *interop.Context, v *vm.VM) error { var res bool var err error @@ -327,9 +329,9 @@ func (ic *interopContext) runtimeCheckWitness(v *vm.VM) error { if err != nil { return errors.New("parameter given is neither a key nor a hash") } - res, err = ic.checkKeyedWitness(key) + res, err = checkKeyedWitness(ic, key) } else { - res, err = ic.checkHashedWitness(hash) + res, err = checkHashedWitness(ic, hash) } if err != nil { return gherr.Wrap(err, "failed to check") @@ -340,7 +342,7 @@ func (ic *interopContext) runtimeCheckWitness(v *vm.VM) error { // runtimeNotify should pass stack item to the notify plugin to handle it, but // in neo-go the only meaningful thing to do here is to log. -func (ic *interopContext) runtimeNotify(v *vm.VM) error { +func runtimeNotify(ic *interop.Context, v *vm.VM) error { // It can be just about anything. e := v.Estack().Pop() item := e.Item() @@ -354,49 +356,38 @@ func (ic *interopContext) runtimeNotify(v *vm.VM) error { item = vm.NewByteArrayItem([]byte(fmt.Sprintf("bad notification: %v", err))) } ne := state.NotificationEvent{ScriptHash: getContextScriptHash(v, 0), Item: item} - ic.notifications = append(ic.notifications, ne) + ic.Notifications = append(ic.Notifications, ne) return nil } // runtimeLog logs the message passed. -func (ic *interopContext) runtimeLog(v *vm.VM) error { +func runtimeLog(ic *interop.Context, v *vm.VM) error { msg := fmt.Sprintf("%q", v.Estack().Pop().Bytes()) - ic.log.Info("runtime log", + ic.Log.Info("runtime log", zap.Stringer("script", getContextScriptHash(v, 0)), zap.String("logs", msg)) return nil } // runtimeGetTime returns timestamp of the block being verified, or the latest -// one in the blockchain if no block is given to interopContext. -func (ic *interopContext) runtimeGetTime(v *vm.VM) error { +// one in the blockchain if no block is given to Context. +func runtimeGetTime(ic *interop.Context, v *vm.VM) error { var header *block.Header - if ic.block == nil { + if ic.Block == nil { var err error - header, err = ic.bc.GetHeader(ic.bc.CurrentBlockHash()) + header, err = ic.Chain.GetHeader(ic.Chain.CurrentBlockHash()) if err != nil { return err } } else { - header = ic.block.Header() + header = ic.Block.Header() } v.Estack().PushVal(header.Timestamp) return nil } -/* -// runtimeSerialize serializes given stack item. -func (ic *interopContext) runtimeSerialize(v *vm.VM) error { - panic("TODO") -} - -// runtimeDeserialize deserializes given stack item. -func (ic *interopContext) runtimeDeserialize(v *vm.VM) error { - panic("TODO") -} -*/ -func (ic *interopContext) checkStorageContext(stc *StorageContext) error { - contract, err := ic.dao.GetContractState(stc.ScriptHash) +func checkStorageContext(ic *interop.Context, stc *StorageContext) error { + contract, err := ic.DAO.GetContractState(stc.ScriptHash) if err != nil { return errors.New("no contract found") } @@ -407,8 +398,8 @@ func (ic *interopContext) checkStorageContext(stc *StorageContext) error { } // storageDelete deletes stored key-value pair. -func (ic *interopContext) storageDelete(v *vm.VM) error { - if ic.trigger != trigger.Application && ic.trigger != trigger.ApplicationR { +func storageDelete(ic *interop.Context, v *vm.VM) error { + if ic.Trigger != trigger.Application && ic.Trigger != trigger.ApplicationR { return errors.New("can't delete when the trigger is not application") } stcInterface := v.Estack().Pop().Value() @@ -419,31 +410,31 @@ func (ic *interopContext) storageDelete(v *vm.VM) error { if stc.ReadOnly { return errors.New("StorageContext is read only") } - err := ic.checkStorageContext(stc) + err := checkStorageContext(ic, stc) if err != nil { return err } key := v.Estack().Pop().Bytes() - si := ic.dao.GetStorageItem(stc.ScriptHash, key) + si := ic.DAO.GetStorageItem(stc.ScriptHash, key) if si != nil && si.IsConst { return errors.New("storage item is constant") } - return ic.dao.DeleteStorageItem(stc.ScriptHash, key) + return ic.DAO.DeleteStorageItem(stc.ScriptHash, key) } // storageGet returns stored key-value pair. -func (ic *interopContext) storageGet(v *vm.VM) error { +func storageGet(ic *interop.Context, v *vm.VM) error { stcInterface := v.Estack().Pop().Value() stc, ok := stcInterface.(*StorageContext) if !ok { return fmt.Errorf("%T is not a StorageContext", stcInterface) } - err := ic.checkStorageContext(stc) + err := checkStorageContext(ic, stc) if err != nil { return err } key := v.Estack().Pop().Bytes() - si := ic.dao.GetStorageItem(stc.ScriptHash, key) + si := ic.DAO.GetStorageItem(stc.ScriptHash, key) if si != nil && si.Value != nil { v.Estack().PushVal(si.Value) } else { @@ -453,7 +444,7 @@ func (ic *interopContext) storageGet(v *vm.VM) error { } // storageGetContext returns storage context (scripthash). -func (ic *interopContext) storageGetContext(v *vm.VM) error { +func storageGetContext(ic *interop.Context, v *vm.VM) error { sc := &StorageContext{ ScriptHash: getContextScriptHash(v, 0), ReadOnly: false, @@ -463,7 +454,7 @@ func (ic *interopContext) storageGetContext(v *vm.VM) error { } // storageGetReadOnlyContext returns read-only context (scripthash). -func (ic *interopContext) storageGetReadOnlyContext(v *vm.VM) error { +func storageGetReadOnlyContext(ic *interop.Context, v *vm.VM) error { sc := &StorageContext{ ScriptHash: getContextScriptHash(v, 0), ReadOnly: true, @@ -472,8 +463,8 @@ func (ic *interopContext) storageGetReadOnlyContext(v *vm.VM) error { return nil } -func (ic *interopContext) putWithContextAndFlags(stc *StorageContext, key []byte, value []byte, isConst bool) error { - if ic.trigger != trigger.Application && ic.trigger != trigger.ApplicationR { +func putWithContextAndFlags(ic *interop.Context, stc *StorageContext, key []byte, value []byte, isConst bool) error { + if ic.Trigger != trigger.Application && ic.Trigger != trigger.ApplicationR { return errors.New("can't delete when the trigger is not application") } if len(key) > MaxStorageKeyLen { @@ -482,11 +473,11 @@ func (ic *interopContext) putWithContextAndFlags(stc *StorageContext, key []byte if stc.ReadOnly { return errors.New("StorageContext is read only") } - err := ic.checkStorageContext(stc) + err := checkStorageContext(ic, stc) if err != nil { return err } - si := ic.dao.GetStorageItem(stc.ScriptHash, key) + si := ic.DAO.GetStorageItem(stc.ScriptHash, key) if si == nil { si = &state.StorageItem{} } @@ -495,11 +486,11 @@ func (ic *interopContext) putWithContextAndFlags(stc *StorageContext, key []byte } si.Value = value si.IsConst = isConst - return ic.dao.PutStorageItem(stc.ScriptHash, key, si) + return ic.DAO.PutStorageItem(stc.ScriptHash, key, si) } // storagePutInternal is a unified implementation of storagePut and storagePutEx. -func (ic *interopContext) storagePutInternal(v *vm.VM, getFlag bool) error { +func storagePutInternal(ic *interop.Context, v *vm.VM, getFlag bool) error { stcInterface := v.Estack().Pop().Value() stc, ok := stcInterface.(*StorageContext) if !ok { @@ -511,21 +502,21 @@ func (ic *interopContext) storagePutInternal(v *vm.VM, getFlag bool) error { if getFlag { flag = int(v.Estack().Pop().BigInt().Int64()) } - return ic.putWithContextAndFlags(stc, key, value, flag == 1) + return putWithContextAndFlags(ic, stc, key, value, flag == 1) } // storagePut puts key-value pair into the storage. -func (ic *interopContext) storagePut(v *vm.VM) error { - return ic.storagePutInternal(v, false) +func storagePut(ic *interop.Context, v *vm.VM) error { + return storagePutInternal(ic, v, false) } // storagePutEx puts key-value pair with given flags into the storage. -func (ic *interopContext) storagePutEx(v *vm.VM) error { - return ic.storagePutInternal(v, true) +func storagePutEx(ic *interop.Context, v *vm.VM) error { + return storagePutInternal(ic, v, true) } // storageContextAsReadOnly sets given context to read-only mode. -func (ic *interopContext) storageContextAsReadOnly(v *vm.VM) error { +func storageContextAsReadOnly(ic *interop.Context, v *vm.VM) error { stcInterface := v.Estack().Pop().Value() stc, ok := stcInterface.(*StorageContext) if !ok { @@ -543,39 +534,39 @@ func (ic *interopContext) storageContextAsReadOnly(v *vm.VM) error { } // contractDestroy destroys a contract. -func (ic *interopContext) contractDestroy(v *vm.VM) error { - if ic.trigger != trigger.Application { +func contractDestroy(ic *interop.Context, v *vm.VM) error { + if ic.Trigger != trigger.Application { return errors.New("can't destroy contract when not triggered by application") } hash := getContextScriptHash(v, 0) - cs, err := ic.dao.GetContractState(hash) + cs, err := ic.DAO.GetContractState(hash) if err != nil { return nil } - err = ic.dao.DeleteContractState(hash) + err = ic.DAO.DeleteContractState(hash) if err != nil { return err } if cs.HasStorage() { - siMap, err := ic.dao.GetStorageItems(hash) + siMap, err := ic.DAO.GetStorageItems(hash) if err != nil { return err } for k := range siMap { - _ = ic.dao.DeleteStorageItem(hash, []byte(k)) + _ = ic.DAO.DeleteStorageItem(hash, []byte(k)) } } return nil } // contractGetStorageContext retrieves StorageContext of a contract. -func (ic *interopContext) contractGetStorageContext(v *vm.VM) error { +func contractGetStorageContext(ic *interop.Context, v *vm.VM) error { csInterface := v.Estack().Pop().Value() cs, ok := csInterface.(*state.Contract) if !ok { return fmt.Errorf("%T is not a contract state", cs) } - contractState, err := ic.dao.GetContractState(cs.ScriptHash()) + contractState, err := ic.DAO.GetContractState(cs.ScriptHash()) if contractState == nil || err != nil { return fmt.Errorf("contract was not created in this transaction") } diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 445be4d76..edcdb3310 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -10,274 +10,246 @@ package core import ( "sort" - "github.com/nspcc-dev/neo-go/pkg/core/block" - "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" + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator" + "github.com/nspcc-dev/neo-go/pkg/core/interop/iterator" "github.com/nspcc-dev/neo-go/pkg/smartcontract" - "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" - "go.uber.org/zap" ) -type interopContext struct { - bc Blockchainer - trigger trigger.Type - block *block.Block - tx *transaction.Transaction - dao *dao.Cached - notifications []state.NotificationEvent - log *zap.Logger -} - -func newInteropContext(trigger trigger.Type, bc Blockchainer, d dao.DAO, block *block.Block, tx *transaction.Transaction, log *zap.Logger) *interopContext { - dao := dao.NewCached(d) - nes := make([]state.NotificationEvent, 0) - return &interopContext{bc, trigger, block, tx, dao, nes, log} -} - // SpawnVM returns a VM with script getter and interop functions set // up for current blockchain. -func (ic *interopContext) SpawnVM() *vm.VM { +func SpawnVM(ic *interop.Context) *vm.VM { vm := vm.New() vm.SetScriptGetter(func(hash util.Uint160) ([]byte, bool) { - cs, err := ic.dao.GetContractState(hash) + cs, err := ic.DAO.GetContractState(hash) if err != nil { return nil, false } hasDynamicInvoke := (cs.Properties & smartcontract.HasDynamicInvoke) != 0 return cs.Script, hasDynamicInvoke }) - vm.RegisterInteropGetter(ic.getSystemInterop) - vm.RegisterInteropGetter(ic.getNeoInterop) + vm.RegisterInteropGetter(getSystemInterop(ic)) + vm.RegisterInteropGetter(getNeoInterop(ic)) return vm } -// interopedFunction 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 interopedFunction struct { - ID uint32 - Name string - Func func(*interopContext, *vm.VM) error - Price int -} - // getSystemInterop returns matching interop function from the System namespace // for a given id in the current context. -func (ic *interopContext) getSystemInterop(id uint32) *vm.InteropFuncPrice { - return ic.getInteropFromSlice(id, systemInterops) +func getSystemInterop(ic *interop.Context) vm.InteropGetterFunc { + return getInteropFromSlice(ic, systemInterops) } // getNeoInterop returns matching interop function from the Neo and AntShares // namespaces for a given id in the current context. -func (ic *interopContext) getNeoInterop(id uint32) *vm.InteropFuncPrice { - return ic.getInteropFromSlice(id, neoInterops) +func getNeoInterop(ic *interop.Context) vm.InteropGetterFunc { + return getInteropFromSlice(ic, neoInterops) } // getInteropFromSlice returns matching interop function from the given slice of // interop functions in the current context. -func (ic *interopContext) getInteropFromSlice(id uint32, slice []interopedFunction) *vm.InteropFuncPrice { - n := sort.Search(len(slice), func(i int) bool { - return slice[i].ID >= id - }) - if n < len(slice) && slice[n].ID == id { - // Currying, yay! - return &vm.InteropFuncPrice{Func: func(v *vm.VM) error { - return slice[n].Func(ic, v) - }, Price: slice[n].Price} +func getInteropFromSlice(ic *interop.Context, slice []interop.Function) func(uint32) *vm.InteropFuncPrice { + return func(id uint32) *vm.InteropFuncPrice { + n := sort.Search(len(slice), func(i int) bool { + return slice[i].ID >= id + }) + if n < len(slice) && slice[n].ID == id { + return &vm.InteropFuncPrice{Func: func(v *vm.VM) error { + return slice[n].Func(ic, v) + }, Price: slice[n].Price} + } + return nil } - return nil } // All lists are sorted, keep 'em this way, please. -var systemInterops = []interopedFunction{ - {Name: "System.Block.GetTransaction", Func: (*interopContext).blockGetTransaction, Price: 1}, - {Name: "System.Block.GetTransactionCount", Func: (*interopContext).blockGetTransactionCount, Price: 1}, - {Name: "System.Block.GetTransactions", Func: (*interopContext).blockGetTransactions, Price: 1}, - {Name: "System.Blockchain.GetBlock", Func: (*interopContext).bcGetBlock, Price: 200}, - {Name: "System.Blockchain.GetContract", Func: (*interopContext).bcGetContract, Price: 100}, - {Name: "System.Blockchain.GetHeader", Func: (*interopContext).bcGetHeader, Price: 100}, - {Name: "System.Blockchain.GetHeight", Func: (*interopContext).bcGetHeight, Price: 1}, - {Name: "System.Blockchain.GetTransaction", Func: (*interopContext).bcGetTransaction, Price: 200}, - {Name: "System.Blockchain.GetTransactionHeight", Func: (*interopContext).bcGetTransactionHeight, Price: 100}, - {Name: "System.Contract.Destroy", Func: (*interopContext).contractDestroy, Price: 1}, - {Name: "System.Contract.GetStorageContext", Func: (*interopContext).contractGetStorageContext, Price: 1}, - {Name: "System.ExecutionEngine.GetCallingScriptHash", Func: (*interopContext).engineGetCallingScriptHash, Price: 1}, - {Name: "System.ExecutionEngine.GetEntryScriptHash", Func: (*interopContext).engineGetEntryScriptHash, Price: 1}, - {Name: "System.ExecutionEngine.GetExecutingScriptHash", Func: (*interopContext).engineGetExecutingScriptHash, Price: 1}, - {Name: "System.ExecutionEngine.GetScriptContainer", Func: (*interopContext).engineGetScriptContainer, Price: 1}, - {Name: "System.Header.GetHash", Func: (*interopContext).headerGetHash, Price: 1}, - {Name: "System.Header.GetIndex", Func: (*interopContext).headerGetIndex, Price: 1}, - {Name: "System.Header.GetPrevHash", Func: (*interopContext).headerGetPrevHash, Price: 1}, - {Name: "System.Header.GetTimestamp", Func: (*interopContext).headerGetTimestamp, Price: 1}, - {Name: "System.Runtime.CheckWitness", Func: (*interopContext).runtimeCheckWitness, Price: 200}, - {Name: "System.Runtime.Deserialize", Func: (*interopContext).runtimeDeserialize, Price: 1}, - {Name: "System.Runtime.GetTime", Func: (*interopContext).runtimeGetTime, Price: 1}, - {Name: "System.Runtime.GetTrigger", Func: (*interopContext).runtimeGetTrigger, Price: 1}, - {Name: "System.Runtime.Log", Func: (*interopContext).runtimeLog, Price: 1}, - {Name: "System.Runtime.Notify", Func: (*interopContext).runtimeNotify, Price: 1}, - {Name: "System.Runtime.Platform", Func: (*interopContext).runtimePlatform, Price: 1}, - {Name: "System.Runtime.Serialize", Func: (*interopContext).runtimeSerialize, Price: 1}, - {Name: "System.Storage.Delete", Func: (*interopContext).storageDelete, Price: 100}, - {Name: "System.Storage.Get", Func: (*interopContext).storageGet, Price: 100}, - {Name: "System.Storage.GetContext", Func: (*interopContext).storageGetContext, Price: 1}, - {Name: "System.Storage.GetReadOnlyContext", Func: (*interopContext).storageGetReadOnlyContext, Price: 1}, - {Name: "System.Storage.Put", Func: (*interopContext).storagePut, Price: 0}, // These don't have static price in C# code. - {Name: "System.Storage.PutEx", Func: (*interopContext).storagePutEx, Price: 0}, - {Name: "System.StorageContext.AsReadOnly", Func: (*interopContext).storageContextAsReadOnly, Price: 1}, - {Name: "System.Transaction.GetHash", Func: (*interopContext).txGetHash, Price: 1}, +var systemInterops = []interop.Function{ + {Name: "System.Block.GetTransaction", Func: blockGetTransaction, Price: 1}, + {Name: "System.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1}, + {Name: "System.Block.GetTransactions", Func: blockGetTransactions, Price: 1}, + {Name: "System.Blockchain.GetBlock", Func: bcGetBlock, Price: 200}, + {Name: "System.Blockchain.GetContract", Func: bcGetContract, Price: 100}, + {Name: "System.Blockchain.GetHeader", Func: bcGetHeader, Price: 100}, + {Name: "System.Blockchain.GetHeight", Func: bcGetHeight, Price: 1}, + {Name: "System.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 200}, + {Name: "System.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100}, + {Name: "System.Contract.Destroy", Func: contractDestroy, Price: 1}, + {Name: "System.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1}, + {Name: "System.ExecutionEngine.GetCallingScriptHash", Func: engineGetCallingScriptHash, Price: 1}, + {Name: "System.ExecutionEngine.GetEntryScriptHash", Func: engineGetEntryScriptHash, Price: 1}, + {Name: "System.ExecutionEngine.GetExecutingScriptHash", Func: engineGetExecutingScriptHash, Price: 1}, + {Name: "System.ExecutionEngine.GetScriptContainer", Func: engineGetScriptContainer, Price: 1}, + {Name: "System.Header.GetHash", Func: headerGetHash, Price: 1}, + {Name: "System.Header.GetIndex", Func: headerGetIndex, Price: 1}, + {Name: "System.Header.GetPrevHash", Func: headerGetPrevHash, Price: 1}, + {Name: "System.Header.GetTimestamp", Func: headerGetTimestamp, Price: 1}, + {Name: "System.Runtime.CheckWitness", Func: runtimeCheckWitness, Price: 200}, + {Name: "System.Runtime.Deserialize", Func: runtimeDeserialize, Price: 1}, + {Name: "System.Runtime.GetTime", Func: runtimeGetTime, Price: 1}, + {Name: "System.Runtime.GetTrigger", Func: runtimeGetTrigger, Price: 1}, + {Name: "System.Runtime.Log", Func: runtimeLog, Price: 1}, + {Name: "System.Runtime.Notify", Func: runtimeNotify, Price: 1}, + {Name: "System.Runtime.Platform", Func: runtimePlatform, Price: 1}, + {Name: "System.Runtime.Serialize", Func: runtimeSerialize, Price: 1}, + {Name: "System.Storage.Delete", Func: storageDelete, Price: 100}, + {Name: "System.Storage.Get", Func: storageGet, Price: 100}, + {Name: "System.Storage.GetContext", Func: storageGetContext, Price: 1}, + {Name: "System.Storage.GetReadOnlyContext", Func: storageGetReadOnlyContext, Price: 1}, + {Name: "System.Storage.Put", Func: storagePut, Price: 0}, // These don't have static price in C# code. + {Name: "System.Storage.PutEx", Func: storagePutEx, Price: 0}, + {Name: "System.StorageContext.AsReadOnly", Func: storageContextAsReadOnly, Price: 1}, + {Name: "System.Transaction.GetHash", Func: txGetHash, Price: 1}, } -var neoInterops = []interopedFunction{ - {Name: "Neo.Account.GetBalance", Func: (*interopContext).accountGetBalance, Price: 1}, - {Name: "Neo.Account.GetScriptHash", Func: (*interopContext).accountGetScriptHash, Price: 1}, - {Name: "Neo.Account.GetVotes", Func: (*interopContext).accountGetVotes, Price: 1}, - {Name: "Neo.Account.IsStandard", Func: (*interopContext).accountIsStandard, Price: 100}, - {Name: "Neo.Asset.Create", Func: (*interopContext).assetCreate, Price: 0}, - {Name: "Neo.Asset.GetAdmin", Func: (*interopContext).assetGetAdmin, Price: 1}, - {Name: "Neo.Asset.GetAmount", Func: (*interopContext).assetGetAmount, Price: 1}, - {Name: "Neo.Asset.GetAssetId", Func: (*interopContext).assetGetAssetID, Price: 1}, - {Name: "Neo.Asset.GetAssetType", Func: (*interopContext).assetGetAssetType, Price: 1}, - {Name: "Neo.Asset.GetAvailable", Func: (*interopContext).assetGetAvailable, Price: 1}, - {Name: "Neo.Asset.GetIssuer", Func: (*interopContext).assetGetIssuer, Price: 1}, - {Name: "Neo.Asset.GetOwner", Func: (*interopContext).assetGetOwner, Price: 1}, - {Name: "Neo.Asset.GetPrecision", Func: (*interopContext).assetGetPrecision, Price: 1}, - {Name: "Neo.Asset.Renew", Func: (*interopContext).assetRenew, Price: 0}, - {Name: "Neo.Attribute.GetData", Func: (*interopContext).attrGetData, Price: 1}, - {Name: "Neo.Attribute.GetUsage", Func: (*interopContext).attrGetUsage, Price: 1}, - {Name: "Neo.Block.GetTransaction", Func: (*interopContext).blockGetTransaction, Price: 1}, - {Name: "Neo.Block.GetTransactionCount", Func: (*interopContext).blockGetTransactionCount, Price: 1}, - {Name: "Neo.Block.GetTransactions", Func: (*interopContext).blockGetTransactions, Price: 1}, - {Name: "Neo.Blockchain.GetAccount", Func: (*interopContext).bcGetAccount, Price: 100}, - {Name: "Neo.Blockchain.GetAsset", Func: (*interopContext).bcGetAsset, Price: 100}, - {Name: "Neo.Blockchain.GetBlock", Func: (*interopContext).bcGetBlock, Price: 200}, - {Name: "Neo.Blockchain.GetContract", Func: (*interopContext).bcGetContract, Price: 100}, - {Name: "Neo.Blockchain.GetHeader", Func: (*interopContext).bcGetHeader, Price: 100}, - {Name: "Neo.Blockchain.GetHeight", Func: (*interopContext).bcGetHeight, Price: 1}, - {Name: "Neo.Blockchain.GetTransaction", Func: (*interopContext).bcGetTransaction, Price: 100}, - {Name: "Neo.Blockchain.GetTransactionHeight", Func: (*interopContext).bcGetTransactionHeight, Price: 100}, - {Name: "Neo.Blockchain.GetValidators", Func: (*interopContext).bcGetValidators, Price: 200}, - {Name: "Neo.Contract.Create", Func: (*interopContext).contractCreate, Price: 0}, - {Name: "Neo.Contract.Destroy", Func: (*interopContext).contractDestroy, Price: 1}, - {Name: "Neo.Contract.GetScript", Func: (*interopContext).contractGetScript, Price: 1}, - {Name: "Neo.Contract.GetStorageContext", Func: (*interopContext).contractGetStorageContext, Price: 1}, - {Name: "Neo.Contract.IsPayable", Func: (*interopContext).contractIsPayable, Price: 1}, - {Name: "Neo.Contract.Migrate", Func: (*interopContext).contractMigrate, Price: 0}, - {Name: "Neo.Enumerator.Concat", Func: (*interopContext).enumeratorConcat, Price: 1}, - {Name: "Neo.Enumerator.Create", Func: (*interopContext).enumeratorCreate, Price: 1}, - {Name: "Neo.Enumerator.Next", Func: (*interopContext).enumeratorNext, Price: 1}, - {Name: "Neo.Enumerator.Value", Func: (*interopContext).enumeratorValue, Price: 1}, - {Name: "Neo.Header.GetConsensusData", Func: (*interopContext).headerGetConsensusData, Price: 1}, - {Name: "Neo.Header.GetHash", Func: (*interopContext).headerGetHash, Price: 1}, - {Name: "Neo.Header.GetIndex", Func: (*interopContext).headerGetIndex, Price: 1}, - {Name: "Neo.Header.GetMerkleRoot", Func: (*interopContext).headerGetMerkleRoot, Price: 1}, - {Name: "Neo.Header.GetNextConsensus", Func: (*interopContext).headerGetNextConsensus, Price: 1}, - {Name: "Neo.Header.GetPrevHash", Func: (*interopContext).headerGetPrevHash, Price: 1}, - {Name: "Neo.Header.GetTimestamp", Func: (*interopContext).headerGetTimestamp, Price: 1}, - {Name: "Neo.Header.GetVersion", Func: (*interopContext).headerGetVersion, Price: 1}, - {Name: "Neo.Input.GetHash", Func: (*interopContext).inputGetHash, Price: 1}, - {Name: "Neo.Input.GetIndex", Func: (*interopContext).inputGetIndex, Price: 1}, - {Name: "Neo.InvocationTransaction.GetScript", Func: (*interopContext).invocationTxGetScript, Price: 1}, - {Name: "Neo.Iterator.Concat", Func: (*interopContext).iteratorConcat, Price: 1}, - {Name: "Neo.Iterator.Create", Func: (*interopContext).iteratorCreate, Price: 1}, - {Name: "Neo.Iterator.Key", Func: (*interopContext).iteratorKey, Price: 1}, - {Name: "Neo.Iterator.Keys", Func: (*interopContext).iteratorKeys, Price: 1}, - {Name: "Neo.Iterator.Values", Func: (*interopContext).iteratorValues, Price: 1}, - {Name: "Neo.Output.GetAssetId", Func: (*interopContext).outputGetAssetID, Price: 1}, - {Name: "Neo.Output.GetScriptHash", Func: (*interopContext).outputGetScriptHash, Price: 1}, - {Name: "Neo.Output.GetValue", Func: (*interopContext).outputGetValue, Price: 1}, - {Name: "Neo.Runtime.CheckWitness", Func: (*interopContext).runtimeCheckWitness, Price: 200}, - {Name: "Neo.Runtime.Deserialize", Func: (*interopContext).runtimeDeserialize, Price: 1}, - {Name: "Neo.Runtime.GetTime", Func: (*interopContext).runtimeGetTime, Price: 1}, - {Name: "Neo.Runtime.GetTrigger", Func: (*interopContext).runtimeGetTrigger, Price: 1}, - {Name: "Neo.Runtime.Log", Func: (*interopContext).runtimeLog, Price: 1}, - {Name: "Neo.Runtime.Notify", Func: (*interopContext).runtimeNotify, Price: 1}, - {Name: "Neo.Runtime.Serialize", Func: (*interopContext).runtimeSerialize, Price: 1}, - {Name: "Neo.Storage.Delete", Func: (*interopContext).storageDelete, Price: 100}, - {Name: "Neo.Storage.Find", Func: (*interopContext).storageFind, Price: 1}, - {Name: "Neo.Storage.Get", Func: (*interopContext).storageGet, Price: 100}, - {Name: "Neo.Storage.GetContext", Func: (*interopContext).storageGetContext, Price: 1}, - {Name: "Neo.Storage.GetReadOnlyContext", Func: (*interopContext).storageGetReadOnlyContext, Price: 1}, - {Name: "Neo.Storage.Put", Func: (*interopContext).storagePut, Price: 0}, - {Name: "Neo.StorageContext.AsReadOnly", Func: (*interopContext).storageContextAsReadOnly, Price: 1}, - {Name: "Neo.Transaction.GetAttributes", Func: (*interopContext).txGetAttributes, Price: 1}, - {Name: "Neo.Transaction.GetHash", Func: (*interopContext).txGetHash, Price: 1}, - {Name: "Neo.Transaction.GetInputs", Func: (*interopContext).txGetInputs, Price: 1}, - {Name: "Neo.Transaction.GetOutputs", Func: (*interopContext).txGetOutputs, Price: 1}, - {Name: "Neo.Transaction.GetReferences", Func: (*interopContext).txGetReferences, Price: 200}, - {Name: "Neo.Transaction.GetType", Func: (*interopContext).txGetType, Price: 1}, - {Name: "Neo.Transaction.GetUnspentCoins", Func: (*interopContext).txGetUnspentCoins, Price: 200}, - {Name: "Neo.Transaction.GetWitnesses", Func: (*interopContext).txGetWitnesses, Price: 200}, - {Name: "Neo.Witness.GetVerificationScript", Func: (*interopContext).witnessGetVerificationScript, Price: 100}, +var neoInterops = []interop.Function{ + {Name: "Neo.Account.GetBalance", Func: accountGetBalance, Price: 1}, + {Name: "Neo.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1}, + {Name: "Neo.Account.GetVotes", Func: accountGetVotes, Price: 1}, + {Name: "Neo.Account.IsStandard", Func: accountIsStandard, Price: 100}, + {Name: "Neo.Asset.Create", Func: assetCreate, Price: 0}, + {Name: "Neo.Asset.GetAdmin", Func: assetGetAdmin, Price: 1}, + {Name: "Neo.Asset.GetAmount", Func: assetGetAmount, Price: 1}, + {Name: "Neo.Asset.GetAssetId", Func: assetGetAssetID, Price: 1}, + {Name: "Neo.Asset.GetAssetType", Func: assetGetAssetType, Price: 1}, + {Name: "Neo.Asset.GetAvailable", Func: assetGetAvailable, Price: 1}, + {Name: "Neo.Asset.GetIssuer", Func: assetGetIssuer, Price: 1}, + {Name: "Neo.Asset.GetOwner", Func: assetGetOwner, Price: 1}, + {Name: "Neo.Asset.GetPrecision", Func: assetGetPrecision, Price: 1}, + {Name: "Neo.Asset.Renew", Func: assetRenew, Price: 0}, + {Name: "Neo.Attribute.GetData", Func: attrGetData, Price: 1}, + {Name: "Neo.Attribute.GetUsage", Func: attrGetUsage, Price: 1}, + {Name: "Neo.Block.GetTransaction", Func: blockGetTransaction, Price: 1}, + {Name: "Neo.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1}, + {Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1}, + {Name: "Neo.Blockchain.GetAccount", Func: bcGetAccount, Price: 100}, + {Name: "Neo.Blockchain.GetAsset", Func: bcGetAsset, Price: 100}, + {Name: "Neo.Blockchain.GetBlock", Func: bcGetBlock, Price: 200}, + {Name: "Neo.Blockchain.GetContract", Func: bcGetContract, Price: 100}, + {Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100}, + {Name: "Neo.Blockchain.GetHeight", Func: bcGetHeight, Price: 1}, + {Name: "Neo.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100}, + {Name: "Neo.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100}, + {Name: "Neo.Blockchain.GetValidators", Func: bcGetValidators, Price: 200}, + {Name: "Neo.Contract.Create", Func: contractCreate, Price: 0}, + {Name: "Neo.Contract.Destroy", Func: contractDestroy, Price: 1}, + {Name: "Neo.Contract.GetScript", Func: contractGetScript, Price: 1}, + {Name: "Neo.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1}, + {Name: "Neo.Contract.IsPayable", Func: contractIsPayable, Price: 1}, + {Name: "Neo.Contract.Migrate", Func: contractMigrate, Price: 0}, + {Name: "Neo.Enumerator.Concat", Func: enumerator.Concat, Price: 1}, + {Name: "Neo.Enumerator.Create", Func: enumerator.Create, Price: 1}, + {Name: "Neo.Enumerator.Next", Func: enumerator.Next, Price: 1}, + {Name: "Neo.Enumerator.Value", Func: enumerator.Value, Price: 1}, + {Name: "Neo.Header.GetConsensusData", Func: headerGetConsensusData, Price: 1}, + {Name: "Neo.Header.GetHash", Func: headerGetHash, Price: 1}, + {Name: "Neo.Header.GetIndex", Func: headerGetIndex, Price: 1}, + {Name: "Neo.Header.GetMerkleRoot", Func: headerGetMerkleRoot, Price: 1}, + {Name: "Neo.Header.GetNextConsensus", Func: headerGetNextConsensus, Price: 1}, + {Name: "Neo.Header.GetPrevHash", Func: headerGetPrevHash, Price: 1}, + {Name: "Neo.Header.GetTimestamp", Func: headerGetTimestamp, Price: 1}, + {Name: "Neo.Header.GetVersion", Func: headerGetVersion, Price: 1}, + {Name: "Neo.Input.GetHash", Func: inputGetHash, Price: 1}, + {Name: "Neo.Input.GetIndex", Func: inputGetIndex, Price: 1}, + {Name: "Neo.InvocationTransaction.GetScript", Func: invocationTxGetScript, Price: 1}, + {Name: "Neo.Iterator.Concat", Func: iterator.Concat, Price: 1}, + {Name: "Neo.Iterator.Create", Func: iterator.Create, Price: 1}, + {Name: "Neo.Iterator.Key", Func: iterator.Key, Price: 1}, + {Name: "Neo.Iterator.Keys", Func: iterator.Keys, Price: 1}, + {Name: "Neo.Iterator.Values", Func: iterator.Values, Price: 1}, + {Name: "Neo.Output.GetAssetId", Func: outputGetAssetID, Price: 1}, + {Name: "Neo.Output.GetScriptHash", Func: outputGetScriptHash, Price: 1}, + {Name: "Neo.Output.GetValue", Func: outputGetValue, Price: 1}, + {Name: "Neo.Runtime.CheckWitness", Func: runtimeCheckWitness, Price: 200}, + {Name: "Neo.Runtime.Deserialize", Func: runtimeDeserialize, Price: 1}, + {Name: "Neo.Runtime.GetTime", Func: runtimeGetTime, Price: 1}, + {Name: "Neo.Runtime.GetTrigger", Func: runtimeGetTrigger, Price: 1}, + {Name: "Neo.Runtime.Log", Func: runtimeLog, Price: 1}, + {Name: "Neo.Runtime.Notify", Func: runtimeNotify, Price: 1}, + {Name: "Neo.Runtime.Serialize", Func: runtimeSerialize, Price: 1}, + {Name: "Neo.Storage.Delete", Func: storageDelete, Price: 100}, + {Name: "Neo.Storage.Find", Func: storageFind, Price: 1}, + {Name: "Neo.Storage.Get", Func: storageGet, Price: 100}, + {Name: "Neo.Storage.GetContext", Func: storageGetContext, Price: 1}, + {Name: "Neo.Storage.GetReadOnlyContext", Func: storageGetReadOnlyContext, Price: 1}, + {Name: "Neo.Storage.Put", Func: storagePut, Price: 0}, + {Name: "Neo.StorageContext.AsReadOnly", Func: storageContextAsReadOnly, Price: 1}, + {Name: "Neo.Transaction.GetAttributes", Func: txGetAttributes, Price: 1}, + {Name: "Neo.Transaction.GetHash", Func: txGetHash, Price: 1}, + {Name: "Neo.Transaction.GetInputs", Func: txGetInputs, Price: 1}, + {Name: "Neo.Transaction.GetOutputs", Func: txGetOutputs, Price: 1}, + {Name: "Neo.Transaction.GetReferences", Func: txGetReferences, Price: 200}, + {Name: "Neo.Transaction.GetType", Func: txGetType, Price: 1}, + {Name: "Neo.Transaction.GetUnspentCoins", Func: txGetUnspentCoins, Price: 200}, + {Name: "Neo.Transaction.GetWitnesses", Func: txGetWitnesses, Price: 200}, + {Name: "Neo.Witness.GetVerificationScript", Func: witnessGetVerificationScript, Price: 100}, // Aliases. - {Name: "Neo.Iterator.Next", Func: (*interopContext).enumeratorNext, Price: 1}, - {Name: "Neo.Iterator.Value", Func: (*interopContext).enumeratorValue, Price: 1}, + {Name: "Neo.Iterator.Next", Func: enumerator.Next, Price: 1}, + {Name: "Neo.Iterator.Value", Func: enumerator.Value, Price: 1}, // Old compatibility APIs. - {Name: "AntShares.Account.GetBalance", Func: (*interopContext).accountGetBalance, Price: 1}, - {Name: "AntShares.Account.GetScriptHash", Func: (*interopContext).accountGetScriptHash, Price: 1}, - {Name: "AntShares.Account.GetVotes", Func: (*interopContext).accountGetVotes, Price: 1}, - {Name: "AntShares.Asset.Create", Func: (*interopContext).assetCreate, Price: 0}, - {Name: "AntShares.Asset.GetAdmin", Func: (*interopContext).assetGetAdmin, Price: 1}, - {Name: "AntShares.Asset.GetAmount", Func: (*interopContext).assetGetAmount, Price: 1}, - {Name: "AntShares.Asset.GetAssetId", Func: (*interopContext).assetGetAssetID, Price: 1}, - {Name: "AntShares.Asset.GetAssetType", Func: (*interopContext).assetGetAssetType, Price: 1}, - {Name: "AntShares.Asset.GetAvailable", Func: (*interopContext).assetGetAvailable, Price: 1}, - {Name: "AntShares.Asset.GetIssuer", Func: (*interopContext).assetGetIssuer, Price: 1}, - {Name: "AntShares.Asset.GetOwner", Func: (*interopContext).assetGetOwner, Price: 1}, - {Name: "AntShares.Asset.GetPrecision", Func: (*interopContext).assetGetPrecision, Price: 1}, - {Name: "AntShares.Asset.Renew", Func: (*interopContext).assetRenew, Price: 0}, - {Name: "AntShares.Attribute.GetData", Func: (*interopContext).attrGetData, Price: 1}, - {Name: "AntShares.Attribute.GetUsage", Func: (*interopContext).attrGetUsage, Price: 1}, - {Name: "AntShares.Block.GetTransaction", Func: (*interopContext).blockGetTransaction, Price: 1}, - {Name: "AntShares.Block.GetTransactionCount", Func: (*interopContext).blockGetTransactionCount, Price: 1}, - {Name: "AntShares.Block.GetTransactions", Func: (*interopContext).blockGetTransactions, Price: 1}, - {Name: "AntShares.Blockchain.GetAccount", Func: (*interopContext).bcGetAccount, Price: 100}, - {Name: "AntShares.Blockchain.GetAsset", Func: (*interopContext).bcGetAsset, Price: 100}, - {Name: "AntShares.Blockchain.GetBlock", Func: (*interopContext).bcGetBlock, Price: 200}, - {Name: "AntShares.Blockchain.GetContract", Func: (*interopContext).bcGetContract, Price: 100}, - {Name: "AntShares.Blockchain.GetHeader", Func: (*interopContext).bcGetHeader, Price: 100}, - {Name: "AntShares.Blockchain.GetHeight", Func: (*interopContext).bcGetHeight, Price: 1}, - {Name: "AntShares.Blockchain.GetTransaction", Func: (*interopContext).bcGetTransaction, Price: 100}, - {Name: "AntShares.Blockchain.GetValidators", Func: (*interopContext).bcGetValidators, Price: 200}, - {Name: "AntShares.Contract.Create", Func: (*interopContext).contractCreate, Price: 0}, - {Name: "AntShares.Contract.Destroy", Func: (*interopContext).contractDestroy, Price: 1}, - {Name: "AntShares.Contract.GetScript", Func: (*interopContext).contractGetScript, Price: 1}, - {Name: "AntShares.Contract.GetStorageContext", Func: (*interopContext).contractGetStorageContext, Price: 1}, - {Name: "AntShares.Contract.Migrate", Func: (*interopContext).contractMigrate, Price: 0}, - {Name: "AntShares.Header.GetConsensusData", Func: (*interopContext).headerGetConsensusData, Price: 1}, - {Name: "AntShares.Header.GetHash", Func: (*interopContext).headerGetHash, Price: 1}, - {Name: "AntShares.Header.GetMerkleRoot", Func: (*interopContext).headerGetMerkleRoot, Price: 1}, - {Name: "AntShares.Header.GetNextConsensus", Func: (*interopContext).headerGetNextConsensus, Price: 1}, - {Name: "AntShares.Header.GetPrevHash", Func: (*interopContext).headerGetPrevHash, Price: 1}, - {Name: "AntShares.Header.GetTimestamp", Func: (*interopContext).headerGetTimestamp, Price: 1}, - {Name: "AntShares.Header.GetVersion", Func: (*interopContext).headerGetVersion, Price: 1}, - {Name: "AntShares.Input.GetHash", Func: (*interopContext).inputGetHash, Price: 1}, - {Name: "AntShares.Input.GetIndex", Func: (*interopContext).inputGetIndex, Price: 1}, - {Name: "AntShares.Output.GetAssetId", Func: (*interopContext).outputGetAssetID, Price: 1}, - {Name: "AntShares.Output.GetScriptHash", Func: (*interopContext).outputGetScriptHash, Price: 1}, - {Name: "AntShares.Output.GetValue", Func: (*interopContext).outputGetValue, Price: 1}, - {Name: "AntShares.Runtime.CheckWitness", Func: (*interopContext).runtimeCheckWitness, Price: 200}, - {Name: "AntShares.Runtime.Log", Func: (*interopContext).runtimeLog, Price: 1}, - {Name: "AntShares.Runtime.Notify", Func: (*interopContext).runtimeNotify, Price: 1}, - {Name: "AntShares.Storage.Delete", Func: (*interopContext).storageDelete, Price: 100}, - {Name: "AntShares.Storage.Get", Func: (*interopContext).storageGet, Price: 100}, - {Name: "AntShares.Storage.GetContext", Func: (*interopContext).storageGetContext, Price: 1}, - {Name: "AntShares.Storage.Put", Func: (*interopContext).storagePut, Price: 0}, - {Name: "AntShares.Transaction.GetAttributes", Func: (*interopContext).txGetAttributes, Price: 1}, - {Name: "AntShares.Transaction.GetHash", Func: (*interopContext).txGetHash, Price: 1}, - {Name: "AntShares.Transaction.GetInputs", Func: (*interopContext).txGetInputs, Price: 1}, - {Name: "AntShares.Transaction.GetOutputs", Func: (*interopContext).txGetOutputs, Price: 1}, - {Name: "AntShares.Transaction.GetReferences", Func: (*interopContext).txGetReferences, Price: 200}, - {Name: "AntShares.Transaction.GetType", Func: (*interopContext).txGetType, Price: 1}, + {Name: "AntShares.Account.GetBalance", Func: accountGetBalance, Price: 1}, + {Name: "AntShares.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1}, + {Name: "AntShares.Account.GetVotes", Func: accountGetVotes, Price: 1}, + {Name: "AntShares.Asset.Create", Func: assetCreate, Price: 0}, + {Name: "AntShares.Asset.GetAdmin", Func: assetGetAdmin, Price: 1}, + {Name: "AntShares.Asset.GetAmount", Func: assetGetAmount, Price: 1}, + {Name: "AntShares.Asset.GetAssetId", Func: assetGetAssetID, Price: 1}, + {Name: "AntShares.Asset.GetAssetType", Func: assetGetAssetType, Price: 1}, + {Name: "AntShares.Asset.GetAvailable", Func: assetGetAvailable, Price: 1}, + {Name: "AntShares.Asset.GetIssuer", Func: assetGetIssuer, Price: 1}, + {Name: "AntShares.Asset.GetOwner", Func: assetGetOwner, Price: 1}, + {Name: "AntShares.Asset.GetPrecision", Func: assetGetPrecision, Price: 1}, + {Name: "AntShares.Asset.Renew", Func: assetRenew, Price: 0}, + {Name: "AntShares.Attribute.GetData", Func: attrGetData, Price: 1}, + {Name: "AntShares.Attribute.GetUsage", Func: attrGetUsage, Price: 1}, + {Name: "AntShares.Block.GetTransaction", Func: blockGetTransaction, Price: 1}, + {Name: "AntShares.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1}, + {Name: "AntShares.Block.GetTransactions", Func: blockGetTransactions, Price: 1}, + {Name: "AntShares.Blockchain.GetAccount", Func: bcGetAccount, Price: 100}, + {Name: "AntShares.Blockchain.GetAsset", Func: bcGetAsset, Price: 100}, + {Name: "AntShares.Blockchain.GetBlock", Func: bcGetBlock, Price: 200}, + {Name: "AntShares.Blockchain.GetContract", Func: bcGetContract, Price: 100}, + {Name: "AntShares.Blockchain.GetHeader", Func: bcGetHeader, Price: 100}, + {Name: "AntShares.Blockchain.GetHeight", Func: bcGetHeight, Price: 1}, + {Name: "AntShares.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100}, + {Name: "AntShares.Blockchain.GetValidators", Func: bcGetValidators, Price: 200}, + {Name: "AntShares.Contract.Create", Func: contractCreate, Price: 0}, + {Name: "AntShares.Contract.Destroy", Func: contractDestroy, Price: 1}, + {Name: "AntShares.Contract.GetScript", Func: contractGetScript, Price: 1}, + {Name: "AntShares.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1}, + {Name: "AntShares.Contract.Migrate", Func: contractMigrate, Price: 0}, + {Name: "AntShares.Header.GetConsensusData", Func: headerGetConsensusData, Price: 1}, + {Name: "AntShares.Header.GetHash", Func: headerGetHash, Price: 1}, + {Name: "AntShares.Header.GetMerkleRoot", Func: headerGetMerkleRoot, Price: 1}, + {Name: "AntShares.Header.GetNextConsensus", Func: headerGetNextConsensus, Price: 1}, + {Name: "AntShares.Header.GetPrevHash", Func: headerGetPrevHash, Price: 1}, + {Name: "AntShares.Header.GetTimestamp", Func: headerGetTimestamp, Price: 1}, + {Name: "AntShares.Header.GetVersion", Func: headerGetVersion, Price: 1}, + {Name: "AntShares.Input.GetHash", Func: inputGetHash, Price: 1}, + {Name: "AntShares.Input.GetIndex", Func: inputGetIndex, Price: 1}, + {Name: "AntShares.Output.GetAssetId", Func: outputGetAssetID, Price: 1}, + {Name: "AntShares.Output.GetScriptHash", Func: outputGetScriptHash, Price: 1}, + {Name: "AntShares.Output.GetValue", Func: outputGetValue, Price: 1}, + {Name: "AntShares.Runtime.CheckWitness", Func: runtimeCheckWitness, Price: 200}, + {Name: "AntShares.Runtime.Log", Func: runtimeLog, Price: 1}, + {Name: "AntShares.Runtime.Notify", Func: runtimeNotify, Price: 1}, + {Name: "AntShares.Storage.Delete", Func: storageDelete, Price: 100}, + {Name: "AntShares.Storage.Get", Func: storageGet, Price: 100}, + {Name: "AntShares.Storage.GetContext", Func: storageGetContext, Price: 1}, + {Name: "AntShares.Storage.Put", Func: storagePut, Price: 0}, + {Name: "AntShares.Transaction.GetAttributes", Func: txGetAttributes, Price: 1}, + {Name: "AntShares.Transaction.GetHash", Func: txGetHash, Price: 1}, + {Name: "AntShares.Transaction.GetInputs", Func: txGetInputs, Price: 1}, + {Name: "AntShares.Transaction.GetOutputs", Func: txGetOutputs, Price: 1}, + {Name: "AntShares.Transaction.GetReferences", Func: txGetReferences, Price: 200}, + {Name: "AntShares.Transaction.GetType", Func: txGetType, Price: 1}, } // initIDinInteropsSlice initializes IDs from names in one given -// interopedFunction slice and then sorts it. -func initIDinInteropsSlice(iops []interopedFunction) { +// Function slice and then sorts it. +func initIDinInteropsSlice(iops []interop.Function) { for i := range iops { iops[i].ID = vm.InteropNameToID([]byte(iops[i].Name)) } diff --git a/pkg/core/interops_test.go b/pkg/core/interops_test.go index ec4f1fa03..2f7b47b74 100644 --- a/pkg/core/interops_test.go +++ b/pkg/core/interops_test.go @@ -6,13 +6,14 @@ import ( "testing" "github.com/nspcc-dev/neo-go/pkg/core/dao" + "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/stretchr/testify/require" ) -func testNonInterop(t *testing.T, value interface{}, f func(*interopContext, *vm.VM) error) { +func testNonInterop(t *testing.T, value interface{}, f func(*interop.Context, *vm.VM) error) { v := vm.New() v.Estack().PushVal(value) chain := newTestChain(t) @@ -30,56 +31,56 @@ func TestUnexpectedNonInterops(t *testing.T) { } // All of these functions expect an interop item on the stack. - funcs := []func(*interopContext, *vm.VM) error{ - (*interopContext).accountGetBalance, - (*interopContext).accountGetScriptHash, - (*interopContext).accountGetVotes, - (*interopContext).assetGetAdmin, - (*interopContext).assetGetAmount, - (*interopContext).assetGetAssetID, - (*interopContext).assetGetAssetType, - (*interopContext).assetGetAvailable, - (*interopContext).assetGetIssuer, - (*interopContext).assetGetOwner, - (*interopContext).assetGetPrecision, - (*interopContext).assetRenew, - (*interopContext).attrGetData, - (*interopContext).attrGetUsage, - (*interopContext).blockGetTransaction, - (*interopContext).blockGetTransactionCount, - (*interopContext).blockGetTransactions, - (*interopContext).contractGetScript, - (*interopContext).contractGetStorageContext, - (*interopContext).contractIsPayable, - (*interopContext).headerGetConsensusData, - (*interopContext).headerGetHash, - (*interopContext).headerGetIndex, - (*interopContext).headerGetMerkleRoot, - (*interopContext).headerGetNextConsensus, - (*interopContext).headerGetPrevHash, - (*interopContext).headerGetTimestamp, - (*interopContext).headerGetVersion, - (*interopContext).inputGetHash, - (*interopContext).inputGetIndex, - (*interopContext).invocationTxGetScript, - (*interopContext).outputGetAssetID, - (*interopContext).outputGetScriptHash, - (*interopContext).outputGetValue, - (*interopContext).storageContextAsReadOnly, - (*interopContext).storageDelete, - (*interopContext).storageFind, - (*interopContext).storageGet, - (*interopContext).storagePut, - (*interopContext).storagePutEx, - (*interopContext).txGetAttributes, - (*interopContext).txGetHash, - (*interopContext).txGetInputs, - (*interopContext).txGetOutputs, - (*interopContext).txGetReferences, - (*interopContext).txGetType, - (*interopContext).txGetUnspentCoins, - (*interopContext).txGetWitnesses, - (*interopContext).witnessGetVerificationScript, + funcs := []func(*interop.Context, *vm.VM) error{ + accountGetBalance, + accountGetScriptHash, + accountGetVotes, + assetGetAdmin, + assetGetAmount, + assetGetAssetID, + assetGetAssetType, + assetGetAvailable, + assetGetIssuer, + assetGetOwner, + assetGetPrecision, + assetRenew, + attrGetData, + attrGetUsage, + blockGetTransaction, + blockGetTransactionCount, + blockGetTransactions, + contractGetScript, + contractGetStorageContext, + contractIsPayable, + headerGetConsensusData, + headerGetHash, + headerGetIndex, + headerGetMerkleRoot, + headerGetNextConsensus, + headerGetPrevHash, + headerGetTimestamp, + headerGetVersion, + inputGetHash, + inputGetIndex, + invocationTxGetScript, + outputGetAssetID, + outputGetScriptHash, + outputGetValue, + storageContextAsReadOnly, + storageDelete, + storageFind, + storageGet, + storagePut, + storagePutEx, + txGetAttributes, + txGetHash, + txGetInputs, + txGetOutputs, + txGetReferences, + txGetType, + txGetUnspentCoins, + txGetWitnesses, + witnessGetVerificationScript, } for _, f := range funcs { for k, v := range vals { diff --git a/pkg/network/blockqueue.go b/pkg/network/blockqueue.go index 762e569fa..ed6eac1ae 100644 --- a/pkg/network/blockqueue.go +++ b/pkg/network/blockqueue.go @@ -2,8 +2,8 @@ package network import ( "github.com/Workiva/go-datastructures/queue" - "github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core/block" + "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "go.uber.org/zap" ) @@ -11,11 +11,11 @@ type blockQueue struct { log *zap.Logger queue *queue.PriorityQueue checkBlocks chan struct{} - chain core.Blockchainer + chain blockchainer.Blockchainer relayF func(*block.Block) } -func newBlockQueue(capacity int, bc core.Blockchainer, log *zap.Logger, relayer func(*block.Block)) *blockQueue { +func newBlockQueue(capacity int, bc blockchainer.Blockchainer, log *zap.Logger, relayer func(*block.Block)) *blockQueue { if log == nil { return nil } diff --git a/pkg/network/server.go b/pkg/network/server.go index efd6d5e3f..729995067 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -13,6 +13,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/consensus" "github.com/nspcc-dev/neo-go/pkg/core" "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/transaction" "github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/util" @@ -53,7 +54,7 @@ type ( transport Transporter discovery Discoverer - chain core.Blockchainer + chain blockchainer.Blockchainer bQueue *blockQueue consensus consensus.Service @@ -84,7 +85,7 @@ func randomID() uint32 { } // NewServer returns a new Server, initialized with the given configuration. -func NewServer(config ServerConfig, chain core.Blockchainer, log *zap.Logger) (*Server, error) { +func NewServer(config ServerConfig, chain blockchainer.Blockchainer, log *zap.Logger) (*Server, error) { if log == nil { return nil, errors.New("logger is a required parameter") } diff --git a/pkg/rpc/response/result/block.go b/pkg/rpc/response/result/block.go index e021cc64a..8f02a2999 100644 --- a/pkg/rpc/response/result/block.go +++ b/pkg/rpc/response/result/block.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - "github.com/nspcc-dev/neo-go/pkg/core" "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/transaction" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/io" @@ -50,7 +50,7 @@ type ( ) // NewBlock creates a new Block wrapper. -func NewBlock(b *block.Block, chain core.Blockchainer) Block { +func NewBlock(b *block.Block, chain blockchainer.Blockchainer) Block { res := Block{ Version: b.Version, Hash: b.Hash(), diff --git a/pkg/rpc/response/result/block_header.go b/pkg/rpc/response/result/block_header.go index f333d54de..886903500 100644 --- a/pkg/rpc/response/result/block_header.go +++ b/pkg/rpc/response/result/block_header.go @@ -3,8 +3,8 @@ package result import ( "strconv" - "github.com/nspcc-dev/neo-go/pkg/core" "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/transaction" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/io" @@ -31,7 +31,7 @@ type ( ) // NewHeader creates a new Header wrapper. -func NewHeader(h *block.Header, chain core.Blockchainer) Header { +func NewHeader(h *block.Header, chain blockchainer.Blockchainer) Header { res := Header{ Hash: h.Hash(), Size: io.GetVarSize(h), diff --git a/pkg/rpc/response/result/tx_raw_output.go b/pkg/rpc/response/result/tx_raw_output.go index d039e2eb6..3c0269022 100644 --- a/pkg/rpc/response/result/tx_raw_output.go +++ b/pkg/rpc/response/result/tx_raw_output.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" - "github.com/nspcc-dev/neo-go/pkg/core" "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/transaction" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -27,7 +27,7 @@ type TransactionMetadata struct { } // NewTransactionOutputRaw returns a new ransactionOutputRaw object. -func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain core.Blockchainer) TransactionOutputRaw { +func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain blockchainer.Blockchainer) TransactionOutputRaw { // confirmations formula confirmations := int(chain.BlockHeight() - header.Base.Index + 1) // set index position diff --git a/pkg/rpc/response/result/unclaimed.go b/pkg/rpc/response/result/unclaimed.go index e636f5c1a..f8cd8d1a9 100644 --- a/pkg/rpc/response/result/unclaimed.go +++ b/pkg/rpc/response/result/unclaimed.go @@ -2,6 +2,7 @@ package result import ( "github.com/nspcc-dev/neo-go/pkg/core" + "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -14,7 +15,7 @@ type Unclaimed struct { } // NewUnclaimed creates a new Unclaimed wrapper using given Blockchainer. -func NewUnclaimed(a *state.Account, chain core.Blockchainer) (*Unclaimed, error) { +func NewUnclaimed(a *state.Account, chain blockchainer.Blockchainer) (*Unclaimed, error) { var ( available util.Fixed8 unavailable util.Fixed8 diff --git a/pkg/rpc/response/result/unspents.go b/pkg/rpc/response/result/unspents.go index 623d2e1a5..9a1613b86 100644 --- a/pkg/rpc/response/result/unspents.go +++ b/pkg/rpc/response/result/unspents.go @@ -1,7 +1,7 @@ package result import ( - "github.com/nspcc-dev/neo-go/pkg/core" + "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -29,7 +29,7 @@ var GlobalAssets = map[string]string{ } // NewUnspents creates a new Account wrapper using given Blockchainer. -func NewUnspents(a *state.Account, chain core.Blockchainer, addr string) Unspents { +func NewUnspents(a *state.Account, chain blockchainer.Blockchainer, addr string) Unspents { res := Unspents{ Address: addr, Balance: make([]UnspentBalanceInfo, 0, len(a.Balances)), diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 3d5da1e2b..87d9e3506 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -10,6 +10,7 @@ import ( "net/http" "strconv" + "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "github.com/nspcc-dev/neo-go/pkg/rpc" "github.com/nspcc-dev/neo-go/pkg/core" @@ -35,7 +36,7 @@ type ( // Server represents the JSON-RPC 2.0 server. Server struct { *http.Server - chain core.Blockchainer + chain blockchainer.Blockchainer config rpc.Config coreServer *network.Server log *zap.Logger @@ -81,7 +82,7 @@ var invalidBlockHeightError = func(index int, height int) error { } // New creates a new Server struct. -func New(chain core.Blockchainer, conf rpc.Config, coreServer *network.Server, log *zap.Logger) Server { +func New(chain blockchainer.Blockchainer, conf rpc.Config, coreServer *network.Server, log *zap.Logger) Server { httpServer := &http.Server{ Addr: conf.Address + ":" + strconv.FormatUint(uint64(conf.Port), 10), }