forked from TrueCloudLab/neoneo-go
core: refactor helper test contracts generation
* Move generator to a separate package. * Move loader to a separate package and get rid of the code duplications.
This commit is contained in:
parent
889a7ec378
commit
13252bb941
19 changed files with 648 additions and 702 deletions
103
internal/contracts/contracts.go
Normal file
103
internal/contracts/contracts.go
Normal file
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
495
internal/contracts/contracts_test.go
Normal file
495
internal/contracts/contracts_test.go
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
9
internal/contracts/management_helper/README.md
Normal file
9
internal/contracts/management_helper/README.md
Normal file
|
@ -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`.
|
0
pkg/core/test_data/management_helper/management_helper1.nef → internal/contracts/management_helper/management_helper1.nef
Executable file → Normal file
0
pkg/core/test_data/management_helper/management_helper1.nef → internal/contracts/management_helper/management_helper1.nef
Executable file → Normal file
0
pkg/core/test_data/management_helper/management_helper2.nef → internal/contracts/management_helper/management_helper2.nef
Executable file → Normal file
0
pkg/core/test_data/management_helper/management_helper2.nef → internal/contracts/management_helper/management_helper2.nef
Executable file → Normal file
9
internal/contracts/oracle_contract/README.md
Normal file
9
internal/contracts/oracle_contract/README.md
Normal file
|
@ -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`.
|
0
pkg/core/test_data/oracle_contract/oracle.manifest.json → internal/contracts/oracle_contract/oracle.manifest.json
Executable file → Normal file
0
pkg/core/test_data/oracle_contract/oracle.manifest.json → internal/contracts/oracle_contract/oracle.manifest.json
Executable file → Normal file
0
pkg/core/test_data/oracle_contract/oracle.nef → internal/contracts/oracle_contract/oracle.nef
Executable file → Normal file
0
pkg/core/test_data/oracle_contract/oracle.nef → internal/contracts/oracle_contract/oracle.nef
Executable file → Normal file
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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`.
|
|
@ -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`.
|
Loading…
Reference in a new issue