From e0ca05f62ca443d878e4b0a394b216c8a4807730 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 9 Dec 2021 20:12:15 +0300 Subject: [PATCH] nativetest: migrate Management contract tests to neotest --- pkg/core/blockchain_test.go | 6 +- pkg/core/helper_test.go | 19 - pkg/core/interop_system_test.go | 148 ++++- .../native/native_test/management_test.go | 590 +++++++++++++++++ pkg/core/native_contract_test.go | 3 +- pkg/core/native_management_test.go | 600 ------------------ pkg/core/native_neo_test.go | 2 +- .../test_data/management_helper/README.md | 9 + .../management_helper1.manifest.json | 1 + .../management_helper/management_helper1.nef | Bin 0 -> 506 bytes .../management_helper2.manifest.json | 1 + .../management_helper/management_helper2.nef | Bin 0 -> 79 bytes pkg/neotest/chain/chain.go | 13 +- 13 files changed, 731 insertions(+), 661 deletions(-) create mode 100644 pkg/core/native/native_test/management_test.go create mode 100644 pkg/core/test_data/management_helper/README.md create mode 100755 pkg/core/test_data/management_helper/management_helper1.manifest.json create mode 100755 pkg/core/test_data/management_helper/management_helper1.nef create mode 100755 pkg/core/test_data/management_helper/management_helper2.manifest.json create mode 100755 pkg/core/test_data/management_helper/management_helper2.nef diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index ac146c4ac..1d0a5f155 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -1116,7 +1116,7 @@ func TestVerifyTx(t *testing.T) { func TestVerifyHashAgainstScript(t *testing.T) { bc := newTestChain(t) - cs, csInvalid := getTestContractState(bc) + cs, csInvalid := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test ic := bc.newInteropContext(trigger.Verification, bc.dao, nil, nil) require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, csInvalid)) @@ -1681,7 +1681,7 @@ func TestRemoveUntraceable(t *testing.T) { func TestInvalidNotification(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(bc) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) aer, err := invokeContractMethod(bc, 1_00000000, cs.Hash, "invalidStack") @@ -1695,7 +1695,7 @@ func TestInvalidNotification(t *testing.T) { func TestMPTDeleteNoKey(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(bc) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) aer, err := invokeContractMethod(bc, 1_00000000, cs.Hash, "delValue", "non-existent-key") require.NoError(t, err) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 1d52f6593..9420de533 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -674,12 +674,6 @@ func signTxWithAccounts(chain *Blockchain, sysFee int64, tx *transaction.Transac } } -func prepareContractMethodInvoke(chain *Blockchain, sysfee int64, - hash util.Uint160, method string, args ...interface{}) (*transaction.Transaction, error) { - return prepareContractMethodInvokeGeneric(chain, sysfee, hash, - method, false, args...) -} - func persistBlock(chain *Blockchain, txs ...*transaction.Transaction) ([]*state.AppExecResult, error) { b := chain.newBlock(txs...) err := chain.AddBlock(b) @@ -716,19 +710,6 @@ func invokeContractMethodGeneric(chain *Blockchain, sysfee int64, hash util.Uint return aers[0], nil } -func invokeContractMethodBy(t *testing.T, chain *Blockchain, signer *wallet.Account, hash util.Uint160, method string, args ...interface{}) (*state.AppExecResult, error) { - var ( - netfee int64 = 1000_0000 - sysfee int64 = 1_0000_0000 - ) - transferTx := transferTokenFromMultisigAccount(t, chain, signer.PrivateKey().PublicKey().GetScriptHash(), chain.contracts.GAS.Hash, sysfee+netfee+1000_0000, nil) - res, err := chain.GetAppExecResults(transferTx.Hash(), trigger.Application) - require.NoError(t, err) - require.Equal(t, vm.HaltState, res[0].VMState) - require.Equal(t, 0, len(res[0].Stack)) - return invokeContractMethodGeneric(chain, sysfee, hash, method, signer, args...) -} - func transferTokenFromMultisigAccountCheckOK(t *testing.T, chain *Blockchain, to, tokenHash util.Uint160, amount int64, additionalArgs ...interface{}) { transferTx := transferTokenFromMultisigAccount(t, chain, to, tokenHash, amount, additionalArgs...) res, err := chain.GetAppExecResults(transferTx.Hash(), trigger.Application) diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index 06e75656d..de236b9d3 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -1,10 +1,14 @@ package core import ( + "encoding/json" "errors" "fmt" + "io/ioutil" "math" "math/big" + "os" + "path/filepath" "testing" "github.com/nspcc-dev/neo-go/internal/random" @@ -36,6 +40,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/stretchr/testify/require" ) @@ -231,7 +236,7 @@ func TestRuntimeGetNotifications(t *testing.T) { func TestRuntimeGetInvocationCounter(t *testing.T) { v, ic, bc := createVM(t) - cs, _ := getTestContractState(bc) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs)) ic.Invocations[hash.Hash160([]byte{2})] = 42 @@ -658,22 +663,28 @@ func createVMAndContractState(t testing.TB) (*vm.VM, *state.Contract, *interop.C return v, contractState, context, chain } -func createVMAndTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop.Context, *Blockchain) { - script := []byte{byte(opcode.PUSH1), byte(opcode.RET)} - tx := transaction.New(script, 0) - tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3, 4}}} - tx.Scripts = []transaction.Witness{{InvocationScript: []byte{}, VerificationScript: []byte{}}} - chain := newTestChain(t) - d := dao.NewSimple(storage.NewMemoryStore(), chain.config.StateRootInHeader, chain.config.P2PSigExtensions) - context := chain.newInteropContext(trigger.Application, d, nil, tx) - v := context.SpawnVM() - return v, tx, context, chain -} +var ( + helper1ContractNEFPath = filepath.Join("test_data", "management_helper", "management_helper1.nef") + helper1ContractManifestPath = filepath.Join("test_data", "management_helper", "management_helper1.manifest.json") + helper2ContractNEFPath = filepath.Join("test_data", "management_helper", "management_helper2.nef") + helper2ContractManifestPath = filepath.Join("test_data", "management_helper", "management_helper2.manifest.json") +) -// getTestContractState returns 2 contracts second of which is allowed to call the first. -func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { - mgmtHash := bc.ManagementContractHash() +// TestGenerateManagementHelperContracts generates 2 helper contracts second of which is +// allowed to call the first. It uses test chain to define Management and StdLib +// native hashes and saves generated NEF and manifest to ../test_data/management_contract folder. +// Set `saveState` flag to true and run the test to rewrite NEF and manifest files. +func TestGenerateManagementHelperContracts(t *testing.T) { + const saveState = false + + bc := newTestChain(t) + mgmtHash := bc.contracts.Management.Hash stdHash := bc.contracts.Std.Hash + neoHash := bc.contracts.NEO.Hash + singleChainValidator := testchain.PrivateKey(testchain.IDToOrder(0)) + acc := wallet.NewAccountFromPrivateKey(singleChainValidator) + require.NoError(t, acc.ConvertMultisig(1, keys.PublicKeys{singleChainValidator.PublicKey()})) + singleChainValidatorHash := acc.Contract.ScriptHash() w := io.NewBufBinWriter() emit.Opcodes(w.BinWriter, opcode.ABORT) @@ -771,7 +782,6 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { emit.Opcodes(w.BinWriter, opcode.RET) script := w.Bytes() - h := hash.Hash160(script) m := manifest.NewManifest("TestMain") m.ABI.Methods = []manifest.Method{ { @@ -953,20 +963,14 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { m.Permissions[1].Contract.Value = util.Uint160{} m.Permissions[1].Methods.Add("method") - cs := &state.Contract{ - ContractBase: state.ContractBase{ - Hash: h, - Manifest: *m, - ID: 42, - }, - } + // Generate NEF file. ne, err := nef.NewFile(script) if err != nil { panic(err) } ne.Tokens = []nef.MethodToken{ { - Hash: bc.contracts.NEO.Hash, + Hash: neoHash, Method: "balanceOf", ParamCount: 1, HasReturn: true, @@ -980,7 +984,25 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { }, } ne.Checksum = ne.CalculateChecksum() - cs.NEF = *ne + + // Write first NEF file. + bytes, err := ne.Bytes() + require.NoError(t, err) + if saveState { + err = ioutil.WriteFile(helper1ContractNEFPath, bytes, os.ModePerm) + require.NoError(t, err) + } + + // Write first manifest file. + mData, err := json.Marshal(m) + require.NoError(t, err) + if saveState { + err = ioutil.WriteFile(helper1ContractManifestPath, mData, os.ModePerm) + require.NoError(t, err) + } + + // Create hash of the first contract assuming that sender is single-chain validator. + h := state.CreateContractHash(singleChainValidatorHash, ne.Checksum, m.Name) currScript := []byte{byte(opcode.RET)} m = manifest.NewManifest("TestAux") @@ -997,14 +1019,74 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { panic(err) } - return cs, &state.Contract{ + // Write second NEF file. + bytes, err = ne.Bytes() + require.NoError(t, err) + if saveState { + err = ioutil.WriteFile(helper2ContractNEFPath, bytes, os.ModePerm) + require.NoError(t, err) + } + + // Write second manifest file. + mData, err = json.Marshal(m) + require.NoError(t, err) + if saveState { + err = ioutil.WriteFile(helper2ContractManifestPath, mData, os.ModePerm) + require.NoError(t, err) + } + + require.False(t, saveState) +} + +// getTestContractState returns 2 contracts second of which is allowed to call the first. +func getTestContractState(t *testing.T, id1, id2 int32, sender2 util.Uint160) (*state.Contract, *state.Contract) { + errNotFound := errors.New("auto-generated oracle contract is not found, use TestGenerateOracleContract to regenerate") + + neBytes, err := ioutil.ReadFile(helper1ContractNEFPath) + require.NoError(t, err, fmt.Errorf("nef1: %w", errNotFound)) + ne, err := nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err := ioutil.ReadFile(helper1ContractManifestPath) + require.NoError(t, err, fmt.Errorf("manifest1: %w", errNotFound)) + m := &manifest.Manifest{} + err = json.Unmarshal(mBytes, m) + require.NoError(t, err) + + cs1 := &state.Contract{ ContractBase: state.ContractBase{ - NEF: *ne, - Hash: hash.Hash160(currScript), + NEF: ne, Manifest: *m, - ID: 123, + ID: id1, }, } + + neBytes, err = ioutil.ReadFile(helper2ContractNEFPath) + require.NoError(t, err, fmt.Errorf("nef2: %w", errNotFound)) + ne, err = nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err = ioutil.ReadFile(helper2ContractManifestPath) + require.NoError(t, err, fmt.Errorf("manifest2: %w", errNotFound)) + m = &manifest.Manifest{} + err = json.Unmarshal(mBytes, m) + require.NoError(t, err) + + // Retrieve hash of the first contract from the permissions of the second contract. + require.Equal(t, 1, len(m.Permissions)) + require.Equal(t, manifest.PermissionHash, m.Permissions[0].Contract.Type) + cs1.Hash = m.Permissions[0].Contract.Hash() + + cs2 := &state.Contract{ + ContractBase: state.ContractBase{ + NEF: ne, + Manifest: *m, + ID: id2, + Hash: state.CreateContractHash(sender2, ne.Checksum, m.Name), + }, + } + + return cs1, cs2 } func loadScript(ic *interop.Context, script []byte, args ...interface{}) { @@ -1028,12 +1110,12 @@ func loadScriptWithHashAndFlags(ic *interop.Context, script []byte, hash util.Ui func TestContractCall(t *testing.T) { _, ic, bc := createVM(t) - cs, currCs := getTestContractState(bc) + cs, currCs := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, currCs)) currScript := currCs.NEF.Script - h := hash.Hash160(cs.NEF.Script) + h := cs.Hash addArgs := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(2)}) t.Run("Good", func(t *testing.T) { @@ -1420,7 +1502,7 @@ func TestRuntimeCheckWitness(t *testing.T) { func TestLoadToken(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(bc) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) t.Run("good", func(t *testing.T) { @@ -1463,7 +1545,7 @@ func TestRuntimeGetNetwork(t *testing.T) { func TestRuntimeBurnGas(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(bc) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) const sysFee = 2_000000 diff --git a/pkg/core/native/native_test/management_test.go b/pkg/core/native/native_test/management_test.go new file mode 100644 index 000000000..17d0a86fd --- /dev/null +++ b/pkg/core/native/native_test/management_test.go @@ -0,0 +1,590 @@ +package native_test + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "path/filepath" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/storage" + + "github.com/nspcc-dev/neo-go/pkg/core/chaindump" + "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "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" + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/neotest" + "github.com/nspcc-dev/neo-go/pkg/neotest/chain" + "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/emit" + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/stretchr/testify/require" +) + +var ( + helper1ContractNEFPath = filepath.Join("..", "..", "test_data", "management_helper", "management_helper1.nef") + helper1ContractManifestPath = filepath.Join("..", "..", "test_data", "management_helper", "management_helper1.manifest.json") + helper2ContractNEFPath = filepath.Join("..", "..", "test_data", "management_helper", "management_helper2.nef") + helper2ContractManifestPath = filepath.Join("..", "..", "test_data", "management_helper", "management_helper2.manifest.json") +) + +func newManagementClient(t *testing.T) *neotest.ContractInvoker { + return newNativeClient(t, nativenames.Management) +} + +func TestManagement_MinimumDeploymentFee(t *testing.T) { + testGetSet(t, newManagementClient(t), "MinimumDeploymentFee", 10_00000000, 0, 0) +} + +// getTestContractState returns 2 contracts second of which is allowed to call the first. +func getTestContractState(t *testing.T, id1, id2 int32, sender2 util.Uint160) (*state.Contract, *state.Contract) { + errNotFound := errors.New("auto-generated oracle contract is not found, use TestGenerateOracleContract to regenerate") + + neBytes, err := ioutil.ReadFile(helper1ContractNEFPath) + require.NoError(t, err, fmt.Errorf("nef1: %w", errNotFound)) + ne, err := nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err := ioutil.ReadFile(helper1ContractManifestPath) + require.NoError(t, err, fmt.Errorf("manifest1: %w", errNotFound)) + m := &manifest.Manifest{} + err = json.Unmarshal(mBytes, m) + require.NoError(t, err) + + cs1 := &state.Contract{ + ContractBase: state.ContractBase{ + NEF: ne, + Manifest: *m, + ID: id1, + }, + } + + neBytes, err = ioutil.ReadFile(helper2ContractNEFPath) + require.NoError(t, err, fmt.Errorf("nef2: %w", errNotFound)) + ne, err = nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err = ioutil.ReadFile(helper2ContractManifestPath) + require.NoError(t, err, fmt.Errorf("manifest2: %w", errNotFound)) + m = &manifest.Manifest{} + err = json.Unmarshal(mBytes, m) + require.NoError(t, err) + + // Retrieve hash of the first contract from the permissions of the second contract. + require.Equal(t, 1, len(m.Permissions)) + require.Equal(t, manifest.PermissionHash, m.Permissions[0].Contract.Type) + cs1.Hash = m.Permissions[0].Contract.Hash() + + cs2 := &state.Contract{ + ContractBase: state.ContractBase{ + NEF: ne, + Manifest: *m, + ID: id2, + Hash: state.CreateContractHash(sender2, ne.Checksum, m.Name), + }, + } + + return cs1, cs2 +} + +func TestManagement_ContractDeploy(t *testing.T) { + c := newManagementClient(t) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.Committee.ScriptHash()) + manifestBytes, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nefBytes, err := cs1.NEF.Bytes() + require.NoError(t, err) + + t.Run("no NEF", func(t *testing.T) { + managementInvoker.InvokeFail(t, "no valid NEF provided", "deploy", nil, manifestBytes) + }) + t.Run("no manifest", func(t *testing.T) { + managementInvoker.InvokeFail(t, "no valid manifest provided", "deploy", nefBytes, nil) + }) + t.Run("int for NEF", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", int64(1), manifestBytes) + }) + t.Run("zero-length NEF", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", []byte{}, manifestBytes) + }) + t.Run("array for NEF", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", []interface{}{int64(1)}, manifestBytes) + }) + t.Run("bad script in NEF", func(t *testing.T) { + nf, err := nef.FileFromBytes(nefBytes) // make a full copy + require.NoError(t, err) + nf.Script[0] = 0xff + nf.CalculateChecksum() + nefBad, err := nf.Bytes() + require.NoError(t, err) + managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", nefBad, manifestBytes) + }) + t.Run("int for manifest", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, int64(1)) + }) + t.Run("zero-length manifest", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, []byte{}) + }) + t.Run("array for manifest", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, []interface{}{int64(1)}) + }) + t.Run("non-utf8 manifest", func(t *testing.T) { + manifestBad := bytes.Replace(manifestBytes, []byte("TestMain"), []byte("\xff\xfe\xfd"), 1) // Replace name. + managementInvoker.InvokeFail(t, "manifest is not UTF-8 compliant", "deploy", nefBytes, manifestBad) + }) + t.Run("invalid manifest", func(t *testing.T) { + pkey, err := keys.NewPrivateKey() + require.NoError(t, err) + + badManifest := cs1.Manifest + badManifest.Groups = []manifest.Group{{PublicKey: pkey.PublicKey(), Signature: make([]byte, 64)}} + manifB, err := json.Marshal(&badManifest) + require.NoError(t, err) + + managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, manifB) + }) + t.Run("bad methods in manifest 1", func(t *testing.T) { + badManifest := cs1.Manifest + badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) + copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) + badManifest.ABI.Methods[0].Offset = 100500 // out of bounds + manifB, err := json.Marshal(&badManifest) + require.NoError(t, err) + + managementInvoker.InvokeFail(t, "out of bounds method offset", "deploy", nefBytes, manifB) + }) + + t.Run("bad methods in manifest 2", func(t *testing.T) { + var badManifest = cs1.Manifest + badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) + copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) + badManifest.ABI.Methods[0].Offset = len(cs1.NEF.Script) - 2 // Ends with `CALLT(X,X);RET`. + + manifB, err := json.Marshal(badManifest) + require.NoError(t, err) + + managementInvoker.InvokeFail(t, "some methods point to wrong offsets (not to instruction boundary)", "deploy", nefBytes, manifB) + }) + + t.Run("not enough GAS", func(t *testing.T) { + tx := managementInvoker.NewUnsignedTx(t, managementInvoker.Hash, "deploy", nefBytes, manifestBytes) + managementInvoker.SignTx(t, tx, 1_0000_0000, managementInvoker.Signers...) + managementInvoker.AddNewBlock(t, tx) + managementInvoker.CheckFault(t, tx.Hash(), "gas limit exceeded") + }) + + si, err := cs1.ToStackItem() + require.NoError(t, err) + + t.Run("positive", func(t *testing.T) { + tx1 := managementInvoker.PrepareInvoke(t, "deploy", nefBytes, manifestBytes) + tx2 := managementInvoker.PrepareInvoke(t, "getContract", cs1.Hash.BytesBE()) + managementInvoker.AddNewBlock(t, tx1, tx2) + managementInvoker.CheckHalt(t, tx1.Hash(), si) + managementInvoker.CheckHalt(t, tx2.Hash(), si) + managementInvoker.CheckTxNotificationEvent(t, tx1.Hash(), 0, state.NotificationEvent{ + ScriptHash: c.NativeHash(t, nativenames.Management), + Name: "Deploy", + Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), + }) + t.Run("_deploy called", func(t *testing.T) { + helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash) + expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("create"), stackitem.Null{}}) + expectedBytes, err := stackitem.Serialize(expected) + require.NoError(t, err) + helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue") + }) + t.Run("get after deploy", func(t *testing.T) { + managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + }) + t.Run("get after restore", func(t *testing.T) { + w := io.NewBufBinWriter() + require.NoError(t, chaindump.Dump(c.Executor.Chain, w.BinWriter, 0, c.Executor.Chain.BlockHeight()+1)) + require.NoError(t, w.Err) + + r := io.NewBinReaderFromBuf(w.Bytes()) + bc2, acc := chain.NewSingle(t) + e2 := neotest.NewExecutor(t, bc2, acc, acc) + managementInvoker2 := e2.CommitteeInvoker(e2.NativeHash(t, nativenames.Management)) + + require.NoError(t, chaindump.Restore(bc2, r, 0, c.Executor.Chain.BlockHeight()+1, nil)) + require.NoError(t, r.Err) + managementInvoker2.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + }) + }) + t.Run("contract already exists", func(t *testing.T) { + managementInvoker.InvokeFail(t, "contract already exists", "deploy", nefBytes, manifestBytes) + }) + t.Run("failed _deploy", func(t *testing.T) { + deployScript := []byte{byte(opcode.ABORT)} + m := manifest.NewManifest("TestDeployAbort") + m.ABI.Methods = []manifest.Method{ + { + Name: manifest.MethodDeploy, + Offset: 0, + Parameters: []manifest.Parameter{ + manifest.NewParameter("data", smartcontract.AnyType), + manifest.NewParameter("isUpdate", smartcontract.BoolType), + }, + ReturnType: smartcontract.VoidType, + }, + } + nefD, err := nef.NewFile(deployScript) + require.NoError(t, err) + nefDb, err := nefD.Bytes() + require.NoError(t, err) + manifD, err := json.Marshal(m) + require.NoError(t, err) + managementInvoker.InvokeFail(t, "ABORT", "deploy", nefDb, manifD) + + t.Run("get after failed deploy", func(t *testing.T) { + h := state.CreateContractHash(c.CommitteeHash, nefD.Checksum, m.Name) + managementInvoker.Invoke(t, stackitem.Null{}, "getContract", h.BytesBE()) + }) + }) + t.Run("bad _deploy", func(t *testing.T) { // invalid _deploy signature + deployScript := []byte{byte(opcode.RET)} + m := manifest.NewManifest("TestBadDeploy") + m.ABI.Methods = []manifest.Method{ + { + Name: manifest.MethodDeploy, + Offset: 0, + Parameters: []manifest.Parameter{ + manifest.NewParameter("data", smartcontract.AnyType), + manifest.NewParameter("isUpdate", smartcontract.BoolType), + }, + ReturnType: smartcontract.ArrayType, + }, + } + nefD, err := nef.NewFile(deployScript) + require.NoError(t, err) + nefDb, err := nefD.Bytes() + require.NoError(t, err) + manifD, err := json.Marshal(m) + require.NoError(t, err) + managementInvoker.InvokeFail(t, "invalid return values count: expected 0, got 2", "deploy", nefDb, manifD) + + t.Run("get after bad _deploy", func(t *testing.T) { + h := state.CreateContractHash(c.CommitteeHash, nefD.Checksum, m.Name) + managementInvoker.Invoke(t, stackitem.Null{}, "getContract", h.BytesBE()) + }) + }) +} + +func TestManagement_StartFromHeight(t *testing.T) { + // Create database to be able to start another chain from the same height later. + ldbDir := t.TempDir() + dbConfig := storage.DBConfiguration{ + Type: "leveldb", + LevelDBOptions: storage.LevelDBOptions{ + DataDirectoryPath: ldbDir, + }, + } + newLevelStore, err := storage.NewLevelDBStore(dbConfig.LevelDBOptions) + require.Nil(t, err, "NewLevelDBStore error") + + // Create blockchain and put contract state to it. + bc, acc := chain.NewSingleWithCustomConfigAndStore(t, nil, newLevelStore, false) + go bc.Run() + e := neotest.NewExecutor(t, bc, acc, acc) + c := e.CommitteeInvoker(e.NativeHash(t, nativenames.Management)) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + manifestBytes, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nefBytes, err := cs1.NEF.Bytes() + require.NoError(t, err) + + si, err := cs1.ToStackItem() + require.NoError(t, err) + + managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes) + managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + + // Close current blockchain and start the new one from the same height with the same db. + bc.Close() + newLevelStore, err = storage.NewLevelDBStore(dbConfig.LevelDBOptions) + require.NoError(t, err) + bc2, acc := chain.NewSingleWithCustomConfigAndStore(t, nil, newLevelStore, true) + e2 := neotest.NewExecutor(t, bc2, acc, acc) + managementInvoker2 := e2.CommitteeInvoker(e2.NativeHash(t, nativenames.Management)) + + // Check that initialisation of native Management was correctly performed. + managementInvoker2.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) +} + +func TestManagement_DeployManifestOverflow(t *testing.T) { + c := newManagementClient(t) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + manif1, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nef1, err := nef.NewFile(cs1.NEF.Script) + require.NoError(t, err) + nef1b, err := nef1.Bytes() + require.NoError(t, err) + + w := io.NewBufBinWriter() + emit.Bytes(w.BinWriter, manif1) + emit.Int(w.BinWriter, manifest.MaxManifestSize) + emit.Opcodes(w.BinWriter, opcode.NEWBUFFER, opcode.CAT) + emit.Bytes(w.BinWriter, nef1b) + emit.Int(w.BinWriter, 2) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.AppCallNoArgs(w.BinWriter, managementInvoker.Hash, "deploy", callflag.All) + require.NoError(t, w.Err) + script := w.Bytes() + + tx := transaction.New(script, 0) + tx.ValidUntilBlock = managementInvoker.Chain.BlockHeight() + 1 + managementInvoker.SignTx(t, tx, 100_0000_0000, managementInvoker.Signers...) + managementInvoker.AddNewBlock(t, tx) + managementInvoker.CheckFault(t, tx.Hash(), fmt.Sprintf("invalid manifest: len is %d (max %d)", manifest.MaxManifestSize+len(manif1), manifest.MaxManifestSize)) +} + +func TestManagement_ContractDeployAndUpdateWithParameter(t *testing.T) { + c := newManagementClient(t) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} + cs1.ID = 1 + cs1.Hash = state.CreateContractHash(c.CommitteeHash, cs1.NEF.Checksum, cs1.Manifest.Name) + manif1, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nef1b, err := cs1.NEF.Bytes() + require.NoError(t, err) + + si, err := cs1.ToStackItem() + require.NoError(t, err) + managementInvoker.Invoke(t, si, "deploy", nef1b, manif1) + helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash) + + t.Run("_deploy called", func(t *testing.T) { + expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("create"), stackitem.Null{}}) + expectedBytes, err := stackitem.Serialize(expected) + require.NoError(t, err) + helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue") + }) + + cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET)) + cs1.NEF.Checksum = cs1.NEF.CalculateChecksum() + nef1b, err = cs1.NEF.Bytes() + require.NoError(t, err) + cs1.UpdateCounter++ + + helperInvoker.Invoke(t, stackitem.Null{}, "update", nef1b, nil, "new data") + + t.Run("_deploy called", func(t *testing.T) { + expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("update"), stackitem.Make("new data")}) + expectedBytes, err := stackitem.Serialize(expected) + require.NoError(t, err) + helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue") + }) +} + +func TestManagement_ContractUpdate(t *testing.T) { + c := newManagementClient(t) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + // Allow calling management contract. + cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} + manifestBytes, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nefBytes, err := cs1.NEF.Bytes() + require.NoError(t, err) + + si, err := cs1.ToStackItem() + require.NoError(t, err) + managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes) + helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash) + + t.Run("unknown contract", func(t *testing.T) { + managementInvoker.InvokeFail(t, "contract doesn't exist", "update", nefBytes, manifestBytes) + }) + t.Run("zero-length NEF", func(t *testing.T) { + helperInvoker.InvokeFail(t, "invalid NEF file: empty", "update", []byte{}, manifestBytes) + }) + t.Run("zero-length manifest", func(t *testing.T) { + helperInvoker.InvokeFail(t, "invalid manifest: empty", "update", nefBytes, []byte{}) + }) + t.Run("no real params", func(t *testing.T) { + helperInvoker.InvokeFail(t, "both NEF and manifest are nil", "update", nil, nil) + }) + t.Run("invalid manifest", func(t *testing.T) { + pkey, err := keys.NewPrivateKey() + require.NoError(t, err) + + var badManifest = cs1.Manifest + badManifest.Groups = []manifest.Group{{PublicKey: pkey.PublicKey(), Signature: make([]byte, 64)}} + manifB, err := json.Marshal(badManifest) + require.NoError(t, err) + + helperInvoker.InvokeFail(t, "invalid manifest: incorrect group signature", "update", nefBytes, manifB) + }) + t.Run("manifest and script mismatch", func(t *testing.T) { + nf, err := nef.FileFromBytes(nefBytes) // Make a full copy. + require.NoError(t, err) + nf.Script = append(nf.Script, byte(opcode.RET)) + copy(nf.Script[1:], nf.Script) // Now all method offsets are wrong. + nf.Script[0] = byte(opcode.RET) // Even though the script is correct. + nf.CalculateChecksum() + nefnew, err := nf.Bytes() + require.NoError(t, err) + helperInvoker.InvokeFail(t, "invalid NEF file: checksum verification failure", "update", nefnew, manifestBytes) + }) + + t.Run("change name", func(t *testing.T) { + var badManifest = cs1.Manifest + badManifest.Name += "tail" + manifB, err := json.Marshal(badManifest) + require.NoError(t, err) + + helperInvoker.InvokeFail(t, "contract name can't be changed", "update", nefBytes, manifB) + }) + + cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET)) + cs1.NEF.Checksum = cs1.NEF.CalculateChecksum() + nefBytes, err = cs1.NEF.Bytes() + require.NoError(t, err) + cs1.UpdateCounter++ + si, err = cs1.ToStackItem() + require.NoError(t, err) + + t.Run("update script, positive", func(t *testing.T) { + tx1 := helperInvoker.PrepareInvoke(t, "update", nefBytes, nil) + tx2 := managementInvoker.PrepareInvoke(t, "getContract", cs1.Hash.BytesBE()) + managementInvoker.AddNewBlock(t, tx1, tx2) + managementInvoker.CheckHalt(t, tx1.Hash(), stackitem.Null{}) + managementInvoker.CheckHalt(t, tx2.Hash(), si) + managementInvoker.CheckTxNotificationEvent(t, tx1.Hash(), 0, state.NotificationEvent{ + ScriptHash: c.NativeHash(t, nativenames.Management), + Name: "Update", + Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), + }) + t.Run("_deploy called", func(t *testing.T) { + helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash) + expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("update"), stackitem.Null{}}) + expectedBytes, err := stackitem.Serialize(expected) + require.NoError(t, err) + helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue") + }) + t.Run("check contract", func(t *testing.T) { + managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + }) + }) + + cs1.Manifest.Extra = []byte(`"update me"`) + manifestBytes, err = json.Marshal(cs1.Manifest) + require.NoError(t, err) + cs1.UpdateCounter++ + si, err = cs1.ToStackItem() + require.NoError(t, err) + + t.Run("update manifest, positive", func(t *testing.T) { + updHash := helperInvoker.Invoke(t, stackitem.Null{}, "update", nil, manifestBytes) + helperInvoker.CheckTxNotificationEvent(t, updHash, 0, state.NotificationEvent{ + ScriptHash: helperInvoker.NativeHash(t, nativenames.Management), + Name: "Update", + Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), + }) + t.Run("check contract", func(t *testing.T) { + managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + }) + }) + + cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.ABORT)) + cs1.NEF.Checksum = cs1.NEF.CalculateChecksum() + nefBytes, err = cs1.NEF.Bytes() + require.NoError(t, err) + cs1.Manifest.Extra = []byte(`"update me once more"`) + manifestBytes, err = json.Marshal(cs1.Manifest) + require.NoError(t, err) + cs1.UpdateCounter++ + si, err = cs1.ToStackItem() + require.NoError(t, err) + + t.Run("update both script and manifest", func(t *testing.T) { + updHash := helperInvoker.Invoke(t, stackitem.Null{}, "update", nefBytes, manifestBytes) + helperInvoker.CheckTxNotificationEvent(t, updHash, 0, state.NotificationEvent{ + ScriptHash: helperInvoker.NativeHash(t, nativenames.Management), + Name: "Update", + Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), + }) + t.Run("check contract", func(t *testing.T) { + managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + }) + }) +} + +func TestManagement_GetContract(t *testing.T) { + c := newManagementClient(t) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + manifestBytes, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nefBytes, err := cs1.NEF.Bytes() + require.NoError(t, err) + + si, err := cs1.ToStackItem() + require.NoError(t, err) + managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes) + + t.Run("bad parameter type", func(t *testing.T) { + managementInvoker.InvokeFail(t, "invalid conversion: Array/ByteString", "getContract", []interface{}{int64(1)}) + }) + t.Run("not a hash", func(t *testing.T) { + managementInvoker.InvokeFail(t, "expected byte size of 20 got 3", "getContract", []byte{1, 2, 3}) + }) + t.Run("positive", func(t *testing.T) { + managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE()) + }) +} + +func TestManagement_ContractDestroy(t *testing.T) { + c := newManagementClient(t) + managementInvoker := c.WithSigners(c.Committee) + + cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + // Allow calling management contract. + cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} + manifestBytes, err := json.Marshal(cs1.Manifest) + require.NoError(t, err) + nefBytes, err := cs1.NEF.Bytes() + require.NoError(t, err) + + si, err := cs1.ToStackItem() + require.NoError(t, err) + managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes) + helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash) + + t.Run("no contract", func(t *testing.T) { + managementInvoker.InvokeFail(t, "key not found", "destroy") + }) + t.Run("positive", func(t *testing.T) { + dstrHash := helperInvoker.Invoke(t, stackitem.Null{}, "destroy") + helperInvoker.CheckTxNotificationEvent(t, dstrHash, 0, state.NotificationEvent{ + ScriptHash: helperInvoker.NativeHash(t, nativenames.Management), + Name: "Destroy", + Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), + }) + t.Run("check contract", func(t *testing.T) { + managementInvoker.Invoke(t, stackitem.Null{}, "getContract", cs1.Hash.BytesBE()) + }) + }) +} diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index 803c5abba..563f40b9b 100644 --- a/pkg/core/native_contract_test.go +++ b/pkg/core/native_contract_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/interop" @@ -301,7 +302,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { } } - cs, _ := getTestContractState(chain) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, chain.contracts.Management.PutContractState(chain.dao, cs)) baseFee := chain.GetBaseExecFee() diff --git a/pkg/core/native_management_test.go b/pkg/core/native_management_test.go index dc3ca818e..d03009af0 100644 --- a/pkg/core/native_management_test.go +++ b/pkg/core/native_management_test.go @@ -1,617 +1,19 @@ package core import ( - "bytes" - "encoding/json" - "math/big" "testing" - "github.com/nspcc-dev/neo-go/internal/testchain" - "github.com/nspcc-dev/neo-go/pkg/config" - "github.com/nspcc-dev/neo-go/pkg/core/chaindump" - "github.com/nspcc-dev/neo-go/pkg/core/state" - "github.com/nspcc-dev/neo-go/pkg/core/stateroot" "github.com/nspcc-dev/neo-go/pkg/core/storage" - "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/nspcc-dev/neo-go/pkg/crypto/keys" - "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/smartcontract" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" - "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm" - "github.com/nspcc-dev/neo-go/pkg/vm/emit" - "github.com/nspcc-dev/neo-go/pkg/vm/opcode" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/stretchr/testify/require" ) -func TestDeployManifestOverflow(t *testing.T) { - bc := newTestChain(t) - - // nef.NewFile() cares about version a lot. - config.Version = "0.90.0-test" - mgmtHash := bc.ManagementContractHash() - cs1, _ := getTestContractState(bc) - cs1.ID = 1 - cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Checksum, cs1.Manifest.Name) - manif1, err := json.Marshal(cs1.Manifest) - require.NoError(t, err) - nef1, err := nef.NewFile(cs1.NEF.Script) - require.NoError(t, err) - nef1b, err := nef1.Bytes() - require.NoError(t, err) - - w := io.NewBufBinWriter() - emit.Bytes(w.BinWriter, manif1) - emit.Int(w.BinWriter, manifest.MaxManifestSize) - emit.Opcodes(w.BinWriter, opcode.NEWBUFFER, opcode.CAT) - emit.Bytes(w.BinWriter, nef1b) - emit.Int(w.BinWriter, 2) - emit.Opcodes(w.BinWriter, opcode.PACK) - emit.AppCallNoArgs(w.BinWriter, mgmtHash, "deploy", callflag.All) - require.NoError(t, w.Err) - script := w.Bytes() - - tx := transaction.New(script, 0) - tx.ValidUntilBlock = bc.blockHeight + 1 - addSigners(neoOwner, tx) - setTxSystemFee(bc, 100_00000000, tx) - require.NoError(t, testchain.SignTx(bc, tx)) - - aers, err := persistBlock(bc, tx) - require.NoError(t, err) - checkFAULTState(t, aers[0]) -} - type memoryStore struct { *storage.MemoryStore } func (memoryStore) Close() error { return nil } -func TestStartFromHeight(t *testing.T) { - st := memoryStore{storage.NewMemoryStore()} - bc := newTestChainWithCustomCfgAndStore(t, st, nil) - cs1, _ := getTestContractState(bc) - func() { - require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs1)) - checkContractState(t, bc, cs1.Hash, cs1) - _, err := bc.dao.Store.Persist() - require.NoError(t, err) - }() - - bc2 := newTestChainWithCustomCfgAndStore(t, st, nil) - checkContractState(t, bc2, cs1.Hash, cs1) -} - -func TestContractDeployAndUpdateWithParameter(t *testing.T) { - bc := newTestChain(t) - - // nef.NewFile() cares about version a lot. - config.Version = "0.90.0-test" - mgmtHash := bc.ManagementContractHash() - cs1, _ := getTestContractState(bc) - cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} - cs1.ID = 1 - cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Checksum, cs1.Manifest.Name) - manif1, err := json.Marshal(cs1.Manifest) - require.NoError(t, err) - nef1b, err := cs1.NEF.Bytes() - require.NoError(t, err) - - aer, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manif1, int64(42)) - require.NoError(t, err) - require.Equal(t, vm.HaltState, aer.VMState) - - t.Run("_deploy called", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue") - require.NoError(t, err) - require.Equal(t, 1, len(res.Stack)) - item, err := stackitem.Deserialize(res.Stack[0].Value().([]byte)) - require.NoError(t, err) - expected := []stackitem.Item{stackitem.Make("create"), stackitem.Make(42)} - require.Equal(t, stackitem.NewArray(expected), item) - }) - - cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET)) - cs1.NEF.Checksum = cs1.NEF.CalculateChecksum() - nef1b, err = cs1.NEF.Bytes() - require.NoError(t, err) - cs1.UpdateCounter++ - - aer, err = invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, nil, "new data") - require.NoError(t, err) - require.Equal(t, vm.HaltState, aer.VMState) - - t.Run("_deploy called", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue") - require.NoError(t, err) - require.Equal(t, 1, len(res.Stack)) - item, err := stackitem.Deserialize(res.Stack[0].Value().([]byte)) - require.NoError(t, err) - expected := []stackitem.Item{stackitem.Make("update"), stackitem.Make("new data")} - require.Equal(t, stackitem.NewArray(expected), item) - }) -} - -func TestContractDeploy(t *testing.T) { - bc := newTestChain(t) - - // nef.NewFile() cares about version a lot. - config.Version = "0.90.0-test" - mgmtHash := bc.ManagementContractHash() - cs1, _ := getTestContractState(bc) - cs1.ID = 1 - cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Checksum, cs1.Manifest.Name) - manif1, err := json.Marshal(cs1.Manifest) - require.NoError(t, err) - nef1b, err := cs1.NEF.Bytes() - require.NoError(t, err) - - t.Run("no NEF", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nil, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("no manifest", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, nil) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("int for NEF", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", int64(1), manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("zero-length NEF", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", []byte{}, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("array for NEF", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", []interface{}{int64(1)}, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("bad script in NEF", func(t *testing.T) { - nf, err := nef.FileFromBytes(nef1b) // make a full copy - require.NoError(t, err) - nf.Script[0] = 0xff - nf.CalculateChecksum() - nefbad, err := nf.Bytes() - require.NoError(t, err) - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nefbad, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("int for manifest", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, int64(1)) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("zero-length manifest", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, []byte{}) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("array for manifest", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, []interface{}{int64(1)}) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("non-utf8 manifest", func(t *testing.T) { - manifB := bytes.Replace(manif1, []byte("TestMain"), []byte("\xff\xfe\xfd"), 1) // Replace name. - - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manifB) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("invalid manifest", func(t *testing.T) { - pkey, err := keys.NewPrivateKey() - require.NoError(t, err) - - var badManifest = cs1.Manifest - badManifest.Groups = []manifest.Group{{PublicKey: pkey.PublicKey(), Signature: make([]byte, 64)}} - manifB, err := json.Marshal(badManifest) - require.NoError(t, err) - - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manifB) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("bad methods in manifest 1", func(t *testing.T) { - var badManifest = cs1.Manifest - badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) - copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) - badManifest.ABI.Methods[0].Offset = 100500 // out of bounds - - manifB, err := json.Marshal(badManifest) - require.NoError(t, err) - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manifB) - require.NoError(t, err) - checkFAULTState(t, res) - }) - - t.Run("bad methods in manifest 2", func(t *testing.T) { - var badManifest = cs1.Manifest - badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods)) - copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods) - badManifest.ABI.Methods[0].Offset = len(cs1.NEF.Script) - 2 // Ends with `CALLT(X,X);RET`. - - manifB, err := json.Marshal(badManifest) - require.NoError(t, err) - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manifB) - require.NoError(t, err) - checkFAULTState(t, res) - }) - - t.Run("not enough GAS", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "deploy", nef1b, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("positive", func(t *testing.T) { - tx1, err := prepareContractMethodInvoke(bc, 11_00000000, mgmtHash, "deploy", nef1b, manif1) - require.NoError(t, err) - tx2, err := prepareContractMethodInvoke(bc, 1_00000000, mgmtHash, "getContract", cs1.Hash.BytesBE()) - require.NoError(t, err) - - aers, err := persistBlock(bc, tx1, tx2) - require.NoError(t, err) - for _, res := range aers { - require.Equal(t, vm.HaltState, res.VMState) - require.Equal(t, 1, len(res.Stack)) - compareContractStates(t, cs1, res.Stack[0]) - } - require.Equal(t, aers[0].Events, []state.NotificationEvent{{ - ScriptHash: mgmtHash, - Name: "Deploy", - Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), - }}) - t.Run("_deploy called", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue") - require.NoError(t, err) - require.Equal(t, 1, len(res.Stack)) - item, err := stackitem.Deserialize(res.Stack[0].Value().([]byte)) - require.NoError(t, err) - expected := []stackitem.Item{stackitem.Make("create"), stackitem.Null{}} - require.Equal(t, stackitem.NewArray(expected), item) - }) - t.Run("get after deploy", func(t *testing.T) { - checkContractState(t, bc, cs1.Hash, cs1) - }) - t.Run("get after restore", func(t *testing.T) { - w := io.NewBufBinWriter() - require.NoError(t, chaindump.Dump(bc, w.BinWriter, 0, bc.BlockHeight()+1)) - require.NoError(t, w.Err) - - r := io.NewBinReaderFromBuf(w.Bytes()) - bc2 := newTestChain(t) - - require.NoError(t, chaindump.Restore(bc2, r, 0, bc.BlockHeight()+1, nil)) - require.NoError(t, r.Err) - checkContractState(t, bc2, cs1.Hash, cs1) - }) - }) - t.Run("contract already exists", func(t *testing.T) { - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nef1b, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("failed _deploy", func(t *testing.T) { - deployScript := []byte{byte(opcode.ABORT)} - m := manifest.NewManifest("TestDeployAbort") - m.ABI.Methods = []manifest.Method{ - { - Name: manifest.MethodDeploy, - Offset: 0, - Parameters: []manifest.Parameter{ - manifest.NewParameter("data", smartcontract.AnyType), - manifest.NewParameter("isUpdate", smartcontract.BoolType), - }, - ReturnType: smartcontract.VoidType, - }, - } - nefD, err := nef.NewFile(deployScript) - require.NoError(t, err) - nefDb, err := nefD.Bytes() - require.NoError(t, err) - manifD, err := json.Marshal(m) - require.NoError(t, err) - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nefDb, manifD) - require.NoError(t, err) - checkFAULTState(t, res) - - t.Run("get after failed deploy", func(t *testing.T) { - h := state.CreateContractHash(neoOwner, nefD.Checksum, m.Name) - checkContractState(t, bc, h, nil) - }) - }) - t.Run("bad _deploy", func(t *testing.T) { // invalid _deploy signature - deployScript := []byte{byte(opcode.RET)} - m := manifest.NewManifest("TestBadDeploy") - m.ABI.Methods = []manifest.Method{ - { - Name: manifest.MethodDeploy, - Offset: 0, - Parameters: []manifest.Parameter{ - manifest.NewParameter("data", smartcontract.AnyType), - manifest.NewParameter("isUpdate", smartcontract.BoolType), - }, - ReturnType: smartcontract.ArrayType, - }, - } - nefD, err := nef.NewFile(deployScript) - require.NoError(t, err) - nefDb, err := nefD.Bytes() - require.NoError(t, err) - manifD, err := json.Marshal(m) - require.NoError(t, err) - res, err := invokeContractMethod(bc, 11_00000000, mgmtHash, "deploy", nefDb, manifD) - require.NoError(t, err) - checkFAULTState(t, res) - - t.Run("get after bad _deploy", func(t *testing.T) { - h := state.CreateContractHash(neoOwner, nefD.Checksum, m.Name) - checkContractState(t, bc, h, nil) - }) - }) -} - -func checkContractState(t *testing.T, bc *Blockchain, h util.Uint160, cs *state.Contract) { - mgmtHash := bc.contracts.Management.Hash - res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "getContract", h.BytesBE()) - require.NoError(t, err) - require.Equal(t, vm.HaltState, res.VMState) - require.Equal(t, 1, len(res.Stack)) - if cs == nil { - require.Equal(t, stackitem.Null{}, res.Stack[0]) - } else { - compareContractStates(t, cs, res.Stack[0]) - } -} - -func TestContractUpdate(t *testing.T) { - bc := newTestChain(t) - - // nef.NewFile() cares about version a lot. - config.Version = "0.90.0-test" - mgmtHash := bc.ManagementContractHash() - cs1, _ := getTestContractState(bc) - // Allow calling management contract. - cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} - err := bc.contracts.Management.PutContractState(bc.dao, cs1) - require.NoError(t, err) - manif1, err := json.Marshal(cs1.Manifest) - require.NoError(t, err) - nef1, err := nef.NewFile(cs1.NEF.Script) - require.NoError(t, err) - nef1b, err := nef1.Bytes() - require.NoError(t, err) - - t.Run("no contract", func(t *testing.T) { - res, err := invokeContractMethod(bc, 10_00000000, mgmtHash, "update", nef1b, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("zero-length NEF", func(t *testing.T) { - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", []byte{}, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("zero-length manifest", func(t *testing.T) { - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, []byte{}) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("not enough GAS", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "update", nef1b, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("no real params", func(t *testing.T) { - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nil, nil) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("invalid manifest", func(t *testing.T) { - pkey, err := keys.NewPrivateKey() - require.NoError(t, err) - - var badManifest = cs1.Manifest - badManifest.Groups = []manifest.Group{{PublicKey: pkey.PublicKey(), Signature: make([]byte, 64)}} - manifB, err := json.Marshal(badManifest) - require.NoError(t, err) - - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, manifB) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("manifest and script mismatch", func(t *testing.T) { - nf, err := nef.FileFromBytes(nef1b) // Make a full copy. - require.NoError(t, err) - nf.Script = append(nf.Script, byte(opcode.RET)) - copy(nf.Script[1:], nf.Script) // Now all method offsets are wrong. - nf.Script[0] = byte(opcode.RET) // Even though the script is correct. - nf.CalculateChecksum() - nefnew, err := nf.Bytes() - require.NoError(t, err) - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nefnew, manif1) - require.NoError(t, err) - checkFAULTState(t, res) - }) - - t.Run("change name", func(t *testing.T) { - var badManifest = cs1.Manifest - badManifest.Name += "tail" - manifB, err := json.Marshal(badManifest) - require.NoError(t, err) - - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, manifB) - require.NoError(t, err) - checkFAULTState(t, res) - }) - - cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET)) - cs1.NEF.Checksum = cs1.NEF.CalculateChecksum() - nef1b, err = cs1.NEF.Bytes() - require.NoError(t, err) - cs1.UpdateCounter++ - - t.Run("update script, positive", func(t *testing.T) { - tx1, err := prepareContractMethodInvoke(bc, 10_00000000, cs1.Hash, "update", nef1b, nil) - require.NoError(t, err) - tx2, err := prepareContractMethodInvoke(bc, 1_00000000, mgmtHash, "getContract", cs1.Hash.BytesBE()) - require.NoError(t, err) - - aers, err := persistBlock(bc, tx1, tx2) - require.NoError(t, err) - require.Equal(t, vm.HaltState, aers[0].VMState) - require.Equal(t, vm.HaltState, aers[1].VMState) - require.Equal(t, 1, len(aers[1].Stack)) - compareContractStates(t, cs1, aers[1].Stack[0]) - require.Equal(t, aers[0].Events, []state.NotificationEvent{{ - ScriptHash: mgmtHash, - Name: "Update", - Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), - }}) - t.Run("_deploy called", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "getValue") - require.NoError(t, err) - require.Equal(t, 1, len(res.Stack)) - item, err := stackitem.Deserialize(res.Stack[0].Value().([]byte)) - require.NoError(t, err) - expected := []stackitem.Item{stackitem.Make("update"), stackitem.Null{}} - require.Equal(t, stackitem.NewArray(expected), item) - }) - t.Run("check contract", func(t *testing.T) { - checkContractState(t, bc, cs1.Hash, cs1) - }) - }) - - cs1.Manifest.Extra = []byte(`"update me"`) - manif1, err = json.Marshal(cs1.Manifest) - require.NoError(t, err) - cs1.UpdateCounter++ - - t.Run("update manifest, positive", func(t *testing.T) { - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nil, manif1) - require.NoError(t, err) - require.Equal(t, vm.HaltState, res.VMState) - require.Equal(t, res.Events, []state.NotificationEvent{{ - ScriptHash: mgmtHash, - Name: "Update", - Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), - }}) - t.Run("check contract", func(t *testing.T) { - checkContractState(t, bc, cs1.Hash, cs1) - }) - }) - - cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.ABORT)) - cs1.NEF.Checksum = cs1.NEF.CalculateChecksum() - nef1b, err = cs1.NEF.Bytes() - require.NoError(t, err) - cs1.Manifest.Extra = []byte(`"update me once more"`) - manif1, err = json.Marshal(cs1.Manifest) - require.NoError(t, err) - cs1.UpdateCounter++ - - t.Run("update both script and manifest", func(t *testing.T) { - res, err := invokeContractMethod(bc, 10_00000000, cs1.Hash, "update", nef1b, manif1) - require.NoError(t, err) - require.Equal(t, vm.HaltState, res.VMState) - require.Equal(t, res.Events, []state.NotificationEvent{{ - ScriptHash: mgmtHash, - Name: "Update", - Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), - }}) - t.Run("check contract", func(t *testing.T) { - checkContractState(t, bc, cs1.Hash, cs1) - }) - }) -} - -func TestGetContract(t *testing.T) { - bc := newTestChain(t) - - mgmtHash := bc.ManagementContractHash() - cs1, _ := getTestContractState(bc) - err := bc.contracts.Management.PutContractState(bc.dao, cs1) - require.NoError(t, err) - - t.Run("bad parameter type", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "getContract", []interface{}{int64(1)}) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("not a hash", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "getContract", []byte{1, 2, 3}) - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("positive", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "getContract", cs1.Hash.BytesBE()) - require.NoError(t, err) - require.Equal(t, 1, len(res.Stack)) - compareContractStates(t, cs1, res.Stack[0]) - }) -} - -func TestContractDestroy(t *testing.T) { - bc := newTestChain(t) - - mgmtHash := bc.ManagementContractHash() - cs1, _ := getTestContractState(bc) - // Allow calling management contract. - cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} - err := bc.contracts.Management.PutContractState(bc.dao, cs1) - require.NoError(t, err) - err = bc.dao.PutStorageItem(cs1.ID, []byte{1, 2, 3}, state.StorageItem{3, 2, 1}) - require.NoError(t, err) - b := bc.dao.GetMPTBatch() - _, _, err = bc.GetStateModule().(*stateroot.Module).AddMPTBatch(bc.BlockHeight(), b, bc.dao.Store) - require.NoError(t, err) - - t.Run("no contract", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, mgmtHash, "destroy") - require.NoError(t, err) - checkFAULTState(t, res) - }) - t.Run("positive", func(t *testing.T) { - res, err := invokeContractMethod(bc, 1_00000000, cs1.Hash, "destroy") - require.NoError(t, err) - require.Equal(t, vm.HaltState, res.VMState) - require.Equal(t, res.Events, []state.NotificationEvent{{ - ScriptHash: mgmtHash, - Name: "Destroy", - Item: stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}), - }}) - t.Run("check contract", func(t *testing.T) { - checkContractState(t, bc, cs1.Hash, nil) - }) - }) -} - -func compareContractStates(t *testing.T, expected *state.Contract, actual stackitem.Item) { - act, ok := actual.Value().([]stackitem.Item) - require.True(t, ok) - - expectedManifest, err := expected.Manifest.ToStackItem() - require.NoError(t, err) - expectedNef, err := expected.NEF.Bytes() - require.NoError(t, err) - - require.Equal(t, 5, len(act)) - require.Equal(t, expected.ID, int32(act[0].Value().(*big.Int).Int64())) - require.Equal(t, expected.UpdateCounter, uint16(act[1].Value().(*big.Int).Int64())) - require.Equal(t, expected.Hash.BytesBE(), act[2].Value().([]byte)) - require.Equal(t, expectedNef, act[3].Value().([]byte)) - require.Equal(t, expectedManifest, act[4]) -} - func TestMinimumDeploymentFee(t *testing.T) { chain := newTestChain(t) @@ -619,8 +21,6 @@ func TestMinimumDeploymentFee(t *testing.T) { n := chain.contracts.Management.GetMinimumDeploymentFee(chain.dao) require.Equal(t, 10_00000000, int(n)) }) - - testGetSet(t, chain, chain.contracts.Management.Hash, "MinimumDeploymentFee", 10_00000000, 0, 0) } func TestManagement_GetNEP17Contracts(t *testing.T) { diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go index e96915250..fae508fc9 100644 --- a/pkg/core/native_neo_test.go +++ b/pkg/core/native_neo_test.go @@ -318,7 +318,7 @@ func TestNEO_CommitteeBountyOnPersist(t *testing.T) { func TestNEO_TransferOnPayment(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(bc) + cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) const amount = 2 diff --git a/pkg/core/test_data/management_helper/README.md b/pkg/core/test_data/management_helper/README.md new file mode 100644 index 000000000..853e322f6 --- /dev/null +++ b/pkg/core/test_data/management_helper/README.md @@ -0,0 +1,9 @@ +## Management helper contracts + +Management helper contracts NEF and manifest files are generated automatically by +`TestGenerateManagementHelperContracts` and are used in tests. Do not modify these files manually. +To regenerate these files: + +1. Open `TestGenerateManagementHelperContracts` and set `saveState` flag to `true`. +2. Run `TestGenerateManagementHelperContracts`. +3. Set `saveState` back to `false`. \ No newline at end of file diff --git a/pkg/core/test_data/management_helper/management_helper1.manifest.json b/pkg/core/test_data/management_helper/management_helper1.manifest.json new file mode 100755 index 000000000..baea0b094 --- /dev/null +++ b/pkg/core/test_data/management_helper/management_helper1.manifest.json @@ -0,0 +1 @@ +{"name":"TestMain","abi":{"methods":[{"name":"add","offset":1,"parameters":[{"name":"addend1","type":"Integer"},{"name":"addend2","type":"Integer"}],"returntype":"Integer","safe":false},{"name":"add","offset":3,"parameters":[{"name":"addend1","type":"Integer"},{"name":"addend2","type":"Integer"},{"name":"addend3","type":"Integer"}],"returntype":"Integer","safe":false},{"name":"ret7","offset":6,"parameters":[],"returntype":"Integer","safe":false},{"name":"drop","offset":8,"parameters":null,"returntype":"Void","safe":false},{"name":"_initialize","offset":10,"parameters":null,"returntype":"Void","safe":false},{"name":"add3","offset":15,"parameters":[{"name":"addend","type":"Integer"}],"returntype":"Integer","safe":false},{"name":"invalidReturn","offset":18,"parameters":null,"returntype":"Integer","safe":false},{"name":"justReturn","offset":21,"parameters":null,"returntype":"Void","safe":false},{"name":"verify","offset":22,"parameters":null,"returntype":"Boolean","safe":false},{"name":"_deploy","offset":27,"parameters":[{"name":"data","type":"Any"},{"name":"isUpdate","type":"Boolean"}],"returntype":"Void","safe":false},{"name":"getValue","offset":158,"parameters":null,"returntype":"String","safe":false},{"name":"putValue","offset":138,"parameters":[{"name":"value","type":"String"}],"returntype":"Void","safe":false},{"name":"delValue","offset":178,"parameters":[{"name":"key","type":"String"}],"returntype":"Void","safe":false},{"name":"onNEP11Payment","offset":215,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"tokenid","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"onNEP17Payment","offset":189,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"update","offset":244,"parameters":[{"name":"nef","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"update","offset":241,"parameters":[{"name":"nef","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"destroy","offset":284,"parameters":null,"returntype":"Void","safe":false},{"name":"invalidStack","offset":325,"parameters":null,"returntype":"Void","safe":false},{"name":"callT0","offset":335,"parameters":[{"name":"address","type":"Hash160"}],"returntype":"Integer","safe":false},{"name":"callT1","offset":341,"parameters":null,"returntype":"Integer","safe":false},{"name":"callT2","offset":345,"parameters":null,"returntype":"Integer","safe":false},{"name":"burnGas","offset":349,"parameters":[{"name":"amount","type":"Integer"}],"returntype":"Void","safe":false},{"name":"invocCounter","offset":355,"parameters":null,"returntype":"Integer","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","methods":["balanceOf"]},{"contract":"0x0000000000000000000000000000000000000000","methods":["method"]}],"supportedstandards":[],"trusts":[],"extra":null} \ No newline at end of file diff --git a/pkg/core/test_data/management_helper/management_helper1.nef b/pkg/core/test_data/management_helper/management_helper1.nef new file mode 100755 index 0000000000000000000000000000000000000000..bccf14cdc1a994f5e1753af71b31e28194ab6fc2 GIT binary patch literal 506 zcmeZsbu-RO&DTxO*JU6dFnvva<*-M?)|ZdjOHTDqV`N}t z#AY~KZfZ$JehLFv`fnzq#XN_3^Blw-Tphv~g%cbi<~axoIXFbjzpda9pkl$pmRyvY zSduDqK=6P(4`*>|QD$OJW>qSW$bt8k=N>$Hse0_tf~?AiF1$DL&#iGxs*MgZv2@^J zD=kPNQ5UlV4|`@_W(m-I$JyV~&pAG`muNv3n-u%P&;cT?A93`pgQI0|o{h)>9&Vq+ z;*x;G%G}hv633~G`H2u2QIJeNnvAd#vk=fPP$%+;{9XLZ+3i)ZmTLcz>37%OPBB0E z_dnPpt_}h~b?hmr#U(}gm3S2%^71