github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/vm/numeric_test.go (about)

     1  package vm
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"testing"
     7  
     8  	"github.com/bytom/bytom/testutil"
     9  )
    10  
    11  func TestNumericOps(t *testing.T) {
    12  	type testStruct struct {
    13  		op      Op
    14  		startVM *virtualMachine
    15  		wantErr error
    16  		wantVM  *virtualMachine
    17  	}
    18  	cases := []testStruct{{
    19  		op: OP_1ADD,
    20  		startVM: &virtualMachine{
    21  			runLimit:  50000,
    22  			dataStack: [][]byte{{2}},
    23  		},
    24  		wantVM: &virtualMachine{
    25  			runLimit:  49998,
    26  			dataStack: [][]byte{{3}},
    27  		},
    28  	}, {
    29  		op: OP_1SUB,
    30  		startVM: &virtualMachine{
    31  			runLimit:  50000,
    32  			dataStack: [][]byte{{2}},
    33  		},
    34  		wantVM: &virtualMachine{
    35  			runLimit:  49998,
    36  			dataStack: [][]byte{{1}},
    37  		},
    38  	}, {
    39  		op: OP_2MUL,
    40  		startVM: &virtualMachine{
    41  			runLimit:  50000,
    42  			dataStack: [][]byte{{2}},
    43  		},
    44  		wantVM: &virtualMachine{
    45  			runLimit:  49998,
    46  			dataStack: [][]byte{{4}},
    47  		},
    48  	}, {
    49  		op: OP_2DIV,
    50  		startVM: &virtualMachine{
    51  			runLimit:  50000,
    52  			dataStack: [][]byte{{2}},
    53  		},
    54  		wantVM: &virtualMachine{
    55  			runLimit:  49998,
    56  			dataStack: [][]byte{{1}},
    57  		},
    58  	}, {
    59  		op: OP_2DIV,
    60  		startVM: &virtualMachine{
    61  			runLimit:  50000,
    62  			dataStack: [][]byte{Int64Bytes(-2)},
    63  		},
    64  		wantVM: &virtualMachine{
    65  			runLimit:  49998,
    66  			dataStack: [][]byte{Int64Bytes(-1)},
    67  		},
    68  	}, {
    69  		op: OP_2DIV,
    70  		startVM: &virtualMachine{
    71  			runLimit:  50000,
    72  			dataStack: [][]byte{Int64Bytes(-1)},
    73  		},
    74  		wantVM: &virtualMachine{
    75  			runLimit:  49998,
    76  			dataStack: [][]byte{Int64Bytes(-1)},
    77  		},
    78  	}, {
    79  		op: OP_NEGATE,
    80  		startVM: &virtualMachine{
    81  			runLimit:  50000,
    82  			dataStack: [][]byte{{2}},
    83  		},
    84  		wantVM: &virtualMachine{
    85  			runLimit:     49998,
    86  			deferredCost: 7,
    87  			dataStack:    [][]byte{Int64Bytes(-2)},
    88  		},
    89  	}, {
    90  		op: OP_ABS,
    91  		startVM: &virtualMachine{
    92  			runLimit:  50000,
    93  			dataStack: [][]byte{{2}},
    94  		},
    95  		wantVM: &virtualMachine{
    96  			runLimit:  49998,
    97  			dataStack: [][]byte{{2}},
    98  		},
    99  	}, {
   100  		op: OP_ABS,
   101  		startVM: &virtualMachine{
   102  			runLimit:  50000,
   103  			dataStack: [][]byte{Int64Bytes(-2)},
   104  		},
   105  		wantVM: &virtualMachine{
   106  			runLimit:     49998,
   107  			deferredCost: -7,
   108  			dataStack:    [][]byte{{2}},
   109  		},
   110  	}, {
   111  		op: OP_NOT,
   112  		startVM: &virtualMachine{
   113  			runLimit:  50000,
   114  			dataStack: [][]byte{{2}},
   115  		},
   116  		wantVM: &virtualMachine{
   117  			runLimit:     49998,
   118  			deferredCost: -1,
   119  			dataStack:    [][]byte{{}},
   120  		},
   121  	}, {
   122  		op: OP_0NOTEQUAL,
   123  		startVM: &virtualMachine{
   124  			runLimit:  50000,
   125  			dataStack: [][]byte{{2}},
   126  		},
   127  		wantVM: &virtualMachine{
   128  			runLimit:  49998,
   129  			dataStack: [][]byte{{1}},
   130  		},
   131  	}, {
   132  		op: OP_ADD,
   133  		startVM: &virtualMachine{
   134  			runLimit:  50000,
   135  			dataStack: [][]byte{{2}, {1}},
   136  		},
   137  		wantVM: &virtualMachine{
   138  			runLimit:     49998,
   139  			deferredCost: -9,
   140  			dataStack:    [][]byte{{3}},
   141  		},
   142  	}, {
   143  		op: OP_SUB,
   144  		startVM: &virtualMachine{
   145  			runLimit:  50000,
   146  			dataStack: [][]byte{{2}, {1}},
   147  		},
   148  		wantVM: &virtualMachine{
   149  			runLimit:     49998,
   150  			deferredCost: -9,
   151  			dataStack:    [][]byte{{1}},
   152  		},
   153  	}, {
   154  		op: OP_MUL,
   155  		startVM: &virtualMachine{
   156  			runLimit:  50000,
   157  			dataStack: [][]byte{{2}, {1}},
   158  		},
   159  		wantVM: &virtualMachine{
   160  			runLimit:     49992,
   161  			deferredCost: -9,
   162  			dataStack:    [][]byte{{2}},
   163  		},
   164  	}, {
   165  		op: OP_DIV,
   166  		startVM: &virtualMachine{
   167  			runLimit:  50000,
   168  			dataStack: [][]byte{{2}, {1}},
   169  		},
   170  		wantVM: &virtualMachine{
   171  			runLimit:     49992,
   172  			deferredCost: -9,
   173  			dataStack:    [][]byte{{2}},
   174  		},
   175  	}, {
   176  		op: OP_DIV,
   177  		startVM: &virtualMachine{
   178  			runLimit:  50000,
   179  			dataStack: [][]byte{Int64Bytes(-2), {1}},
   180  		},
   181  		wantVM: &virtualMachine{
   182  			runLimit:     49992,
   183  			deferredCost: -9,
   184  			dataStack:    [][]byte{Int64Bytes(-2)},
   185  		},
   186  	}, {
   187  		op: OP_DIV,
   188  		startVM: &virtualMachine{
   189  			runLimit:  50000,
   190  			dataStack: [][]byte{Int64Bytes(-2), Int64Bytes(-1)},
   191  		},
   192  		wantVM: &virtualMachine{
   193  			runLimit:     49992,
   194  			deferredCost: -23,
   195  			dataStack:    [][]byte{{2}},
   196  		},
   197  	}, {
   198  		op: OP_DIV,
   199  		startVM: &virtualMachine{
   200  			runLimit:  50000,
   201  			dataStack: [][]byte{Int64Bytes(-3), Int64Bytes(2)},
   202  		},
   203  		wantVM: &virtualMachine{
   204  			runLimit:     49992,
   205  			deferredCost: -9,
   206  			dataStack:    [][]byte{Int64Bytes(-1)},
   207  		},
   208  	}, {
   209  		op: OP_DIV,
   210  		startVM: &virtualMachine{
   211  			runLimit:  50000,
   212  			dataStack: [][]byte{{2}, {}},
   213  		},
   214  		wantErr: ErrDivZero,
   215  	}, {
   216  		op: OP_MOD,
   217  		startVM: &virtualMachine{
   218  			runLimit:  50000,
   219  			dataStack: [][]byte{{2}, {1}},
   220  		},
   221  		wantVM: &virtualMachine{
   222  			runLimit:     49992,
   223  			deferredCost: -10,
   224  			dataStack:    [][]byte{{}},
   225  		},
   226  	}, {
   227  		op: OP_MOD,
   228  		startVM: &virtualMachine{
   229  			runLimit:  50000,
   230  			dataStack: [][]byte{Int64Bytes(-12), {10}},
   231  		},
   232  		wantVM: &virtualMachine{
   233  			runLimit:     49992,
   234  			deferredCost: -16,
   235  			dataStack:    [][]byte{{8}},
   236  		},
   237  	}, {
   238  		op: OP_MOD,
   239  		startVM: &virtualMachine{
   240  			runLimit:  50000,
   241  			dataStack: [][]byte{{2}, {0}},
   242  		},
   243  		wantErr: ErrDivZero,
   244  	}, {
   245  		op: OP_LSHIFT,
   246  		startVM: &virtualMachine{
   247  			runLimit:  50000,
   248  			dataStack: [][]byte{{2}, {1}},
   249  		},
   250  		wantVM: &virtualMachine{
   251  			runLimit:     49992,
   252  			deferredCost: -9,
   253  			dataStack:    [][]byte{{4}},
   254  		},
   255  	}, {
   256  		op: OP_LSHIFT,
   257  		startVM: &virtualMachine{
   258  			runLimit:  50000,
   259  			dataStack: [][]byte{Int64Bytes(-2), {1}},
   260  		},
   261  		wantVM: &virtualMachine{
   262  			runLimit:     49992,
   263  			deferredCost: -9,
   264  			dataStack:    [][]byte{Int64Bytes(-4)},
   265  		},
   266  	}, {
   267  		op: OP_RSHIFT,
   268  		startVM: &virtualMachine{
   269  			runLimit:  50000,
   270  			dataStack: [][]byte{{2}, {1}},
   271  		},
   272  		wantVM: &virtualMachine{
   273  			runLimit:     49992,
   274  			deferredCost: -9,
   275  			dataStack:    [][]byte{{1}},
   276  		},
   277  	}, {
   278  		op: OP_RSHIFT,
   279  		startVM: &virtualMachine{
   280  			runLimit:  50000,
   281  			dataStack: [][]byte{Int64Bytes(-2), {1}},
   282  		},
   283  		wantVM: &virtualMachine{
   284  			runLimit:     49992,
   285  			deferredCost: -9,
   286  			dataStack:    [][]byte{Int64Bytes(-1)},
   287  		},
   288  	}, {
   289  		op: OP_BOOLAND,
   290  		startVM: &virtualMachine{
   291  			runLimit:  50000,
   292  			dataStack: [][]byte{{2}, {1}},
   293  		},
   294  		wantVM: &virtualMachine{
   295  			runLimit:     49998,
   296  			deferredCost: -9,
   297  			dataStack:    [][]byte{{1}},
   298  		},
   299  	}, {
   300  		op: OP_BOOLOR,
   301  		startVM: &virtualMachine{
   302  			runLimit:  50000,
   303  			dataStack: [][]byte{{2}, {1}},
   304  		},
   305  		wantVM: &virtualMachine{
   306  			runLimit:     49998,
   307  			deferredCost: -9,
   308  			dataStack:    [][]byte{{1}},
   309  		},
   310  	}, {
   311  		op: OP_NUMEQUAL,
   312  		startVM: &virtualMachine{
   313  			runLimit:  50000,
   314  			dataStack: [][]byte{{2}, {1}},
   315  		},
   316  		wantVM: &virtualMachine{
   317  			runLimit:     49998,
   318  			deferredCost: -10,
   319  			dataStack:    [][]byte{{}},
   320  		},
   321  	}, {
   322  		op: OP_NUMEQUALVERIFY,
   323  		startVM: &virtualMachine{
   324  			runLimit:  50000,
   325  			dataStack: [][]byte{{2}, {2}},
   326  		},
   327  		wantVM: &virtualMachine{
   328  			runLimit:     49998,
   329  			deferredCost: -18,
   330  			dataStack:    [][]byte{},
   331  		},
   332  	}, {
   333  		op: OP_NUMEQUALVERIFY,
   334  		startVM: &virtualMachine{
   335  			runLimit:  50000,
   336  			dataStack: [][]byte{{1}, {2}},
   337  		},
   338  		wantErr: ErrVerifyFailed,
   339  	}, {
   340  		op: OP_NUMNOTEQUAL,
   341  		startVM: &virtualMachine{
   342  			runLimit:  50000,
   343  			dataStack: [][]byte{{2}, {1}},
   344  		},
   345  		wantVM: &virtualMachine{
   346  			runLimit:     49998,
   347  			deferredCost: -9,
   348  			dataStack:    [][]byte{{1}},
   349  		},
   350  	}, {
   351  		op: OP_LESSTHAN,
   352  		startVM: &virtualMachine{
   353  			runLimit:  50000,
   354  			dataStack: [][]byte{{2}, {1}},
   355  		},
   356  		wantVM: &virtualMachine{
   357  			runLimit:     49998,
   358  			deferredCost: -10,
   359  			dataStack:    [][]byte{{}},
   360  		},
   361  	}, {
   362  		op: OP_LESSTHANOREQUAL,
   363  		startVM: &virtualMachine{
   364  			runLimit:  50000,
   365  			dataStack: [][]byte{{2}, {1}},
   366  		},
   367  		wantVM: &virtualMachine{
   368  			runLimit:     49998,
   369  			deferredCost: -10,
   370  			dataStack:    [][]byte{{}},
   371  		},
   372  	}, {
   373  		op: OP_GREATERTHAN,
   374  		startVM: &virtualMachine{
   375  			runLimit:  50000,
   376  			dataStack: [][]byte{{2}, {1}},
   377  		},
   378  		wantVM: &virtualMachine{
   379  			runLimit:     49998,
   380  			deferredCost: -9,
   381  			dataStack:    [][]byte{{1}},
   382  		},
   383  	}, {
   384  		op: OP_GREATERTHANOREQUAL,
   385  		startVM: &virtualMachine{
   386  			runLimit:  50000,
   387  			dataStack: [][]byte{{2}, {1}},
   388  		},
   389  		wantVM: &virtualMachine{
   390  			runLimit:     49998,
   391  			deferredCost: -9,
   392  			dataStack:    [][]byte{{1}},
   393  		},
   394  	}, {
   395  		op: OP_MIN,
   396  		startVM: &virtualMachine{
   397  			runLimit:  50000,
   398  			dataStack: [][]byte{{2}, {1}},
   399  		},
   400  		wantVM: &virtualMachine{
   401  			runLimit:     49998,
   402  			deferredCost: -9,
   403  			dataStack:    [][]byte{{1}},
   404  		},
   405  	}, {
   406  		op: OP_MIN,
   407  		startVM: &virtualMachine{
   408  			runLimit:  50000,
   409  			dataStack: [][]byte{{1}, {2}},
   410  		},
   411  		wantVM: &virtualMachine{
   412  			runLimit:     49998,
   413  			deferredCost: -9,
   414  			dataStack:    [][]byte{{1}},
   415  		},
   416  	}, {
   417  		op: OP_MAX,
   418  		startVM: &virtualMachine{
   419  			runLimit:  50000,
   420  			dataStack: [][]byte{{2}, {1}},
   421  		},
   422  		wantVM: &virtualMachine{
   423  			runLimit:     49998,
   424  			deferredCost: -9,
   425  			dataStack:    [][]byte{{2}},
   426  		},
   427  	}, {
   428  		op: OP_MAX,
   429  		startVM: &virtualMachine{
   430  			runLimit:  50000,
   431  			dataStack: [][]byte{{1}, {2}},
   432  		},
   433  		wantVM: &virtualMachine{
   434  			runLimit:     49998,
   435  			deferredCost: -9,
   436  			dataStack:    [][]byte{{2}},
   437  		},
   438  	}, {
   439  		op: OP_WITHIN,
   440  		startVM: &virtualMachine{
   441  			runLimit:  50000,
   442  			dataStack: [][]byte{{1}, {1}, {2}},
   443  		},
   444  		wantVM: &virtualMachine{
   445  			runLimit:     49996,
   446  			deferredCost: -18,
   447  			dataStack:    [][]byte{{1}},
   448  		},
   449  	}}
   450  
   451  	numops := []Op{
   452  		OP_1ADD, OP_1SUB, OP_2MUL, OP_2DIV, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL,
   453  		OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT, OP_BOOLAND,
   454  		OP_BOOLOR, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN,
   455  		OP_LESSTHANOREQUAL, OP_GREATERTHAN, OP_GREATERTHANOREQUAL, OP_MIN, OP_MAX, OP_WITHIN,
   456  	}
   457  
   458  	for _, op := range numops {
   459  		cases = append(cases, testStruct{
   460  			op: op,
   461  			startVM: &virtualMachine{
   462  				runLimit:  0,
   463  				dataStack: [][]byte{{2}, {2}, {2}},
   464  			},
   465  			wantErr: ErrRunLimitExceeded,
   466  		})
   467  	}
   468  
   469  	for i, c := range cases {
   470  		err := ops[c.op].fn(c.startVM)
   471  
   472  		if err != c.wantErr {
   473  			t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
   474  			continue
   475  		}
   476  		if c.wantErr != nil {
   477  			continue
   478  		}
   479  
   480  		if !testutil.DeepEqual(c.startVM, c.wantVM) {
   481  			t.Errorf("case %d, op %s: unexpected vm result\n\tgot:  %+v\n\twant: %+v\n", i, ops[c.op].name, c.startVM, c.wantVM)
   482  		}
   483  	}
   484  }
   485  
   486  func TestRangeErrs(t *testing.T) {
   487  	cases := []struct {
   488  		prog           string
   489  		expectRangeErr bool
   490  	}{
   491  		{"0 1ADD", false},
   492  		{fmt.Sprintf("%d 1ADD", int64(math.MinInt64)), false},
   493  		{fmt.Sprintf("%d 1ADD", int64(math.MaxInt64)-1), false},
   494  		{fmt.Sprintf("%d 1ADD", int64(math.MaxInt64)), true},
   495  		{"0 1SUB", false},
   496  		{fmt.Sprintf("%d 1SUB", int64(math.MaxInt64)), false},
   497  		{fmt.Sprintf("%d 1SUB", int64(math.MinInt64)+1), false},
   498  		{fmt.Sprintf("%d 1SUB", int64(math.MinInt64)), true},
   499  		{"1 2MUL", false},
   500  		{fmt.Sprintf("%d 2MUL", int64(math.MaxInt64)/2-1), false},
   501  		{fmt.Sprintf("%d 2MUL", int64(math.MaxInt64)/2+1), true},
   502  		{fmt.Sprintf("%d 2MUL", int64(math.MinInt64)/2+1), false},
   503  		{fmt.Sprintf("%d 2MUL", int64(math.MinInt64)/2-1), true},
   504  		{"1 NEGATE", false},
   505  		{"-1 NEGATE", false},
   506  		{fmt.Sprintf("%d NEGATE", int64(math.MaxInt64)), false},
   507  		{fmt.Sprintf("%d NEGATE", int64(math.MinInt64)), true},
   508  		{"1 ABS", false},
   509  		{"-1 ABS", false},
   510  		{fmt.Sprintf("%d ABS", int64(math.MaxInt64)), false},
   511  		{fmt.Sprintf("%d ABS", int64(math.MinInt64)), true},
   512  		{"2 3 ADD", false},
   513  		{fmt.Sprintf("%d %d ADD", int64(math.MinInt64), int64(math.MaxInt64)), false},
   514  		{fmt.Sprintf("%d %d ADD", int64(math.MaxInt64)/2-1, int64(math.MaxInt64)/2-2), false},
   515  		{fmt.Sprintf("%d %d ADD", int64(math.MaxInt64)/2+1, int64(math.MaxInt64)/2+2), true},
   516  		{fmt.Sprintf("%d %d ADD", int64(math.MinInt64)/2+1, int64(math.MinInt64)/2+2), false},
   517  		{fmt.Sprintf("%d %d ADD", int64(math.MinInt64)/2-1, int64(math.MinInt64)/2-2), true},
   518  		{"2 3 SUB", false},
   519  		{fmt.Sprintf("1 %d SUB", int64(math.MaxInt64)), false},
   520  		{fmt.Sprintf("-1 %d SUB", int64(math.MinInt64)), false},
   521  		{fmt.Sprintf("1 %d SUB", int64(math.MinInt64)), true},
   522  		{fmt.Sprintf("-1 %d SUB", int64(math.MaxInt64)), false},
   523  		{fmt.Sprintf("-2 %d SUB", int64(math.MaxInt64)), true},
   524  		{"1 2 LSHIFT", false},
   525  		{"-1 2 LSHIFT", false},
   526  		{"-1 63 LSHIFT", false},
   527  		{"-1 64 LSHIFT", true},
   528  		{"0 64 LSHIFT", false},
   529  		{"1 62 LSHIFT", false},
   530  		{"1 63 LSHIFT", true},
   531  		{fmt.Sprintf("%d 0 LSHIFT", int64(math.MaxInt64)), false},
   532  		{fmt.Sprintf("%d 1 LSHIFT", int64(math.MaxInt64)), true},
   533  		{fmt.Sprintf("%d 1 LSHIFT", int64(math.MaxInt64)/2), false},
   534  		{fmt.Sprintf("%d 2 LSHIFT", int64(math.MaxInt64)/2), true},
   535  		{fmt.Sprintf("%d 0 LSHIFT", int64(math.MinInt64)), false},
   536  		{fmt.Sprintf("%d 1 LSHIFT", int64(math.MinInt64)), true},
   537  		{fmt.Sprintf("%d 1 LSHIFT", int64(math.MinInt64)/2), false},
   538  		{fmt.Sprintf("%d 2 LSHIFT", int64(math.MinInt64)/2), true},
   539  	}
   540  
   541  	for i, c := range cases {
   542  		prog, _ := Assemble(c.prog)
   543  		vm := &virtualMachine{
   544  			program:  prog,
   545  			runLimit: 50000,
   546  		}
   547  		err := vm.run()
   548  		switch err {
   549  		case nil:
   550  			if c.expectRangeErr {
   551  				t.Errorf("case %d (%s): expected range error, got none", i, c.prog)
   552  			}
   553  		case ErrRange:
   554  			if !c.expectRangeErr {
   555  				t.Errorf("case %d (%s): got unexpected range error", i, c.prog)
   556  			}
   557  		default:
   558  			if c.expectRangeErr {
   559  				t.Errorf("case %d (%s): expected range error, got %s", i, c.prog, err)
   560  			} else {
   561  				t.Errorf("case %d (%s): got unexpected error %s", i, c.prog, err)
   562  			}
   563  		}
   564  	}
   565  }