From ff15a0acfd5b77efdb99dc76ef00c71cc2de124c Mon Sep 17 00:00:00 2001 From: Vsevolod Brekelov Date: Wed, 4 Dec 2019 12:27:04 +0300 Subject: [PATCH] core: add trigger types as constants. Closes #509 --- pkg/core/blockchain.go | 11 +++---- pkg/core/interop_neo.go | 7 +++-- pkg/core/interop_neo_test.go | 13 ++++---- pkg/core/interop_system.go | 7 +++-- pkg/smartcontract/trigger/trigger_type.go | 36 +++++++++++++++++++++++ 5 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 pkg/smartcontract/trigger/trigger_type.go diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 87d219125..1552aa14f 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -16,6 +16,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/smartcontract" + "github.com/CityOfZion/neo-go/pkg/smartcontract/trigger" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" "github.com/pkg/errors" @@ -487,7 +488,7 @@ func (bc *Blockchain) storeBlock(block *Block) error { } chainState.contracts[contract.ScriptHash()] = contract case *transaction.InvocationTX: - systemInterop := newInteropContext(0x10, bc, chainState.store, block, tx) + systemInterop := newInteropContext(trigger.Application, bc, chainState.store, block, tx) v := bc.spawnVMWithInterops(systemInterop) v.SetCheckedHash(tx.VerificationHash().Bytes()) v.LoadScript(t.Script) @@ -530,7 +531,7 @@ func (bc *Blockchain) storeBlock(block *Block) error { } aer := &AppExecResult{ TxHash: tx.Hash(), - Trigger: 0x10, + Trigger: trigger.Application, VMState: v.State(), GasConsumed: util.Fixed8(0), Stack: v.Stack("estack"), @@ -1418,7 +1419,7 @@ func (bc *Blockchain) spawnVMWithInterops(interopCtx *interopContext) *vm.VM { // GetTestVM returns a VM and a Store setup for a test run of some sort of code. func (bc *Blockchain) GetTestVM() (*vm.VM, storage.Store) { tmpStore := storage.NewMemCachedStore(bc.store) - systemInterop := newInteropContext(0x10, bc, tmpStore, nil, nil) + systemInterop := newInteropContext(trigger.Application, bc, tmpStore, nil, nil) vm := bc.spawnVMWithInterops(systemInterop) return vm, tmpStore } @@ -1482,7 +1483,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *Block } sort.Slice(hashes, func(i, j int) bool { return hashes[i].Less(hashes[j]) }) sort.Slice(witnesses, func(i, j int) bool { return witnesses[i].ScriptHash().Less(witnesses[j].ScriptHash()) }) - interopCtx := newInteropContext(0, bc, bc.store, block, t) + interopCtx := newInteropContext(trigger.Verification, bc, bc.store, block, t) for i := 0; i < len(hashes); i++ { err := bc.verifyHashAgainstScript(hashes[i], witnesses[i], t.VerificationHash(), interopCtx) if err != nil { @@ -1502,7 +1503,7 @@ func (bc *Blockchain) verifyBlockWitnesses(block *Block, prevHeader *Header) err } else { hash = prevHeader.NextConsensus } - interopCtx := newInteropContext(0, bc, bc.store, nil, nil) + interopCtx := newInteropContext(trigger.Verification, bc, bc.store, nil, nil) return bc.verifyHashAgainstScript(hash, block.Script, block.VerificationHash(), interopCtx) } diff --git a/pkg/core/interop_neo.go b/pkg/core/interop_neo.go index 9c177c3e9..1aa46e532 100644 --- a/pkg/core/interop_neo.go +++ b/pkg/core/interop_neo.go @@ -8,6 +8,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/smartcontract" + "github.com/CityOfZion/neo-go/pkg/smartcontract/trigger" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" gherr "github.com/pkg/errors" @@ -429,7 +430,7 @@ func (ic *interopContext) storageFind(v *vm.VM) error { // evaluation stack, does a lot of checks and returns ContractState if it // succeeds. func (ic *interopContext) createContractStateFromVM(v *vm.VM) (*ContractState, error) { - if ic.trigger != 0x10 { + if ic.trigger != trigger.Application { return nil, errors.New("can't create contract when not triggered by an application") } script := v.Estack().Pop().Bytes() @@ -551,7 +552,7 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error { // assetCreate creates an asset. func (ic *interopContext) assetCreate(v *vm.VM) error { - if ic.trigger != 0x10 { + 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()) @@ -717,7 +718,7 @@ func (ic *interopContext) assetGetPrecision(v *vm.VM) error { // assetRenew updates asset expiration date. func (ic *interopContext) assetRenew(v *vm.VM) error { - if ic.trigger != 0x10 { + if ic.trigger != trigger.Application { return errors.New("can't create asset when not triggered by an application") } asInterface := v.Estack().Pop().Value() diff --git a/pkg/core/interop_neo_test.go b/pkg/core/interop_neo_test.go index ef1033ac6..eaaa84fc9 100644 --- a/pkg/core/interop_neo_test.go +++ b/pkg/core/interop_neo_test.go @@ -8,6 +8,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/smartcontract" + "github.com/CityOfZion/neo-go/pkg/smartcontract/trigger" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" "github.com/stretchr/testify/require" @@ -42,7 +43,7 @@ func TestHeaderGetVersion(t *testing.T) { func TestHeaderGetVersion_Negative(t *testing.T) { v := vm.New() block := newDumbBlock() - context := newInteropContext(0x10, newTestChain(t), storage.NewMemoryStore(), block, nil) + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), block, nil) v.Estack().PushVal(vm.NewBoolItem(false)) err := context.headerGetVersion(v) @@ -325,7 +326,7 @@ func TestAssetGetPrecision(t *testing.T) { func createVMAndPushBlock(t *testing.T) (*vm.VM, *Block, *interopContext) { v := vm.New() block := newDumbBlock() - context := newInteropContext(0x10, newTestChain(t), storage.NewMemoryStore(), block, nil) + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), block, nil) v.Estack().PushVal(vm.NewInteropItem(block)) return v, block, context } @@ -354,7 +355,7 @@ func createVMAndAssetState(t *testing.T) (*vm.VM, *AssetState, *interopContext) IsFrozen: false, } - context := newInteropContext(0x10, newTestChain(t), storage.NewMemoryStore(), nil, nil) + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil) return v, assetState, context } @@ -373,7 +374,7 @@ func createVMAndContractState(t *testing.T) (*vm.VM, *ContractState, *interopCon scriptHash: randomUint160(), } - context := newInteropContext(0x10, newTestChain(t), storage.NewMemoryStore(), nil, nil) + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil) return v, contractState, context } @@ -387,7 +388,7 @@ func createVMAndAccState(t *testing.T) (*vm.VM, *AccountState, *interopContext) accountState.Votes = []*keys.PublicKey{key} require.NoError(t, err) - context := newInteropContext(0x10, newTestChain(t), storage.NewMemoryStore(), nil, nil) + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil) return v, accountState, context } @@ -416,6 +417,6 @@ func createVMAndTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interopCont tx.Attributes = attributes tx.Inputs = inputs tx.Outputs = outputs - context := newInteropContext(0x10, newTestChain(t), storage.NewMemoryStore(), nil, tx) + context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, tx) return v, tx, context } diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index 1d8a4a981..714ef7056 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -8,6 +8,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/smartcontract/trigger" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" gherr "github.com/pkg/errors" @@ -393,7 +394,7 @@ func (ic *interopContext) checkStorageContext(stc *StorageContext) error { // storageDelete deletes stored key-value pair. func (ic *interopContext) storageDelete(v *vm.VM) error { - if ic.trigger != 0x10 && ic.trigger != 0x11 { + 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() @@ -464,7 +465,7 @@ func (ic *interopContext) storageGetReadOnlyContext(v *vm.VM) error { } func (ic *interopContext) putWithContextAndFlags(stc *StorageContext, key []byte, value []byte, isConst bool) error { - if ic.trigger != 0x10 && ic.trigger != 0x11 { + 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 { @@ -538,7 +539,7 @@ func (ic *interopContext) storageContextAsReadOnly(v *vm.VM) error { // contractDestroy destroys a contract. func (ic *interopContext) contractDestroy(v *vm.VM) error { - if ic.trigger != 0x10 { + if ic.trigger != trigger.Application { return errors.New("can't destroy contract when not triggered by application") } hash := getContextScriptHash(v, 0) diff --git a/pkg/smartcontract/trigger/trigger_type.go b/pkg/smartcontract/trigger/trigger_type.go new file mode 100644 index 000000000..6b5630a1e --- /dev/null +++ b/pkg/smartcontract/trigger/trigger_type.go @@ -0,0 +1,36 @@ +package trigger + +// Trigger typed used in C# reference node: https://github.com/neo-project/neo/blob/c64748ecbac3baeb8045b16af0d518398a6ced24/neo/SmartContract/TriggerType.cs#L3 +const ( + // The verification trigger indicates that the contract is being invoked as a verification function. + // The verification function can accept multiple parameters, and should return a boolean value that indicates the validity of the transaction or block. + // The entry point of the contract will be invoked if the contract is triggered by Verification: + // main(...); + // The entry point of the contract must be able to handle this type of invocation. + Verification = 0x00 + + // The verificationR trigger indicates that the contract is being invoked as a verification function because it is specified as a target of an output of the transaction. + // The verification function accepts no parameter, and should return a boolean value that indicates the validity of the transaction. + // The entry point of the contract will be invoked if the contract is triggered by VerificationR: + // main("receiving", new object[0]); + // The receiving function should have the following signature: + // public bool receiving() + // The receiving function will be invoked automatically when a contract is receiving assets from a transfer. + VerificationR = 0x01 + + // The application trigger indicates that the contract is being invoked as an application function. + // The application function can accept multiple parameters, change the states of the blockchain, and return any type of value. + // The contract can have any form of entry point, but we recommend that all contracts should have the following entry point: + // public byte[] main(string operation, params object[] args) + // The functions can be invoked by creating an InvocationTransaction. + Application = 0x10 + + // The ApplicationR trigger indicates that the default function received of the contract is being invoked because it is specified as a target of an output of the transaction. + // The received function accepts no parameter, changes the states of the blockchain, and returns any type of value. + // The entry point of the contract will be invoked if the contract is triggered by ApplicationR: + // main("received", new object[0]); + // The received function should have the following signature: + // public byte[] received() + // The received function will be invoked automatically when a contract is receiving assets from a transfer. + ApplicationR = 0x11 +)