mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-05-05 13:06:20 +00:00
parent
c5e39dfabf
commit
1cf1fe5d74
32 changed files with 320 additions and 304 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/dbft/crypto"
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
"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"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/callback"
|
||||
|
@ -21,6 +22,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
|
@ -204,7 +206,7 @@ func TestContractIsStandard(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
pub := priv.PublicKey()
|
||||
err = ic.DAO.PutContractState(&state.Contract{ID: 42, Script: pub.GetVerificationScript()})
|
||||
err = ic.DAO.PutContractState(&state.Contract{ID: 42, Hash: pub.GetScriptHash(), Script: pub.GetVerificationScript()})
|
||||
require.NoError(t, err)
|
||||
|
||||
v.Estack().PushVal(pub.GetScriptHash().BytesBE())
|
||||
|
@ -213,7 +215,7 @@ func TestContractIsStandard(t *testing.T) {
|
|||
})
|
||||
t.Run("contract stored, false", func(t *testing.T) {
|
||||
script := []byte{byte(opcode.PUSHT)}
|
||||
require.NoError(t, ic.DAO.PutContractState(&state.Contract{ID: 24, Script: script}))
|
||||
require.NoError(t, ic.DAO.PutContractState(&state.Contract{ID: 24, Hash: hash.Hash160(script), Script: script}))
|
||||
|
||||
v.Estack().PushVal(crypto.Hash160(script).BytesBE())
|
||||
require.NoError(t, contractIsStandard(ic))
|
||||
|
@ -319,7 +321,7 @@ func TestBlockchainGetContractState(t *testing.T) {
|
|||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
|
||||
t.Run("positive", func(t *testing.T) {
|
||||
v.Estack().PushVal(cs.ScriptHash().BytesBE())
|
||||
v.Estack().PushVal(cs.Hash.BytesBE())
|
||||
require.NoError(t, bcGetContract(ic))
|
||||
|
||||
actual := v.Estack().Pop().Item()
|
||||
|
@ -502,6 +504,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
|
|||
}
|
||||
cs := &state.Contract{
|
||||
Script: script,
|
||||
Hash: h,
|
||||
Manifest: *m,
|
||||
ID: 42,
|
||||
}
|
||||
|
@ -519,6 +522,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
|
|||
|
||||
return cs, &state.Contract{
|
||||
Script: currScript,
|
||||
Hash: hash.Hash160(currScript),
|
||||
Manifest: *m,
|
||||
ID: 123,
|
||||
}
|
||||
|
@ -654,13 +658,31 @@ func TestContractCreate(t *testing.T) {
|
|||
v.GasLimit = -1
|
||||
defer bc.Close()
|
||||
|
||||
// nef.NewFile() cares about version a lot.
|
||||
config.Version = "0.90.0-test"
|
||||
putArgsOnStack := func() {
|
||||
manifest, err := json.Marshal(cs.Manifest)
|
||||
require.NoError(t, err)
|
||||
ne, err := nef.NewFile(cs.Script)
|
||||
require.NoError(t, err)
|
||||
neb, err := ne.Bytes()
|
||||
require.NoError(t, err)
|
||||
v.Estack().PushVal(manifest)
|
||||
v.Estack().PushVal(cs.Script)
|
||||
v.Estack().PushVal(neb)
|
||||
}
|
||||
|
||||
t.Run("no tx", func(t *testing.T) {
|
||||
putArgsOnStack()
|
||||
|
||||
require.Error(t, contractCreate(ic))
|
||||
})
|
||||
|
||||
ic.Tx = transaction.New(netmode.UnitTestNet, []byte{1}, 0)
|
||||
var sender = util.Uint160{1, 2, 3}
|
||||
ic.Tx.Signers = append(ic.Tx.Signers, transaction.Signer{Account: sender})
|
||||
cs.ID = 0
|
||||
cs.Hash = state.CreateContractHash(sender, cs.Script)
|
||||
|
||||
t.Run("positive", func(t *testing.T) {
|
||||
putArgsOnStack()
|
||||
|
||||
|
@ -670,8 +692,6 @@ func TestContractCreate(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("contract already exists", func(t *testing.T) {
|
||||
cs.Script = cs.Script[:len(cs.Script)-1]
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
putArgsOnStack()
|
||||
|
||||
require.Error(t, contractCreate(ic))
|
||||
|
@ -685,9 +705,12 @@ func compareContractStates(t *testing.T, expected *state.Contract, actual stacki
|
|||
expectedManifest, err := json.Marshal(expected.Manifest)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 2, len(act))
|
||||
require.Equal(t, expected.Script, act[0].Value().([]byte))
|
||||
require.Equal(t, expectedManifest, act[1].Value().([]byte))
|
||||
require.Equal(t, 5, len(act))
|
||||
require.Equal(t, expected.ID, int32(act[0].Value().(*big.Int).Int64()))
|
||||
require.Equal(t, expected.UpdateCounter, uint16(act[1].Value().(*big.Int).Int64()))
|
||||
require.Equal(t, expected.Hash.BytesBE(), act[2].Value().([]byte))
|
||||
require.Equal(t, expected.Script, act[3].Value().([]byte))
|
||||
require.Equal(t, expectedManifest, act[4].Value().([]byte))
|
||||
}
|
||||
|
||||
func TestContractUpdate(t *testing.T) {
|
||||
|
@ -697,12 +720,19 @@ func TestContractUpdate(t *testing.T) {
|
|||
|
||||
putArgsOnStack := func(script, manifest interface{}) {
|
||||
v.Estack().PushVal(manifest)
|
||||
b, ok := script.([]byte)
|
||||
if ok {
|
||||
ne, err := nef.NewFile(b)
|
||||
require.NoError(t, err)
|
||||
script, err = ne.Bytes()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
v.Estack().PushVal(script)
|
||||
}
|
||||
|
||||
t.Run("no args", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack(stackitem.Null{}, stackitem.Null{})
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
@ -710,19 +740,20 @@ func TestContractUpdate(t *testing.T) {
|
|||
t.Run("no contract", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, util.Uint160{8, 9, 7}, smartcontract.All)
|
||||
putArgsOnStack([]byte{1}, stackitem.Null{})
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
t.Run("too large script", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack(make([]byte, MaxContractScriptSize+1), stackitem.Null{})
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
t.Run("too large manifest", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack(stackitem.Null{}, make([]byte, manifest.MaxManifestSize+1))
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
@ -730,70 +761,43 @@ func TestContractUpdate(t *testing.T) {
|
|||
t.Run("gas limit exceeded", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.GasLimit = 0
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack([]byte{1}, []byte{2})
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
t.Run("update script, the same script", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.GasLimit = -1
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
putArgsOnStack(cs.Script, stackitem.Null{})
|
||||
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
t.Run("update script, already exists", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
duplicateScript := []byte{byte(opcode.PUSHDATA4)}
|
||||
require.NoError(t, ic.DAO.PutContractState(&state.Contract{
|
||||
ID: 95,
|
||||
Script: duplicateScript,
|
||||
Manifest: manifest.Manifest{
|
||||
ABI: manifest.ABI{},
|
||||
},
|
||||
}))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
putArgsOnStack(duplicateScript, stackitem.Null{})
|
||||
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
v.GasLimit = -1
|
||||
t.Run("update script, positive", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
t.Run("empty manifest", func(t *testing.T) {
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
newScript := []byte{9, 8, 7, 6, 5}
|
||||
putArgsOnStack(newScript, []byte{})
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
newScript := []byte{9, 8, 7, 6, 5}
|
||||
putArgsOnStack(newScript, stackitem.Null{})
|
||||
|
||||
require.NoError(t, contractUpdate(ic))
|
||||
|
||||
// updated contract should have new scripthash
|
||||
actual, err := ic.DAO.GetContractState(hash.Hash160(newScript))
|
||||
// updated contract should have the same scripthash
|
||||
actual, err := ic.DAO.GetContractState(cs.Hash)
|
||||
require.NoError(t, err)
|
||||
expected := &state.Contract{
|
||||
ID: cs.ID,
|
||||
Script: newScript,
|
||||
Manifest: cs.Manifest,
|
||||
ID: cs.ID,
|
||||
UpdateCounter: 1,
|
||||
Hash: cs.Hash,
|
||||
Script: newScript,
|
||||
Manifest: cs.Manifest,
|
||||
}
|
||||
_ = expected.ScriptHash()
|
||||
require.Equal(t, expected, actual)
|
||||
|
||||
// old contract should be deleted
|
||||
_, err = ic.DAO.GetContractState(cs.ScriptHash())
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("update manifest, bad manifest", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack(stackitem.Null{}, []byte{1, 2, 3})
|
||||
|
||||
require.Error(t, contractUpdate(ic))
|
||||
|
@ -808,30 +812,31 @@ func TestContractUpdate(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
t.Run("empty script", func(t *testing.T) {
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack([]byte{}, manifestBytes)
|
||||
require.Error(t, contractUpdate(ic))
|
||||
})
|
||||
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
putArgsOnStack(stackitem.Null{}, manifestBytes)
|
||||
require.NoError(t, contractUpdate(ic))
|
||||
|
||||
// updated contract should have new scripthash
|
||||
actual, err := ic.DAO.GetContractState(cs.ScriptHash())
|
||||
// updated contract should have old scripthash
|
||||
actual, err := ic.DAO.GetContractState(cs.Hash)
|
||||
require.NoError(t, err)
|
||||
expected := &state.Contract{
|
||||
ID: cs.ID,
|
||||
Script: cs.Script,
|
||||
Manifest: *manifest,
|
||||
ID: cs.ID,
|
||||
UpdateCounter: 2,
|
||||
Hash: cs.Hash,
|
||||
Script: cs.Script,
|
||||
Manifest: *manifest,
|
||||
}
|
||||
_ = expected.ScriptHash()
|
||||
require.Equal(t, expected, actual)
|
||||
})
|
||||
|
||||
t.Run("update both script and manifest", func(t *testing.T) {
|
||||
require.NoError(t, ic.DAO.PutContractState(cs))
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
|
||||
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.Hash, smartcontract.All)
|
||||
newScript := []byte{12, 13, 14}
|
||||
newManifest := manifest.Manifest{
|
||||
ABI: manifest.ABI{},
|
||||
|
@ -844,19 +849,16 @@ func TestContractUpdate(t *testing.T) {
|
|||
require.NoError(t, contractUpdate(ic))
|
||||
|
||||
// updated contract should have new script and manifest
|
||||
actual, err := ic.DAO.GetContractState(hash.Hash160(newScript))
|
||||
actual, err := ic.DAO.GetContractState(cs.Hash)
|
||||
require.NoError(t, err)
|
||||
expected := &state.Contract{
|
||||
ID: cs.ID,
|
||||
Script: newScript,
|
||||
Manifest: newManifest,
|
||||
ID: cs.ID,
|
||||
UpdateCounter: 3,
|
||||
Hash: cs.Hash,
|
||||
Script: newScript,
|
||||
Manifest: newManifest,
|
||||
}
|
||||
_ = expected.ScriptHash()
|
||||
require.Equal(t, expected, actual)
|
||||
|
||||
// old contract should be deleted
|
||||
_, err = ic.DAO.GetContractState(cs.ScriptHash())
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -871,28 +873,37 @@ func TestContractCreateDeploy(t *testing.T) {
|
|||
rawManifest, err := json.Marshal(cs.Manifest)
|
||||
require.NoError(t, err)
|
||||
v.Estack().PushVal(rawManifest)
|
||||
v.Estack().PushVal(cs.Script)
|
||||
ne, err := nef.NewFile(cs.Script)
|
||||
require.NoError(t, err)
|
||||
b, err := ne.Bytes()
|
||||
require.NoError(t, err)
|
||||
v.Estack().PushVal(b)
|
||||
}
|
||||
cs, currCs := getTestContractState()
|
||||
|
||||
ic.Tx = transaction.New(netmode.UnitTestNet, []byte{1}, 0)
|
||||
var sender = util.Uint160{1, 2, 3}
|
||||
ic.Tx.Signers = append(ic.Tx.Signers, transaction.Signer{Account: sender})
|
||||
v.LoadScriptWithFlags([]byte{byte(opcode.RET)}, smartcontract.All)
|
||||
putArgs(cs)
|
||||
require.NoError(t, contractCreate(ic))
|
||||
require.NoError(t, ic.VM.Run())
|
||||
|
||||
v.LoadScriptWithFlags(currCs.Script, smartcontract.All)
|
||||
cs.Hash = state.CreateContractHash(sender, cs.Script)
|
||||
v.LoadScriptWithHash(currCs.Script, cs.Hash, smartcontract.All)
|
||||
err := contract.CallExInternal(ic, cs, "getValue", nil, smartcontract.All, vm.EnsureNotEmpty, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, v.Run())
|
||||
require.Equal(t, "create", v.Estack().Pop().String())
|
||||
|
||||
v.LoadScriptWithFlags(cs.Script, smartcontract.All)
|
||||
v.LoadScriptWithHash(cs.Script, cs.Hash, smartcontract.All)
|
||||
md := cs.Manifest.ABI.GetMethod("justReturn")
|
||||
v.Jump(v.Context(), md.Offset)
|
||||
|
||||
t.Run("Update", func(t *testing.T) {
|
||||
newCs := &state.Contract{
|
||||
ID: cs.ID,
|
||||
Hash: cs.Hash,
|
||||
Script: append(cs.Script, byte(opcode.RET)),
|
||||
Manifest: cs.Manifest,
|
||||
}
|
||||
|
@ -900,7 +911,7 @@ func TestContractCreateDeploy(t *testing.T) {
|
|||
require.NoError(t, contractUpdate(ic))
|
||||
require.NoError(t, v.Run())
|
||||
|
||||
v.LoadScriptWithFlags(currCs.Script, smartcontract.All)
|
||||
v.LoadScriptWithHash(currCs.Script, cs.Hash, smartcontract.All)
|
||||
err = contract.CallExInternal(ic, newCs, "getValue", nil, smartcontract.All, vm.EnsureNotEmpty, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, v.Run())
|
||||
|
@ -1219,6 +1230,7 @@ func TestRuntimeCheckWitness(t *testing.T) {
|
|||
contractScriptHash := hash.Hash160(contractScript)
|
||||
contractState := &state.Contract{
|
||||
ID: 15,
|
||||
Hash: contractScriptHash,
|
||||
Script: contractScript,
|
||||
Manifest: manifest.Manifest{
|
||||
Groups: []manifest.Group{{PublicKey: pk.PublicKey()}},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue