github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/interop/contract/account_test.go (about)

     1  package contract_test
     2  
     3  import (
     4  	"bytes"
     5  	"math"
     6  	"math/big"
     7  	"testing"
     8  
     9  	"github.com/nspcc-dev/neo-go/pkg/config"
    10  	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
    11  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    12  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    13  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    14  	"github.com/nspcc-dev/neo-go/pkg/io"
    15  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    16  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    17  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    18  	"github.com/nspcc-dev/neo-go/pkg/util"
    19  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestCreateStandardAccount(t *testing.T) {
    24  	bc, acc := chain.NewSingle(t)
    25  	e := neotest.NewExecutor(t, bc, acc, acc)
    26  	w := io.NewBufBinWriter()
    27  
    28  	t.Run("Good", func(t *testing.T) {
    29  		priv, err := keys.NewPrivateKey()
    30  		require.NoError(t, err)
    31  		pub := priv.PublicKey()
    32  
    33  		emit.Bytes(w.BinWriter, pub.Bytes())
    34  		emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount)
    35  		require.NoError(t, w.Err)
    36  		script := w.Bytes()
    37  
    38  		tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Validator}, bc.BlockHeight()+1)
    39  		e.AddNewBlock(t, tx)
    40  		e.CheckHalt(t, tx.Hash())
    41  
    42  		res := e.GetTxExecResult(t, tx.Hash())
    43  		value := res.Stack[0].Value().([]byte)
    44  		u, err := util.Uint160DecodeBytesBE(value)
    45  		require.NoError(t, err)
    46  		require.Equal(t, pub.GetScriptHash(), u)
    47  	})
    48  	t.Run("InvalidKey", func(t *testing.T) {
    49  		w.Reset()
    50  		emit.Bytes(w.BinWriter, []byte{1, 2, 3})
    51  		emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount)
    52  		require.NoError(t, w.Err)
    53  		script := w.Bytes()
    54  
    55  		tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Validator}, bc.BlockHeight()+1)
    56  		e.AddNewBlock(t, tx)
    57  		e.CheckFault(t, tx.Hash(), "invalid prefix 1")
    58  	})
    59  }
    60  
    61  func TestCreateMultisigAccount(t *testing.T) {
    62  	bc, acc := chain.NewSingle(t)
    63  	e := neotest.NewExecutor(t, bc, acc, acc)
    64  	w := io.NewBufBinWriter()
    65  
    66  	createScript := func(t *testing.T, pubs []any, m int) []byte {
    67  		w.Reset()
    68  		emit.Array(w.BinWriter, pubs...)
    69  		emit.Int(w.BinWriter, int64(m))
    70  		emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount)
    71  		require.NoError(t, w.Err)
    72  		return w.Bytes()
    73  	}
    74  	t.Run("Good", func(t *testing.T) {
    75  		m, n := 3, 5
    76  		pubs := make(keys.PublicKeys, n)
    77  		arr := make([]any, n)
    78  		for i := range pubs {
    79  			pk, err := keys.NewPrivateKey()
    80  			require.NoError(t, err)
    81  			pubs[i] = pk.PublicKey()
    82  			arr[i] = pubs[i].Bytes()
    83  		}
    84  		script := createScript(t, arr, m)
    85  
    86  		txH := e.InvokeScript(t, script, []neotest.Signer{acc})
    87  		e.CheckHalt(t, txH)
    88  		res := e.GetTxExecResult(t, txH)
    89  		value := res.Stack[0].Value().([]byte)
    90  		u, err := util.Uint160DecodeBytesBE(value)
    91  		require.NoError(t, err)
    92  		expected, err := smartcontract.CreateMultiSigRedeemScript(m, pubs)
    93  		require.NoError(t, err)
    94  		require.Equal(t, hash.Hash160(expected), u)
    95  	})
    96  	t.Run("InvalidKey", func(t *testing.T) {
    97  		script := createScript(t, []any{[]byte{1, 2, 3}}, 1)
    98  		e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "invalid prefix 1")
    99  	})
   100  	t.Run("Invalid m", func(t *testing.T) {
   101  		pk, err := keys.NewPrivateKey()
   102  		require.NoError(t, err)
   103  		script := createScript(t, []any{pk.PublicKey().Bytes()}, 2)
   104  		e.InvokeScriptCheckFAULT(t, script, []neotest.Signer{acc}, "length of the signatures (2) is higher then the number of public keys")
   105  	})
   106  	t.Run("m overflows int32", func(t *testing.T) {
   107  		pk, err := keys.NewPrivateKey()
   108  		require.NoError(t, err)
   109  		m := big.NewInt(math.MaxInt32)
   110  		m.Add(m, big.NewInt(1))
   111  		w.Reset()
   112  		emit.Array(w.BinWriter, pk.Bytes())
   113  		emit.BigInt(w.BinWriter, m)
   114  		emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount)
   115  		require.NoError(t, w.Err)
   116  		e.InvokeScriptCheckFAULT(t, w.Bytes(), []neotest.Signer{acc}, "m must be positive and fit int32")
   117  	})
   118  }
   119  
   120  func TestCreateAccount_HFAspidochelone(t *testing.T) {
   121  	const enabledHeight = 3
   122  	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
   123  		c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled
   124  		c.Hardforks = map[string]uint32{
   125  			config.HFAspidochelone.String(): enabledHeight,
   126  		}
   127  	})
   128  	e := neotest.NewExecutor(t, bc, acc, acc)
   129  
   130  	priv, err := keys.NewPrivateKey()
   131  	require.NoError(t, err)
   132  	pub := priv.PublicKey()
   133  
   134  	w := io.NewBufBinWriter()
   135  	emit.Array(w.BinWriter, []any{pub.Bytes(), pub.Bytes(), pub.Bytes()}...)
   136  	emit.Int(w.BinWriter, int64(2))
   137  	emit.Syscall(w.BinWriter, interopnames.SystemContractCreateMultisigAccount)
   138  	require.NoError(t, w.Err)
   139  	multisigScript := bytes.Clone(w.Bytes())
   140  
   141  	w.Reset()
   142  	emit.Bytes(w.BinWriter, pub.Bytes())
   143  	emit.Syscall(w.BinWriter, interopnames.SystemContractCreateStandardAccount)
   144  	require.NoError(t, w.Err)
   145  	standardScript := bytes.Clone(w.Bytes())
   146  
   147  	createAccTx := func(t *testing.T, script []byte) *transaction.Transaction {
   148  		tx := e.PrepareInvocation(t, script, []neotest.Signer{e.Committee}, bc.BlockHeight()+1)
   149  		return tx
   150  	}
   151  
   152  	// blocks #1, #2: old prices
   153  	tx1Standard := createAccTx(t, standardScript)
   154  	tx1Multisig := createAccTx(t, multisigScript)
   155  	e.AddNewBlock(t, tx1Standard, tx1Multisig)
   156  	e.CheckHalt(t, tx1Standard.Hash())
   157  	e.CheckHalt(t, tx1Multisig.Hash())
   158  	tx2Standard := createAccTx(t, standardScript)
   159  	tx2Multisig := createAccTx(t, multisigScript)
   160  	e.AddNewBlock(t, tx2Standard, tx2Multisig)
   161  	e.CheckHalt(t, tx2Standard.Hash())
   162  	e.CheckHalt(t, tx2Multisig.Hash())
   163  
   164  	// block #3: updated prices (larger than the previous ones)
   165  	require.Equal(t, uint32(enabledHeight-1), e.Chain.BlockHeight())
   166  	tx3Standard := createAccTx(t, standardScript)
   167  	tx3Multisig := createAccTx(t, multisigScript)
   168  	e.AddNewBlock(t, tx3Standard, tx3Multisig)
   169  	e.CheckHalt(t, tx3Standard.Hash())
   170  	e.CheckHalt(t, tx3Multisig.Hash())
   171  	require.True(t, tx1Standard.SystemFee == tx2Standard.SystemFee)
   172  	require.True(t, tx1Multisig.SystemFee == tx2Multisig.SystemFee)
   173  	require.True(t, tx2Standard.SystemFee < tx3Standard.SystemFee)
   174  	require.True(t, tx2Multisig.SystemFee < tx3Multisig.SystemFee)
   175  }