github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/native/native_test/common_test.go (about)

     1  package native_test
     2  
     3  import (
     4  	"math/big"
     5  	"testing"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/config"
     8  	"github.com/nspcc-dev/neo-go/pkg/core/native"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
    10  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    11  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    12  	"github.com/nspcc-dev/neo-go/pkg/io"
    13  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    14  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    15  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    16  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    17  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    18  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func newNativeClient(t *testing.T, name string) *neotest.ContractInvoker {
    23  	return newCustomNativeClient(t, name, nil)
    24  }
    25  
    26  func newCustomNativeClient(t *testing.T, name string, f func(cfg *config.Blockchain)) *neotest.ContractInvoker {
    27  	bc, acc := chain.NewSingleWithCustomConfig(t, f)
    28  	e := neotest.NewExecutor(t, bc, acc, acc)
    29  
    30  	return e.CommitteeInvoker(e.NativeHash(t, name))
    31  }
    32  
    33  func testGetSet(t *testing.T, c *neotest.ContractInvoker, name string, defaultValue, minValue, maxValue int64) {
    34  	getName := "get" + name
    35  	setName := "set" + name
    36  
    37  	randomInvoker := c.WithSigners(c.NewAccount(t))
    38  	committeeInvoker := c.WithSigners(c.Committee)
    39  
    40  	t.Run("set, not signed by committee", func(t *testing.T) {
    41  		randomInvoker.InvokeFail(t, "invalid committee signature", setName, minValue+1)
    42  	})
    43  	t.Run("get, default value", func(t *testing.T) {
    44  		randomInvoker.Invoke(t, defaultValue, getName)
    45  	})
    46  	t.Run("set, too small value", func(t *testing.T) {
    47  		committeeInvoker.InvokeFail(t, "", setName, minValue-1)
    48  	})
    49  
    50  	if maxValue != 0 {
    51  		t.Run("set, too large value", func(t *testing.T) {
    52  			// use big.Int because max can be `math.MaxInt64`
    53  			max := big.NewInt(maxValue)
    54  			max.Add(max, big.NewInt(1))
    55  			committeeInvoker.InvokeFail(t, "", setName, max)
    56  		})
    57  	}
    58  
    59  	t.Run("set, success", func(t *testing.T) {
    60  		// Set and get in the same block.
    61  		txSet := committeeInvoker.PrepareInvoke(t, setName, defaultValue+1)
    62  		txGet := randomInvoker.PrepareInvoke(t, getName)
    63  		c.AddNewBlock(t, txSet, txGet)
    64  		c.CheckHalt(t, txSet.Hash(), stackitem.Null{})
    65  
    66  		switch name {
    67  		case "GasPerBlock":
    68  			// GasPerBlock is set on the next block
    69  			c.CheckHalt(t, txGet.Hash(), stackitem.Make(defaultValue))
    70  			c.AddNewBlock(t)
    71  			randomInvoker.Invoke(t, defaultValue+1, getName)
    72  		case "ExecFeeFactor":
    73  			// ExecFeeFactor was risen, so the second transaction will fail because
    74  			// of gas limit exceeding (its fees are out-of-date).
    75  			c.CheckFault(t, txGet.Hash(), "gas limit exceeded")
    76  			// Set in a separate block.
    77  			committeeInvoker.Invoke(t, stackitem.Null{}, setName, defaultValue+1)
    78  			// Get in the next block.
    79  			randomInvoker.Invoke(t, defaultValue+1, getName)
    80  		default:
    81  			c.CheckHalt(t, txGet.Hash(), stackitem.Make(defaultValue+1))
    82  			// Get in the next block.
    83  			randomInvoker.Invoke(t, defaultValue+1, getName)
    84  		}
    85  	})
    86  }
    87  
    88  func testGetSetCache(t *testing.T, c *neotest.ContractInvoker, name string, defaultValue int64) {
    89  	getName := "get" + name
    90  	setName := "set" + name
    91  
    92  	committeeInvoker := c.WithSigners(c.Committee)
    93  
    94  	newVal := defaultValue - 1
    95  
    96  	// Change fee, abort the transaction and check that contract cache wasn't persisted
    97  	// for FAULTed tx at the same block.
    98  	w := io.NewBufBinWriter()
    99  	emit.AppCall(w.BinWriter, committeeInvoker.Hash, setName, callflag.All, newVal)
   100  	emit.Opcodes(w.BinWriter, opcode.ABORT)
   101  	tx1 := committeeInvoker.PrepareInvocation(t, w.Bytes(), committeeInvoker.Signers)
   102  	tx2 := committeeInvoker.PrepareInvoke(t, getName)
   103  	committeeInvoker.AddNewBlock(t, tx1, tx2)
   104  	committeeInvoker.CheckFault(t, tx1.Hash(), "ABORT")
   105  	committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(defaultValue))
   106  
   107  	// Change fee and check that change is available for the next tx.
   108  	tx1 = committeeInvoker.PrepareInvoke(t, setName, newVal)
   109  	tx2 = committeeInvoker.PrepareInvoke(t, getName)
   110  	committeeInvoker.AddNewBlock(t, tx1, tx2)
   111  	committeeInvoker.CheckHalt(t, tx1.Hash())
   112  	if name != "GasPerBlock" {
   113  		committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(newVal))
   114  	} else {
   115  		committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(defaultValue))
   116  		committeeInvoker.Invoke(t, newVal, getName)
   117  	}
   118  }
   119  
   120  func setNodesByRole(t *testing.T, designateInvoker *neotest.ContractInvoker, ok bool, r noderoles.Role, nodes keys.PublicKeys) {
   121  	pubs := make([]any, len(nodes))
   122  	for i := range nodes {
   123  		pubs[i] = nodes[i].Bytes()
   124  	}
   125  	if ok {
   126  		h := designateInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(r), pubs)
   127  		designateInvoker.CheckTxNotificationEvent(t, h, 0, state.NotificationEvent{
   128  			ScriptHash: designateInvoker.Hash,
   129  			Name:       native.DesignationEventName,
   130  			Item: stackitem.NewArray([]stackitem.Item{
   131  				stackitem.Make(int64(r)),
   132  				stackitem.Make(designateInvoker.Chain.BlockHeight()),
   133  			}),
   134  		})
   135  	} else {
   136  		designateInvoker.InvokeFail(t, "", "designateAsRole", int64(r), pubs)
   137  	}
   138  }
   139  
   140  func checkNodeRoles(t *testing.T, designateInvoker *neotest.ContractInvoker, ok bool, r noderoles.Role, index uint32, res keys.PublicKeys) {
   141  	if ok {
   142  		designateInvoker.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
   143  			require.Equal(t, 1, len(stack))
   144  			arr := stack[0].Value().([]stackitem.Item)
   145  			require.Equal(t, len(res), len(arr))
   146  			for i := range arr {
   147  				require.Equal(t, res[i].Bytes(), arr[i].Value().([]byte), i)
   148  			}
   149  		}, "getDesignatedByRole", int64(r), int64(index))
   150  	} else {
   151  		designateInvoker.InvokeFail(t, "", "getDesignatedByRole", int64(r), int64(index))
   152  	}
   153  }