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 }