diff --git a/pkg/core/interop/contract/account_test.go b/pkg/core/interop/contract/account_test.go new file mode 100644 index 000000000..a4ad6a60a --- /dev/null +++ b/pkg/core/interop/contract/account_test.go @@ -0,0 +1,115 @@ +package contract_test + +import ( + "math" + "math/big" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" + "github.com/nspcc-dev/neo-go/pkg/crypto/hash" + "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/util" + "github.com/nspcc-dev/neo-go/pkg/vm/emit" + "github.com/stretchr/testify/require" +) + +func TestCreateStandardAccount(t *testing.T) { + bc, acc := chain.NewSingle(t) + e := neotest.NewExecutor(t, bc, acc, acc) + w := io.NewBufBinWriter() + + t.Run("Good", func(t *testing.T) { + priv, err := keys.NewPrivateKey() + require.NoError(t, err) + pub := priv.PublicKey() + + emit.Bytes(w.BinWriter, pub.Bytes()) + emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount) + require.NoError(t, w.Err) + script := w.Bytes() + + tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Validator}, bc.BlockHeight()+1) + e.AddNewBlock(t, tx) + e.CheckHalt(t, tx.Hash()) + + res := e.GetTxExecResult(t, tx.Hash()) + value := res.Stack[0].Value().([]byte) + u, err := util.Uint160DecodeBytesBE(value) + require.NoError(t, err) + require.Equal(t, pub.GetScriptHash(), u) + }) + t.Run("InvalidKey", func(t *testing.T) { + w.Reset() + emit.Bytes(w.BinWriter, []byte{1, 2, 3}) + emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount) + require.NoError(t, w.Err) + script := w.Bytes() + + tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Validator}, bc.BlockHeight()+1) + e.AddNewBlock(t, tx) + e.CheckFault(t, tx.Hash(), "invalid prefix 1") + }) +} + +func TestCreateMultisigAccount(t *testing.T) { + bc, acc := chain.NewSingle(t) + e := neotest.NewExecutor(t, bc, acc, acc) + w := io.NewBufBinWriter() + + createScript := func(t *testing.T, pubs []interface{}, m int) []byte { + w.Reset() + emit.Array(w.BinWriter, pubs...) + emit.Int(w.BinWriter, int64(m)) + emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount) + require.NoError(t, w.Err) + return w.Bytes() + } + t.Run("Good", func(t *testing.T) { + m, n := 3, 5 + pubs := make(keys.PublicKeys, n) + arr := make([]interface{}, n) + for i := range pubs { + pk, err := keys.NewPrivateKey() + require.NoError(t, err) + pubs[i] = pk.PublicKey() + arr[i] = pubs[i].Bytes() + } + script := createScript(t, arr, m) + + txH := e.InvokeScript(t, script, []neotest.Signer{acc}) + e.CheckHalt(t, txH) + res := e.GetTxExecResult(t, txH) + value := res.Stack[0].Value().([]byte) + u, err := util.Uint160DecodeBytesBE(value) + require.NoError(t, err) + expected, err := smartcontract.CreateMultiSigRedeemScript(m, pubs) + require.NoError(t, err) + require.Equal(t, hash.Hash160(expected), u) + }) + t.Run("InvalidKey", func(t *testing.T) { + script := createScript(t, []interface{}{[]byte{1, 2, 3}}, 1) + e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "invalid prefix 1") + }) + t.Run("Invalid m", func(t *testing.T) { + pk, err := keys.NewPrivateKey() + require.NoError(t, err) + script := createScript(t, []interface{}{pk.PublicKey().Bytes()}, 2) + e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "length of the signatures (2) is higher then the number of public keys") + }) + t.Run("m overflows int32", func(t *testing.T) { + pk, err := keys.NewPrivateKey() + require.NoError(t, err) + m := big.NewInt(math.MaxInt32) + m.Add(m, big.NewInt(1)) + w.Reset() + emit.Array(w.BinWriter, pk.Bytes()) + emit.BigInt(w.BinWriter, m) + emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount) + require.NoError(t, w.Err) + e.InvokeScriptCheckFAULT(t, w.Bytes(), []neotest.Signer{acc}, "m must be positive and fit int32") + }) +} diff --git a/pkg/core/interop_system_neotest_test.go b/pkg/core/interop_system_neotest_test.go index 99fcee560..9047aa1d2 100644 --- a/pkg/core/interop_system_neotest_test.go +++ b/pkg/core/interop_system_neotest_test.go @@ -15,13 +15,11 @@ import ( "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/transaction" - "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "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/manifest" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util/slice" @@ -55,103 +53,6 @@ func TestSystemRuntimeGetRandom_DifferentTransactions(t *testing.T) { require.NotEqual(t, r1, r2) } -func TestSystemContractCreateStandardAccount(t *testing.T) { - bc, acc := chain.NewSingle(t) - e := neotest.NewExecutor(t, bc, acc, acc) - w := io.NewBufBinWriter() - - t.Run("Good", func(t *testing.T) { - priv, err := keys.NewPrivateKey() - require.NoError(t, err) - pub := priv.PublicKey() - - emit.Bytes(w.BinWriter, pub.Bytes()) - emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount) - require.NoError(t, w.Err) - script := w.Bytes() - - tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Validator}, bc.BlockHeight()+1) - e.AddNewBlock(t, tx) - e.CheckHalt(t, tx.Hash()) - - res := e.GetTxExecResult(t, tx.Hash()) - value := res.Stack[0].Value().([]byte) - u, err := util.Uint160DecodeBytesBE(value) - require.NoError(t, err) - require.Equal(t, pub.GetScriptHash(), u) - }) - t.Run("InvalidKey", func(t *testing.T) { - w.Reset() - emit.Bytes(w.BinWriter, []byte{1, 2, 3}) - emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount) - require.NoError(t, w.Err) - script := w.Bytes() - - tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Validator}, bc.BlockHeight()+1) - e.AddNewBlock(t, tx) - e.CheckFault(t, tx.Hash(), "invalid prefix 1") - }) -} - -func TestSystemContractCreateMultisigAccount(t *testing.T) { - bc, acc := chain.NewSingle(t) - e := neotest.NewExecutor(t, bc, acc, acc) - w := io.NewBufBinWriter() - - createScript := func(t *testing.T, pubs []interface{}, m int) []byte { - w.Reset() - emit.Array(w.BinWriter, pubs...) - emit.Int(w.BinWriter, int64(m)) - emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount) - require.NoError(t, w.Err) - return w.Bytes() - } - t.Run("Good", func(t *testing.T) { - m, n := 3, 5 - pubs := make(keys.PublicKeys, n) - arr := make([]interface{}, n) - for i := range pubs { - pk, err := keys.NewPrivateKey() - require.NoError(t, err) - pubs[i] = pk.PublicKey() - arr[i] = pubs[i].Bytes() - } - script := createScript(t, arr, m) - - txH := e.InvokeScript(t, script, []neotest.Signer{acc}) - e.CheckHalt(t, txH) - res := e.GetTxExecResult(t, txH) - value := res.Stack[0].Value().([]byte) - u, err := util.Uint160DecodeBytesBE(value) - require.NoError(t, err) - expected, err := smartcontract.CreateMultiSigRedeemScript(m, pubs) - require.NoError(t, err) - require.Equal(t, hash.Hash160(expected), u) - }) - t.Run("InvalidKey", func(t *testing.T) { - script := createScript(t, []interface{}{[]byte{1, 2, 3}}, 1) - e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "invalid prefix 1") - }) - t.Run("Invalid m", func(t *testing.T) { - pk, err := keys.NewPrivateKey() - require.NoError(t, err) - script := createScript(t, []interface{}{pk.PublicKey().Bytes()}, 2) - e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "length of the signatures (2) is higher then the number of public keys") - }) - t.Run("m overflows int32", func(t *testing.T) { - pk, err := keys.NewPrivateKey() - require.NoError(t, err) - m := big.NewInt(math.MaxInt32) - m.Add(m, big.NewInt(1)) - w.Reset() - emit.Array(w.BinWriter, pk.Bytes()) - emit.BigInt(w.BinWriter, m) - emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount) - require.NoError(t, w.Err) - e.InvokeScriptCheckFAULT(t, w.Bytes(), []neotest.Signer{acc}, "m must be positive and fit int32") - }) -} - func TestSystemRuntimeGasLeft(t *testing.T) { const runtimeGasLeftPrice = 1 << 4