3b11f98cd0
This method returns persisted block height and doesn't take into account
persisting block height. Some of the callers of this method relay on
the wrong assumption that BlockHeight() returns persisting block index.
Fix improper usages of this method and adjust tests. Ref.
61a066583e/src/Neo/SmartContract/ApplicationEngine.cs (L634)
.
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
175 lines
5.9 KiB
Go
175 lines
5.9 KiB
Go
package contract_test
|
|
|
|
import (
|
|
"math"
|
|
"math/big"
|
|
"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/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/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/util/slice"
|
|
"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 []any, 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([]any, 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, []any{[]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, []any{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 TestCreateAccount_HFAspidochelone(t *testing.T) {
|
|
const enabledHeight = 3
|
|
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
|
|
c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled
|
|
c.Hardforks = map[string]uint32{
|
|
config.HFAspidochelone.String(): enabledHeight,
|
|
}
|
|
})
|
|
e := neotest.NewExecutor(t, bc, acc, acc)
|
|
|
|
priv, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
pub := priv.PublicKey()
|
|
|
|
w := io.NewBufBinWriter()
|
|
emit.Array(w.BinWriter, []any{pub.Bytes(), pub.Bytes(), pub.Bytes()}...)
|
|
emit.Int(w.BinWriter, int64(2))
|
|
emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount)
|
|
require.NoError(t, w.Err)
|
|
multisigScript := slice.Copy(w.Bytes())
|
|
|
|
w.Reset()
|
|
emit.Bytes(w.BinWriter, pub.Bytes())
|
|
emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount)
|
|
require.NoError(t, w.Err)
|
|
standardScript := slice.Copy(w.Bytes())
|
|
|
|
createAccTx := func(t *testing.T, script []byte) *transaction.Transaction {
|
|
tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Committee}, bc.BlockHeight()+1)
|
|
return tx
|
|
}
|
|
|
|
// blocks #1, #2: old prices
|
|
tx1Standard := createAccTx(t, standardScript)
|
|
tx1Multisig := createAccTx(t, multisigScript)
|
|
e.AddNewBlock(t, tx1Standard, tx1Multisig)
|
|
e.CheckHalt(t, tx1Standard.Hash())
|
|
e.CheckHalt(t, tx1Multisig.Hash())
|
|
tx2Standard := createAccTx(t, standardScript)
|
|
tx2Multisig := createAccTx(t, multisigScript)
|
|
e.AddNewBlock(t, tx2Standard, tx2Multisig)
|
|
e.CheckHalt(t, tx2Standard.Hash())
|
|
e.CheckHalt(t, tx2Multisig.Hash())
|
|
|
|
// block #3: updated prices (larger than the previous ones)
|
|
require.Equal(t, uint32(enabledHeight-1), e.Chain.BlockHeight())
|
|
tx3Standard := createAccTx(t, standardScript)
|
|
tx3Multisig := createAccTx(t, multisigScript)
|
|
e.AddNewBlock(t, tx3Standard, tx3Multisig)
|
|
e.CheckHalt(t, tx3Standard.Hash())
|
|
e.CheckHalt(t, tx3Multisig.Hash())
|
|
require.True(t, tx1Standard.SystemFee == tx2Standard.SystemFee)
|
|
require.True(t, tx1Multisig.SystemFee == tx2Multisig.SystemFee)
|
|
require.True(t, tx2Standard.SystemFee < tx3Standard.SystemFee)
|
|
require.True(t, tx2Multisig.SystemFee < tx3Multisig.SystemFee)
|
|
}
|