diff --git a/internal/contracts/contracts.go b/internal/contracts/contracts.go new file mode 100644 index 000000000..d922985ff --- /dev/null +++ b/internal/contracts/contracts.go @@ -0,0 +1,103 @@ +package contracts + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/state" + "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/stretchr/testify/require" +) + +var ( + helper1ContractNEFPath = filepath.Join("management_helper", "management_helper1.nef") + helper1ContractManifestPath = filepath.Join("management_helper", "management_helper1.manifest.json") + helper2ContractNEFPath = filepath.Join("management_helper", "management_helper2.nef") + helper2ContractManifestPath = filepath.Join("management_helper", "management_helper2.manifest.json") + + oracleContractNEFPath = filepath.Join("oracle_contract", "oracle.nef") + oracleContractManifestPath = filepath.Join("oracle_contract", "oracle.manifest.json") +) + +// GetTestContractState reads 2 pre-compiled contracts generated by +// TestGenerateHelperContracts second of which is allowed to call the first. +func GetTestContractState(t *testing.T, pathToInternalContracts string, id1, id2 int32, sender2 util.Uint160) (*state.Contract, *state.Contract) { + errNotFound := errors.New("auto-generated oracle contract is not found, use TestGenerateHelperContracts to regenerate") + neBytes, err := os.ReadFile(filepath.Join(pathToInternalContracts, helper1ContractNEFPath)) + require.NoError(t, err, fmt.Errorf("nef1: %w", errNotFound)) + ne, err := nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err := os.ReadFile(filepath.Join(pathToInternalContracts, 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 = os.ReadFile(filepath.Join(pathToInternalContracts, helper2ContractNEFPath)) + require.NoError(t, err, fmt.Errorf("nef2: %w", errNotFound)) + ne, err = nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err = os.ReadFile(filepath.Join(pathToInternalContracts, 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 +} + +// GetOracleContractState reads pre-compiled oracle contract generated by +// TestGenerateHelperContracts and returns its state. +func GetOracleContractState(t *testing.T, pathToInternalContracts string, sender util.Uint160, id int32) *state.Contract { + errNotFound := errors.New("auto-generated oracle contract is not found, use TestGenerateHelperContracts to regenerate") + + neBytes, err := os.ReadFile(filepath.Join(pathToInternalContracts, oracleContractNEFPath)) + require.NoError(t, err, fmt.Errorf("nef: %w", errNotFound)) + ne, err := nef.FileFromBytes(neBytes) + require.NoError(t, err) + + mBytes, err := os.ReadFile(filepath.Join(pathToInternalContracts, oracleContractManifestPath)) + require.NoError(t, err, fmt.Errorf("manifest: %w", errNotFound)) + m := &manifest.Manifest{} + err = json.Unmarshal(mBytes, m) + require.NoError(t, err) + + return &state.Contract{ + ContractBase: state.ContractBase{ + NEF: ne, + Hash: state.CreateContractHash(sender, ne.Checksum, m.Name), + Manifest: *m, + ID: id, + }, + } +} diff --git a/internal/contracts/contracts_test.go b/internal/contracts/contracts_test.go new file mode 100644 index 000000000..77cd71e18 --- /dev/null +++ b/internal/contracts/contracts_test.go @@ -0,0 +1,495 @@ +package contracts + +import ( + "encoding/json" + "os" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/config" + "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" + "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/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" +) + +// TestGenerateHelperContracts generates contract states that are used in tests. +// See generateOracleContract and generateManagementHelperContracts comments for +// details. +func TestGenerateHelperContracts(t *testing.T) { + const saveState = false + + generateOracleContract(t, saveState) + generateManagementHelperContracts(t, saveState) + + require.False(t, saveState) +} + +// generateOracleContract generates helper contract that is able to call +// native Oracle contract and has callback method. It uses test chain to define +// Oracle and StdLib native hashes and saves generated NEF and manifest to `oracle_contract` folder. +// Set `saveState` flag to true and run the test to rewrite NEF and manifest files. +func generateOracleContract(t *testing.T, saveState bool) { + bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { + c.P2PSigExtensions = true + }) + e := neotest.NewExecutor(t, bc, validator, committee) + + oracleHash := e.NativeHash(t, nativenames.Oracle) + stdHash := e.NativeHash(t, nativenames.StdLib) + + w := io.NewBufBinWriter() + emit.Int(w.BinWriter, 5) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.Int(w.BinWriter, int64(callflag.All)) + emit.String(w.BinWriter, "request") + emit.Bytes(w.BinWriter, oracleHash.BytesBE()) + emit.Syscall(w.BinWriter, interopnames.SystemContractCall) + emit.Opcodes(w.BinWriter, opcode.DROP) + emit.Opcodes(w.BinWriter, opcode.RET) + + // `handle` method aborts if len(userData) == 2 and does NOT perform witness checks + // for the sake of contract code simplicity (the contract is used in multiple testchains). + offset := w.Len() + + emit.Opcodes(w.BinWriter, opcode.OVER) + emit.Opcodes(w.BinWriter, opcode.SIZE) + emit.Int(w.BinWriter, 2) + emit.Instruction(w.BinWriter, opcode.JMPNE, []byte{3}) + emit.Opcodes(w.BinWriter, opcode.ABORT) + emit.Int(w.BinWriter, 4) // url, userData, code, result + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`) + emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`) + emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes + emit.String(w.BinWriter, "lastOracleResponse") + emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) + emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) + emit.Opcodes(w.BinWriter, opcode.RET) + + m := manifest.NewManifest("TestOracle") + m.ABI.Methods = []manifest.Method{ + { + Name: "requestURL", + Offset: 0, + Parameters: []manifest.Parameter{ + manifest.NewParameter("url", smartcontract.StringType), + manifest.NewParameter("filter", smartcontract.StringType), + manifest.NewParameter("callback", smartcontract.StringType), + manifest.NewParameter("userData", smartcontract.AnyType), + manifest.NewParameter("gasForResponse", smartcontract.IntegerType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "handle", + Offset: offset, + Parameters: []manifest.Parameter{ + manifest.NewParameter("url", smartcontract.StringType), + manifest.NewParameter("userData", smartcontract.AnyType), + manifest.NewParameter("code", smartcontract.IntegerType), + manifest.NewParameter("result", smartcontract.ByteArrayType), + }, + ReturnType: smartcontract.VoidType, + }, + } + + perm := manifest.NewPermission(manifest.PermissionHash, oracleHash) + perm.Methods.Add("request") + m.Permissions = append(m.Permissions, *perm) + + // Generate NEF file. + script := w.Bytes() + ne, err := nef.NewFile(script) + require.NoError(t, err) + + // Write NEF file. + bytes, err := ne.Bytes() + require.NoError(t, err) + if saveState { + err = os.WriteFile(oracleContractNEFPath, bytes, os.ModePerm) + require.NoError(t, err) + } + + // Write manifest file. + mData, err := json.Marshal(m) + require.NoError(t, err) + if saveState { + err = os.WriteFile(oracleContractManifestPath, mData, os.ModePerm) + require.NoError(t, err) + } +} + +// generateManagementHelperContracts 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 `management_contract` folder. +// Set `saveState` flag to true and run the test to rewrite NEF and manifest files. +func generateManagementHelperContracts(t *testing.T, saveState bool) { + bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { + c.P2PSigExtensions = true + }) + e := neotest.NewExecutor(t, bc, validator, committee) + + mgmtHash := e.NativeHash(t, nativenames.Management) + stdHash := e.NativeHash(t, nativenames.StdLib) + neoHash := e.NativeHash(t, nativenames.Neo) + singleChainValidatorAcc := e.Validator.(neotest.MultiSigner).Single(2).Account() // priv0 + require.NoError(t, singleChainValidatorAcc.ConvertMultisig(1, keys.PublicKeys{singleChainValidatorAcc.PrivateKey().PublicKey()})) + singleChainValidatorHash := singleChainValidatorAcc.Contract.ScriptHash() + + w := io.NewBufBinWriter() + emit.Opcodes(w.BinWriter, opcode.ABORT) + addOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.ADD, opcode.RET) + addMultiOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.ADD, opcode.ADD, opcode.RET) + ret7Off := w.Len() + emit.Opcodes(w.BinWriter, opcode.PUSH7, opcode.RET) + dropOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.DROP, opcode.RET) + initOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.INITSSLOT, 1, opcode.PUSH3, opcode.STSFLD0, opcode.RET) + add3Off := w.Len() + emit.Opcodes(w.BinWriter, opcode.LDSFLD0, opcode.ADD, opcode.RET) + invalidRetOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.PUSH1, opcode.PUSH2, opcode.RET) + justRetOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.RET) + verifyOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.LDSFLD0, opcode.SUB, + opcode.CONVERT, opcode.Opcode(stackitem.BooleanT), opcode.RET) + deployOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.SWAP, opcode.JMPIF, 2+8+1+1+1+1+39+3) + emit.String(w.BinWriter, "create") // 8 bytes + emit.Int(w.BinWriter, 2) // 1 byte + emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte + emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`) + emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`) + emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes + emit.Opcodes(w.BinWriter, opcode.CALL, 3+8+1+1+1+1+39+3, opcode.RET) + emit.String(w.BinWriter, "update") // 8 bytes + emit.Int(w.BinWriter, 2) // 1 byte + emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte + emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`) + emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`) + emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes + emit.Opcodes(w.BinWriter, opcode.CALL, 3, opcode.RET) + putValOff := w.Len() + emit.String(w.BinWriter, "initial") + emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) + emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) + emit.Opcodes(w.BinWriter, opcode.RET) + getValOff := w.Len() + emit.String(w.BinWriter, "initial") + emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) + emit.Syscall(w.BinWriter, interopnames.SystemStorageGet) + emit.Opcodes(w.BinWriter, opcode.RET) + delValOff := w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) + emit.Syscall(w.BinWriter, interopnames.SystemStorageDelete) + emit.Opcodes(w.BinWriter, opcode.RET) + onNEP17PaymentOff := w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash) + emit.Int(w.BinWriter, 4) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.String(w.BinWriter, "LastPayment") + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) + emit.Opcodes(w.BinWriter, opcode.RET) + onNEP11PaymentOff := w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash) + emit.Int(w.BinWriter, 5) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.String(w.BinWriter, "LostPayment") + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) + emit.Opcodes(w.BinWriter, opcode.RET) + update3Off := w.Len() + emit.Int(w.BinWriter, 3) + emit.Opcodes(w.BinWriter, opcode.JMP, 2+1) + updateOff := w.Len() + emit.Int(w.BinWriter, 2) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.AppCallNoArgs(w.BinWriter, mgmtHash, "update", callflag.All) + emit.Opcodes(w.BinWriter, opcode.DROP) + emit.Opcodes(w.BinWriter, opcode.RET) + destroyOff := w.Len() + emit.AppCall(w.BinWriter, mgmtHash, "destroy", callflag.All) + emit.Opcodes(w.BinWriter, opcode.DROP) + emit.Opcodes(w.BinWriter, opcode.RET) + invalidStackOff := w.Len() + emit.Opcodes(w.BinWriter, opcode.NEWARRAY0, opcode.DUP, opcode.DUP, opcode.APPEND) // recursive array + emit.Syscall(w.BinWriter, interopnames.SystemStorageGetReadOnlyContext) // interop item + emit.Opcodes(w.BinWriter, opcode.RET) + callT0Off := w.Len() + emit.Opcodes(w.BinWriter, opcode.CALLT, 0, 0, opcode.PUSH1, opcode.ADD, opcode.RET) + callT1Off := w.Len() + emit.Opcodes(w.BinWriter, opcode.CALLT, 1, 0, opcode.RET) + callT2Off := w.Len() + emit.Opcodes(w.BinWriter, opcode.CALLT, 0, 0, opcode.RET) + burnGasOff := w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeBurnGas) + emit.Opcodes(w.BinWriter, opcode.RET) + invocCounterOff := w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetInvocationCounter) + emit.Opcodes(w.BinWriter, opcode.RET) + + script := w.Bytes() + m := manifest.NewManifest("TestMain") + m.ABI.Methods = []manifest.Method{ + { + Name: "add", + Offset: addOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("addend1", smartcontract.IntegerType), + manifest.NewParameter("addend2", smartcontract.IntegerType), + }, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "add", + Offset: addMultiOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("addend1", smartcontract.IntegerType), + manifest.NewParameter("addend2", smartcontract.IntegerType), + manifest.NewParameter("addend3", smartcontract.IntegerType), + }, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "ret7", + Offset: ret7Off, + Parameters: []manifest.Parameter{}, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "drop", + Offset: dropOff, + ReturnType: smartcontract.VoidType, + }, + { + Name: manifest.MethodInit, + Offset: initOff, + ReturnType: smartcontract.VoidType, + }, + { + Name: "add3", + Offset: add3Off, + Parameters: []manifest.Parameter{ + manifest.NewParameter("addend", smartcontract.IntegerType), + }, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "invalidReturn", + Offset: invalidRetOff, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "justReturn", + Offset: justRetOff, + ReturnType: smartcontract.VoidType, + }, + { + Name: manifest.MethodVerify, + Offset: verifyOff, + ReturnType: smartcontract.BoolType, + }, + { + Name: manifest.MethodDeploy, + Offset: deployOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("data", smartcontract.AnyType), + manifest.NewParameter("isUpdate", smartcontract.BoolType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "getValue", + Offset: getValOff, + ReturnType: smartcontract.StringType, + }, + { + Name: "putValue", + Offset: putValOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("value", smartcontract.StringType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "delValue", + Offset: delValOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("key", smartcontract.StringType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: manifest.MethodOnNEP11Payment, + Offset: onNEP11PaymentOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("from", smartcontract.Hash160Type), + manifest.NewParameter("amount", smartcontract.IntegerType), + manifest.NewParameter("tokenid", smartcontract.ByteArrayType), + manifest.NewParameter("data", smartcontract.AnyType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: manifest.MethodOnNEP17Payment, + Offset: onNEP17PaymentOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("from", smartcontract.Hash160Type), + manifest.NewParameter("amount", smartcontract.IntegerType), + manifest.NewParameter("data", smartcontract.AnyType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "update", + Offset: updateOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("nef", smartcontract.ByteArrayType), + manifest.NewParameter("manifest", smartcontract.ByteArrayType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "update", + Offset: update3Off, + Parameters: []manifest.Parameter{ + manifest.NewParameter("nef", smartcontract.ByteArrayType), + manifest.NewParameter("manifest", smartcontract.ByteArrayType), + manifest.NewParameter("data", smartcontract.AnyType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "destroy", + Offset: destroyOff, + ReturnType: smartcontract.VoidType, + }, + { + Name: "invalidStack", + Offset: invalidStackOff, + ReturnType: smartcontract.VoidType, + }, + { + Name: "callT0", + Offset: callT0Off, + Parameters: []manifest.Parameter{ + manifest.NewParameter("address", smartcontract.Hash160Type), + }, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "callT1", + Offset: callT1Off, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "callT2", + Offset: callT2Off, + ReturnType: smartcontract.IntegerType, + }, + { + Name: "burnGas", + Offset: burnGasOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("amount", smartcontract.IntegerType), + }, + ReturnType: smartcontract.VoidType, + }, + { + Name: "invocCounter", + Offset: invocCounterOff, + ReturnType: smartcontract.IntegerType, + }, + } + m.Permissions = make([]manifest.Permission, 2) + m.Permissions[0].Contract.Type = manifest.PermissionHash + m.Permissions[0].Contract.Value = neoHash + m.Permissions[0].Methods.Add("balanceOf") + + m.Permissions[1].Contract.Type = manifest.PermissionHash + m.Permissions[1].Contract.Value = util.Uint160{} + m.Permissions[1].Methods.Add("method") + + // Generate NEF file. + ne, err := nef.NewFile(script) + require.NoError(t, err) + ne.Tokens = []nef.MethodToken{ + { + Hash: neoHash, + Method: "balanceOf", + ParamCount: 1, + HasReturn: true, + CallFlag: callflag.ReadStates, + }, + { + Hash: util.Uint160{}, + Method: "method", + HasReturn: true, + CallFlag: callflag.ReadStates, + }, + } + ne.Checksum = ne.CalculateChecksum() + + // Write first NEF file. + bytes, err := ne.Bytes() + require.NoError(t, err) + if saveState { + err = os.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 = os.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") + perm := manifest.NewPermission(manifest.PermissionHash, h) + perm.Methods.Add("add") + perm.Methods.Add("drop") + perm.Methods.Add("add3") + perm.Methods.Add("invalidReturn") + perm.Methods.Add("justReturn") + perm.Methods.Add("getValue") + m.Permissions = append(m.Permissions, *perm) + ne, err = nef.NewFile(currScript) + require.NoError(t, err) + + // Write second NEF file. + bytes, err = ne.Bytes() + require.NoError(t, err) + if saveState { + err = os.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 = os.WriteFile(helper2ContractManifestPath, mData, os.ModePerm) + require.NoError(t, err) + } +} diff --git a/internal/contracts/management_helper/README.md b/internal/contracts/management_helper/README.md new file mode 100644 index 000000000..888580153 --- /dev/null +++ b/internal/contracts/management_helper/README.md @@ -0,0 +1,9 @@ +## Management helper contracts + +Management helper contracts NEF and manifest files are generated automatically by +`TestGenerateHelperContracts` and are used in tests. Do not modify these files manually. +To regenerate these files: + +1. Open `TestGenerateHelperContracts` and set `saveState` flag to `true`. +2. Run `TestGenerateHelperContracts`. +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/internal/contracts/management_helper/management_helper1.manifest.json old mode 100755 new mode 100644 similarity index 100% rename from pkg/core/test_data/management_helper/management_helper1.manifest.json rename to internal/contracts/management_helper/management_helper1.manifest.json diff --git a/pkg/core/test_data/management_helper/management_helper1.nef b/internal/contracts/management_helper/management_helper1.nef old mode 100755 new mode 100644 similarity index 100% rename from pkg/core/test_data/management_helper/management_helper1.nef rename to internal/contracts/management_helper/management_helper1.nef diff --git a/pkg/core/test_data/management_helper/management_helper2.manifest.json b/internal/contracts/management_helper/management_helper2.manifest.json old mode 100755 new mode 100644 similarity index 100% rename from pkg/core/test_data/management_helper/management_helper2.manifest.json rename to internal/contracts/management_helper/management_helper2.manifest.json diff --git a/pkg/core/test_data/management_helper/management_helper2.nef b/internal/contracts/management_helper/management_helper2.nef old mode 100755 new mode 100644 similarity index 100% rename from pkg/core/test_data/management_helper/management_helper2.nef rename to internal/contracts/management_helper/management_helper2.nef diff --git a/internal/contracts/oracle_contract/README.md b/internal/contracts/oracle_contract/README.md new file mode 100644 index 000000000..d57d41cc4 --- /dev/null +++ b/internal/contracts/oracle_contract/README.md @@ -0,0 +1,9 @@ +## Oracle helper contract + +Oracle helper contract NEF and manifest files are generated automatically by +`TestGenerateHelperContracts` and are used in tests. Do not modify these files manually. +To regenerate these files: + +1. Open `TestGenerateHelperContracts` and set `saveState` flag to `true`. +2. Run `TestGenerateHelperContracts`. +3. Set `saveState` back to `false`. \ No newline at end of file diff --git a/pkg/core/test_data/oracle_contract/oracle.manifest.json b/internal/contracts/oracle_contract/oracle.manifest.json old mode 100755 new mode 100644 similarity index 100% rename from pkg/core/test_data/oracle_contract/oracle.manifest.json rename to internal/contracts/oracle_contract/oracle.manifest.json diff --git a/pkg/core/test_data/oracle_contract/oracle.nef b/internal/contracts/oracle_contract/oracle.nef old mode 100755 new mode 100644 similarity index 100% rename from pkg/core/test_data/oracle_contract/oracle.nef rename to internal/contracts/oracle_contract/oracle.nef diff --git a/pkg/core/blockchain_core_test.go b/pkg/core/blockchain_core_test.go index 808c997c4..93791d447 100644 --- a/pkg/core/blockchain_core_test.go +++ b/pkg/core/blockchain_core_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/config" @@ -1118,7 +1119,7 @@ func TestVerifyTx(t *testing.T) { func TestVerifyHashAgainstScript(t *testing.T) { bc := newTestChain(t) - cs, csInvalid := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, csInvalid := contracts.GetTestContractState(t, pathToInternalContracts, 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)) @@ -1695,7 +1696,7 @@ func TestRemoveUntraceable(t *testing.T) { func TestInvalidNotification(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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") @@ -1709,7 +1710,7 @@ func TestInvalidNotification(t *testing.T) { func TestMPTDeleteNoKey(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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/interop_system_test.go b/pkg/core/interop_system_test.go index 07771e534..f46b04e2b 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -1,15 +1,13 @@ package core import ( - "encoding/json" "errors" "fmt" "math" "math/big" - "os" - "path/filepath" "testing" + "github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/testchain" "github.com/nspcc-dev/neo-go/pkg/config" @@ -39,7 +37,6 @@ 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" ) @@ -235,7 +232,7 @@ func TestRuntimeGetNotifications(t *testing.T) { func TestRuntimeGetInvocationCounter(t *testing.T) { v, ic, bc := createVM(t) - cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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 @@ -661,432 +658,6 @@ func createVMAndContractState(t testing.TB) (*vm.VM, *state.Contract, *interop.C return v, contractState, 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") -) - -// 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) - addOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.ADD, opcode.RET) - addMultiOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.ADD, opcode.ADD, opcode.RET) - ret7Off := w.Len() - emit.Opcodes(w.BinWriter, opcode.PUSH7, opcode.RET) - dropOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.DROP, opcode.RET) - initOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.INITSSLOT, 1, opcode.PUSH3, opcode.STSFLD0, opcode.RET) - add3Off := w.Len() - emit.Opcodes(w.BinWriter, opcode.LDSFLD0, opcode.ADD, opcode.RET) - invalidRetOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.PUSH1, opcode.PUSH2, opcode.RET) - justRetOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.RET) - verifyOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.LDSFLD0, opcode.SUB, - opcode.CONVERT, opcode.Opcode(stackitem.BooleanT), opcode.RET) - deployOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.SWAP, opcode.JMPIF, 2+8+1+1+1+1+39+3) - emit.String(w.BinWriter, "create") // 8 bytes - emit.Int(w.BinWriter, 2) // 1 byte - emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte - emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`) - emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`) - emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes - emit.Opcodes(w.BinWriter, opcode.CALL, 3+8+1+1+1+1+39+3, opcode.RET) - emit.String(w.BinWriter, "update") // 8 bytes - emit.Int(w.BinWriter, 2) // 1 byte - emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte - emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`) - emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`) - emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes - emit.Opcodes(w.BinWriter, opcode.CALL, 3, opcode.RET) - putValOff := w.Len() - emit.String(w.BinWriter, "initial") - emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) - emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) - emit.Opcodes(w.BinWriter, opcode.RET) - getValOff := w.Len() - emit.String(w.BinWriter, "initial") - emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) - emit.Syscall(w.BinWriter, interopnames.SystemStorageGet) - emit.Opcodes(w.BinWriter, opcode.RET) - delValOff := w.Len() - emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) - emit.Syscall(w.BinWriter, interopnames.SystemStorageDelete) - emit.Opcodes(w.BinWriter, opcode.RET) - onNEP17PaymentOff := w.Len() - emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash) - emit.Int(w.BinWriter, 4) - emit.Opcodes(w.BinWriter, opcode.PACK) - emit.String(w.BinWriter, "LastPayment") - emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) - emit.Opcodes(w.BinWriter, opcode.RET) - onNEP11PaymentOff := w.Len() - emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash) - emit.Int(w.BinWriter, 5) - emit.Opcodes(w.BinWriter, opcode.PACK) - emit.String(w.BinWriter, "LostPayment") - emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) - emit.Opcodes(w.BinWriter, opcode.RET) - update3Off := w.Len() - emit.Int(w.BinWriter, 3) - emit.Opcodes(w.BinWriter, opcode.JMP, 2+1) - updateOff := w.Len() - emit.Int(w.BinWriter, 2) - emit.Opcodes(w.BinWriter, opcode.PACK) - emit.AppCallNoArgs(w.BinWriter, mgmtHash, "update", callflag.All) - emit.Opcodes(w.BinWriter, opcode.DROP) - emit.Opcodes(w.BinWriter, opcode.RET) - destroyOff := w.Len() - emit.AppCall(w.BinWriter, mgmtHash, "destroy", callflag.All) - emit.Opcodes(w.BinWriter, opcode.DROP) - emit.Opcodes(w.BinWriter, opcode.RET) - invalidStackOff := w.Len() - emit.Opcodes(w.BinWriter, opcode.NEWARRAY0, opcode.DUP, opcode.DUP, opcode.APPEND) // recursive array - emit.Syscall(w.BinWriter, interopnames.SystemStorageGetReadOnlyContext) // interop item - emit.Opcodes(w.BinWriter, opcode.RET) - callT0Off := w.Len() - emit.Opcodes(w.BinWriter, opcode.CALLT, 0, 0, opcode.PUSH1, opcode.ADD, opcode.RET) - callT1Off := w.Len() - emit.Opcodes(w.BinWriter, opcode.CALLT, 1, 0, opcode.RET) - callT2Off := w.Len() - emit.Opcodes(w.BinWriter, opcode.CALLT, 0, 0, opcode.RET) - burnGasOff := w.Len() - emit.Syscall(w.BinWriter, interopnames.SystemRuntimeBurnGas) - emit.Opcodes(w.BinWriter, opcode.RET) - invocCounterOff := w.Len() - emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetInvocationCounter) - emit.Opcodes(w.BinWriter, opcode.RET) - - script := w.Bytes() - m := manifest.NewManifest("TestMain") - m.ABI.Methods = []manifest.Method{ - { - Name: "add", - Offset: addOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("addend1", smartcontract.IntegerType), - manifest.NewParameter("addend2", smartcontract.IntegerType), - }, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "add", - Offset: addMultiOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("addend1", smartcontract.IntegerType), - manifest.NewParameter("addend2", smartcontract.IntegerType), - manifest.NewParameter("addend3", smartcontract.IntegerType), - }, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "ret7", - Offset: ret7Off, - Parameters: []manifest.Parameter{}, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "drop", - Offset: dropOff, - ReturnType: smartcontract.VoidType, - }, - { - Name: manifest.MethodInit, - Offset: initOff, - ReturnType: smartcontract.VoidType, - }, - { - Name: "add3", - Offset: add3Off, - Parameters: []manifest.Parameter{ - manifest.NewParameter("addend", smartcontract.IntegerType), - }, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "invalidReturn", - Offset: invalidRetOff, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "justReturn", - Offset: justRetOff, - ReturnType: smartcontract.VoidType, - }, - { - Name: manifest.MethodVerify, - Offset: verifyOff, - ReturnType: smartcontract.BoolType, - }, - { - Name: manifest.MethodDeploy, - Offset: deployOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("data", smartcontract.AnyType), - manifest.NewParameter("isUpdate", smartcontract.BoolType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "getValue", - Offset: getValOff, - ReturnType: smartcontract.StringType, - }, - { - Name: "putValue", - Offset: putValOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("value", smartcontract.StringType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "delValue", - Offset: delValOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("key", smartcontract.StringType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: manifest.MethodOnNEP11Payment, - Offset: onNEP11PaymentOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("from", smartcontract.Hash160Type), - manifest.NewParameter("amount", smartcontract.IntegerType), - manifest.NewParameter("tokenid", smartcontract.ByteArrayType), - manifest.NewParameter("data", smartcontract.AnyType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: manifest.MethodOnNEP17Payment, - Offset: onNEP17PaymentOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("from", smartcontract.Hash160Type), - manifest.NewParameter("amount", smartcontract.IntegerType), - manifest.NewParameter("data", smartcontract.AnyType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "update", - Offset: updateOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("nef", smartcontract.ByteArrayType), - manifest.NewParameter("manifest", smartcontract.ByteArrayType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "update", - Offset: update3Off, - Parameters: []manifest.Parameter{ - manifest.NewParameter("nef", smartcontract.ByteArrayType), - manifest.NewParameter("manifest", smartcontract.ByteArrayType), - manifest.NewParameter("data", smartcontract.AnyType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "destroy", - Offset: destroyOff, - ReturnType: smartcontract.VoidType, - }, - { - Name: "invalidStack", - Offset: invalidStackOff, - ReturnType: smartcontract.VoidType, - }, - { - Name: "callT0", - Offset: callT0Off, - Parameters: []manifest.Parameter{ - manifest.NewParameter("address", smartcontract.Hash160Type), - }, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "callT1", - Offset: callT1Off, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "callT2", - Offset: callT2Off, - ReturnType: smartcontract.IntegerType, - }, - { - Name: "burnGas", - Offset: burnGasOff, - Parameters: []manifest.Parameter{ - manifest.NewParameter("amount", smartcontract.IntegerType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "invocCounter", - Offset: invocCounterOff, - ReturnType: smartcontract.IntegerType, - }, - } - m.Permissions = make([]manifest.Permission, 2) - m.Permissions[0].Contract.Type = manifest.PermissionHash - m.Permissions[0].Contract.Value = bc.contracts.NEO.Hash - m.Permissions[0].Methods.Add("balanceOf") - - m.Permissions[1].Contract.Type = manifest.PermissionHash - m.Permissions[1].Contract.Value = util.Uint160{} - m.Permissions[1].Methods.Add("method") - - // Generate NEF file. - ne, err := nef.NewFile(script) - if err != nil { - panic(err) - } - ne.Tokens = []nef.MethodToken{ - { - Hash: neoHash, - Method: "balanceOf", - ParamCount: 1, - HasReturn: true, - CallFlag: callflag.ReadStates, - }, - { - Hash: util.Uint160{}, - Method: "method", - HasReturn: true, - CallFlag: callflag.ReadStates, - }, - } - ne.Checksum = ne.CalculateChecksum() - - // Write first NEF file. - bytes, err := ne.Bytes() - require.NoError(t, err) - if saveState { - err = os.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 = os.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") - perm := manifest.NewPermission(manifest.PermissionHash, h) - perm.Methods.Add("add") - perm.Methods.Add("drop") - perm.Methods.Add("add3") - perm.Methods.Add("invalidReturn") - perm.Methods.Add("justReturn") - perm.Methods.Add("getValue") - m.Permissions = append(m.Permissions, *perm) - ne, err = nef.NewFile(currScript) - if err != nil { - panic(err) - } - - // Write second NEF file. - bytes, err = ne.Bytes() - require.NoError(t, err) - if saveState { - err = os.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 = os.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 := os.ReadFile(helper1ContractNEFPath) - require.NoError(t, err, fmt.Errorf("nef1: %w", errNotFound)) - ne, err := nef.FileFromBytes(neBytes) - require.NoError(t, err) - - mBytes, err := os.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 = os.ReadFile(helper2ContractNEFPath) - require.NoError(t, err, fmt.Errorf("nef2: %w", errNotFound)) - ne, err = nef.FileFromBytes(neBytes) - require.NoError(t, err) - - mBytes, err = os.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{}) { ic.SpawnVM() ic.VM.LoadScriptWithFlags(script, callflag.AllowCall) @@ -1108,7 +679,7 @@ func loadScriptWithHashAndFlags(ic *interop.Context, script []byte, hash util.Ui func TestContractCall(t *testing.T) { _, ic, bc := createVM(t) - cs, currCs := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, currCs := contracts.GetTestContractState(t, pathToInternalContracts, 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)) @@ -1500,7 +1071,7 @@ func TestRuntimeCheckWitness(t *testing.T) { func TestLoadToken(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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) { @@ -1543,7 +1114,7 @@ func TestRuntimeGetNetwork(t *testing.T) { func TestRuntimeBurnGas(t *testing.T) { bc := newTestChain(t) - cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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 index eb4fa8872..c34b1c8d8 100644 --- a/pkg/core/native/native_test/management_test.go +++ b/pkg/core/native/native_test/management_test.go @@ -3,17 +3,14 @@ package native_test import ( "bytes" "encoding/json" - "errors" "fmt" - "os" - "path/filepath" "testing" - "github.com/nspcc-dev/neo-go/pkg/core/storage" - + "github.com/nspcc-dev/neo-go/internal/contracts" "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/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" @@ -23,20 +20,12 @@ import ( "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) } @@ -45,62 +34,11 @@ 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 := os.ReadFile(helper1ContractNEFPath) - require.NoError(t, err, fmt.Errorf("nef1: %w", errNotFound)) - ne, err := nef.FileFromBytes(neBytes) - require.NoError(t, err) - - mBytes, err := os.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 = os.ReadFile(helper2ContractNEFPath) - require.NoError(t, err, fmt.Errorf("nef2: %w", errNotFound)) - ne, err = nef.FileFromBytes(neBytes) - require.NoError(t, err) - - mBytes, err = os.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()) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.Committee.ScriptHash()) manifestBytes, err := json.Marshal(cs1.Manifest) require.NoError(t, err) nefBytes, err := cs1.NEF.Bytes() @@ -301,7 +239,7 @@ func TestManagement_StartFromHeight(t *testing.T) { c := e.CommitteeInvoker(e.NativeHash(t, nativenames.Management)) managementInvoker := c.WithSigners(c.Committee) - cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash) manifestBytes, err := json.Marshal(cs1.Manifest) require.NoError(t, err) nefBytes, err := cs1.NEF.Bytes() @@ -329,7 +267,7 @@ func TestManagement_DeployManifestOverflow(t *testing.T) { c := newManagementClient(t) managementInvoker := c.WithSigners(c.Committee) - cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash) manif1, err := json.Marshal(cs1.Manifest) require.NoError(t, err) nef1, err := nef.NewFile(cs1.NEF.Script) @@ -359,7 +297,7 @@ func TestManagement_ContractDeployAndUpdateWithParameter(t *testing.T) { c := newManagementClient(t) managementInvoker := c.WithSigners(c.Committee) - cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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) @@ -400,7 +338,7 @@ func TestManagement_ContractUpdate(t *testing.T) { c := newManagementClient(t) managementInvoker := c.WithSigners(c.Committee) - cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash) // Allow calling management contract. cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} manifestBytes, err := json.Marshal(cs1.Manifest) @@ -535,7 +473,7 @@ func TestManagement_GetContract(t *testing.T) { c := newManagementClient(t) managementInvoker := c.WithSigners(c.Committee) - cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash) manifestBytes, err := json.Marshal(cs1.Manifest) require.NoError(t, err) nefBytes, err := cs1.NEF.Bytes() @@ -560,7 +498,7 @@ func TestManagement_ContractDestroy(t *testing.T) { c := newManagementClient(t) managementInvoker := c.WithSigners(c.Committee) - cs1, _ := getTestContractState(t, 1, 2, c.CommitteeHash) + cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash) // Allow calling management contract. cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)} manifestBytes, err := json.Marshal(cs1.Manifest) diff --git a/pkg/core/native/native_test/neo_test.go b/pkg/core/native/native_test/neo_test.go index 6da70d52e..d31dd4bab 100644 --- a/pkg/core/native/native_test/neo_test.go +++ b/pkg/core/native/native_test/neo_test.go @@ -7,6 +7,7 @@ import ( "sort" "testing" + "github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" @@ -276,7 +277,7 @@ func TestNEO_TransferOnPayment(t *testing.T) { e := neoValidatorsInvoker.Executor managementValidatorsInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Management)) - cs, _ := getTestContractState(t, 1, 2, e.CommitteeHash) + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, e.CommitteeHash) cs.Hash = state.CreateContractHash(e.Validator.ScriptHash(), cs.NEF.Checksum, cs.Manifest.Name) // set proper hash manifB, err := json.Marshal(cs.Manifest) require.NoError(t, err) diff --git a/pkg/core/native/native_test/oracle_test.go b/pkg/core/native/native_test/oracle_test.go index 8b7ae6a4a..77247f80b 100644 --- a/pkg/core/native/native_test/oracle_test.go +++ b/pkg/core/native/native_test/oracle_test.go @@ -2,32 +2,28 @@ package native_test import ( "encoding/json" - "errors" - "fmt" "math" "math/big" - "os" "path/filepath" "strings" "testing" + "github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" - "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/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/stackitem" "github.com/stretchr/testify/require" ) +var pathToInternalContracts = filepath.Join("..", "..", "..", "..", "internal", "contracts") + func newOracleClient(t *testing.T) *neotest.ContractInvoker { return newNativeClient(t, nativenames.Oracle) } @@ -36,36 +32,6 @@ func TestGetSetPrice(t *testing.T) { testGetSet(t, newOracleClient(t), "Price", native.DefaultOracleRequestPrice, 1, math.MaxInt64) } -// getOracleContractState reads pre-compiled oracle contract generated by -// TestGenerateOracleContract and returns its state. -func getOracleContractState(t *testing.T, sender util.Uint160, id int32) *state.Contract { - var ( - oracleContractNEFPath = filepath.Join("..", "..", "test_data", "oracle_contract", "oracle.nef") - oracleContractManifestPath = filepath.Join("..", "..", "test_data", "oracle_contract", "oracle.manifest.json") - ) - errNotFound := errors.New("auto-generated oracle contract is not found, use TestGenerateOracleContract to regenerate") - - neBytes, err := os.ReadFile(oracleContractNEFPath) - require.NoError(t, err, fmt.Errorf("nef: %w", errNotFound)) - ne, err := nef.FileFromBytes(neBytes) - require.NoError(t, err) - - mBytes, err := os.ReadFile(oracleContractManifestPath) - require.NoError(t, err, fmt.Errorf("manifest: %w", errNotFound)) - m := &manifest.Manifest{} - err = json.Unmarshal(mBytes, m) - require.NoError(t, err) - - return &state.Contract{ - ContractBase: state.ContractBase{ - NEF: ne, - Hash: state.CreateContractHash(sender, ne.Checksum, m.Name), - Manifest: *m, - ID: id, - }, - } -} - func putOracleRequest(t *testing.T, oracleInvoker *neotest.ContractInvoker, url string, filter *string, cb string, userData []byte, gas int64, errStr ...string) { var filtItem interface{} @@ -86,7 +52,7 @@ func TestOracle_Request(t *testing.T) { designationCommitteeInvoker := e.CommitteeInvoker(e.NativeHash(t, nativenames.Designation)) gasCommitteeInvoker := e.CommitteeInvoker(e.NativeHash(t, nativenames.Gas)) - cs := getOracleContractState(t, e.Validator.ScriptHash(), 1) + cs := contracts.GetOracleContractState(t, pathToInternalContracts, e.Validator.ScriptHash(), 1) nBytes, err := cs.NEF.Bytes() require.NoError(t, err) mBytes, err := json.Marshal(cs.Manifest) diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index 563f40b9b..6d7241f19 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/contracts" "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" @@ -302,7 +303,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { } } - cs, _ := getTestContractState(t, 4, 5, random.Uint160()) // sender and IDs are not important for the test + cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 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/oracle_test.go b/pkg/core/oracle_test.go index b33bf78dd..4f5b898ac 100644 --- a/pkg/core/oracle_test.go +++ b/pkg/core/oracle_test.go @@ -2,12 +2,10 @@ package core import ( "bytes" - "encoding/json" "errors" "fmt" gio "io" "net/http" - "os" "path" "path/filepath" "strings" @@ -15,22 +13,16 @@ import ( "testing" "time" + "github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config/netmode" - "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "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/services/oracle" - "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/wallet" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -38,132 +30,10 @@ import ( ) var ( - oracleModulePath = filepath.Join("..", "services", "oracle") - oracleContractNEFPath = filepath.Join("test_data", "oracle_contract", "oracle.nef") - oracleContractManifestPath = filepath.Join("test_data", "oracle_contract", "oracle.manifest.json") + oracleModulePath = filepath.Join("..", "services", "oracle") + pathToInternalContracts = filepath.Join("..", "..", "internal", "contracts") ) -// TestGenerateOracleContract generates helper contract that is able to call -// native Oracle contract and has callback method. It uses test chain to define -// Oracle and StdLib native hashes and saves generated NEF and manifest to ... folder. -// Set `saveState` flag to true and run the test to rewrite NEF and manifest files. -func TestGenerateOracleContract(t *testing.T) { - const saveState = false - - bc := newTestChain(t) - oracleHash := bc.contracts.Oracle.Hash - stdHash := bc.contracts.Std.Hash - - w := io.NewBufBinWriter() - emit.Int(w.BinWriter, 5) - emit.Opcodes(w.BinWriter, opcode.PACK) - emit.Int(w.BinWriter, int64(callflag.All)) - emit.String(w.BinWriter, "request") - emit.Bytes(w.BinWriter, oracleHash.BytesBE()) - emit.Syscall(w.BinWriter, interopnames.SystemContractCall) - emit.Opcodes(w.BinWriter, opcode.DROP) - emit.Opcodes(w.BinWriter, opcode.RET) - - // `handle` method aborts if len(userData) == 2 and does NOT perform witness checks - // for the sake of contract code simplicity (the contract is used in multiple testchains). - offset := w.Len() - - emit.Opcodes(w.BinWriter, opcode.OVER) - emit.Opcodes(w.BinWriter, opcode.SIZE) - emit.Int(w.BinWriter, 2) - emit.Instruction(w.BinWriter, opcode.JMPNE, []byte{3}) - emit.Opcodes(w.BinWriter, opcode.ABORT) - emit.Int(w.BinWriter, 4) // url, userData, code, result - emit.Opcodes(w.BinWriter, opcode.PACK) - emit.Int(w.BinWriter, 1) // 1 byte (args count for `serialize`) - emit.Opcodes(w.BinWriter, opcode.PACK) // 1 byte (pack args into array for `serialize`) - emit.AppCallNoArgs(w.BinWriter, stdHash, "serialize", callflag.All) // 39 bytes - emit.String(w.BinWriter, "lastOracleResponse") - emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) - emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) - emit.Opcodes(w.BinWriter, opcode.RET) - - m := manifest.NewManifest("TestOracle") - m.ABI.Methods = []manifest.Method{ - { - Name: "requestURL", - Offset: 0, - Parameters: []manifest.Parameter{ - manifest.NewParameter("url", smartcontract.StringType), - manifest.NewParameter("filter", smartcontract.StringType), - manifest.NewParameter("callback", smartcontract.StringType), - manifest.NewParameter("userData", smartcontract.AnyType), - manifest.NewParameter("gasForResponse", smartcontract.IntegerType), - }, - ReturnType: smartcontract.VoidType, - }, - { - Name: "handle", - Offset: offset, - Parameters: []manifest.Parameter{ - manifest.NewParameter("url", smartcontract.StringType), - manifest.NewParameter("userData", smartcontract.AnyType), - manifest.NewParameter("code", smartcontract.IntegerType), - manifest.NewParameter("result", smartcontract.ByteArrayType), - }, - ReturnType: smartcontract.VoidType, - }, - } - - perm := manifest.NewPermission(manifest.PermissionHash, oracleHash) - perm.Methods.Add("request") - m.Permissions = append(m.Permissions, *perm) - - // Generate NEF file. - script := w.Bytes() - ne, err := nef.NewFile(script) - require.NoError(t, err) - - // Write NEF file. - bytes, err := ne.Bytes() - require.NoError(t, err) - if saveState { - err = os.WriteFile(oracleContractNEFPath, bytes, os.ModePerm) - require.NoError(t, err) - } - - // Write manifest file. - mData, err := json.Marshal(m) - require.NoError(t, err) - if saveState { - err = os.WriteFile(oracleContractManifestPath, mData, os.ModePerm) - require.NoError(t, err) - } - - require.False(t, saveState) -} - -// getOracleContractState reads pre-compiled oracle contract generated by -// TestGenerateOracleContract and returns its state. -func getOracleContractState(t *testing.T, sender util.Uint160, id int32) *state.Contract { - errNotFound := errors.New("auto-generated oracle contract is not found, use TestGenerateOracleContract to regenerate") - - neBytes, err := os.ReadFile(oracleContractNEFPath) - require.NoError(t, err, fmt.Errorf("nef: %w", errNotFound)) - ne, err := nef.FileFromBytes(neBytes) - require.NoError(t, err) - - mBytes, err := os.ReadFile(oracleContractManifestPath) - require.NoError(t, err, fmt.Errorf("manifest: %w", errNotFound)) - m := &manifest.Manifest{} - err = json.Unmarshal(mBytes, m) - require.NoError(t, err) - - return &state.Contract{ - ContractBase: state.ContractBase{ - NEF: ne, - Hash: state.CreateContractHash(sender, ne.Checksum, m.Name), - Manifest: *m, - ID: id, - }, - } -} - func putOracleRequest(t *testing.T, h util.Uint160, bc *Blockchain, url string, filter *string, cb string, userData []byte, gas int64) util.Uint256 { var filtItem interface{} @@ -274,7 +144,7 @@ func TestOracle(t *testing.T) { orc1.UpdateNativeContract(orcNative.NEF.Script, orcNative.GetOracleResponseScript(), orcNative.Hash, md.MD.Offset) orc2.UpdateNativeContract(orcNative.NEF.Script, orcNative.GetOracleResponseScript(), orcNative.Hash, md.MD.Offset) - cs := getOracleContractState(t, util.Uint160{}, 42) + cs := contracts.GetOracleContractState(t, pathToInternalContracts, util.Uint160{}, 42) require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) putOracleRequest(t, cs.Hash, bc, "https://get.1234", nil, "handle", []byte{}, 10_000_000) @@ -442,7 +312,7 @@ func TestOracleFull(t *testing.T) { orc.OnTransaction = func(tx *transaction.Transaction) error { return mp.Add(tx, bc) } bc.SetOracle(orc) - cs := getOracleContractState(t, util.Uint160{}, 42) + cs := contracts.GetOracleContractState(t, pathToInternalContracts, util.Uint160{}, 42) require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) go bc.Run() @@ -467,7 +337,7 @@ func TestNotYetRunningOracle(t *testing.T) { orc.OnTransaction = func(tx *transaction.Transaction) error { return mp.Add(tx, bc) } bc.SetOracle(orc) - cs := getOracleContractState(t, util.Uint160{}, 42) + cs := contracts.GetOracleContractState(t, pathToInternalContracts, util.Uint160{}, 42) require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs)) go bc.Run() diff --git a/pkg/core/test_data/management_helper/README.md b/pkg/core/test_data/management_helper/README.md deleted file mode 100644 index 853e322f6..000000000 --- a/pkg/core/test_data/management_helper/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## 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/oracle_contract/README.md b/pkg/core/test_data/oracle_contract/README.md deleted file mode 100644 index 83fad42a7..000000000 --- a/pkg/core/test_data/oracle_contract/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## Oracle helper contract - -Oracle helper contract NEF and manifest files are generated automatically by -`TestGenerateOracleContract` and are used in tests. Do not modify these files manually. -To regenerate these files: - -1. Open `TestGenerateOracleContract` and set `saveState` flag to `true`. -2. Run `TestGenerateOracleContract`. -3. Set `saveState` back to `false`. \ No newline at end of file