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

     1  package vm
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/bytom/bytom/testutil"
    11  )
    12  
    13  func TestStackOps(t *testing.T) {
    14  	type testStruct struct {
    15  		op      Op
    16  		startVM *virtualMachine
    17  		wantErr error
    18  		wantVM  *virtualMachine
    19  	}
    20  
    21  	cases := []testStruct{{
    22  		op: OP_TOALTSTACK,
    23  		startVM: &virtualMachine{
    24  			runLimit:  50000,
    25  			dataStack: [][]byte{{1}},
    26  		},
    27  		wantVM: &virtualMachine{
    28  			runLimit:  49998,
    29  			dataStack: [][]byte{},
    30  			altStack:  [][]byte{{1}},
    31  		},
    32  	}, {
    33  		op: OP_FROMALTSTACK,
    34  		startVM: &virtualMachine{
    35  			runLimit: 50000,
    36  			altStack: [][]byte{{1}},
    37  		},
    38  		wantVM: &virtualMachine{
    39  			runLimit:  49998,
    40  			altStack:  [][]byte{},
    41  			dataStack: [][]byte{{1}},
    42  		},
    43  	}, {
    44  		op: OP_FROMALTSTACK,
    45  		startVM: &virtualMachine{
    46  			runLimit: 50000,
    47  			altStack: [][]byte{},
    48  		},
    49  		wantErr: ErrAltStackUnderflow,
    50  	}, {
    51  		op: OP_2DROP,
    52  		startVM: &virtualMachine{
    53  			runLimit:  50000,
    54  			dataStack: [][]byte{{1}, {1}},
    55  		},
    56  		wantVM: &virtualMachine{
    57  			runLimit:  50016,
    58  			dataStack: [][]byte{},
    59  		},
    60  	}, {
    61  		op: OP_2DUP,
    62  		startVM: &virtualMachine{
    63  			runLimit:  50000,
    64  			dataStack: [][]byte{{2}, {1}},
    65  		},
    66  		wantVM: &virtualMachine{
    67  			runLimit:  49980,
    68  			dataStack: [][]byte{{2}, {1}, {2}, {1}},
    69  		},
    70  	}, {
    71  		op: OP_3DUP,
    72  		startVM: &virtualMachine{
    73  			runLimit:  50000,
    74  			dataStack: [][]byte{{3}, {2}, {1}},
    75  		},
    76  		wantVM: &virtualMachine{
    77  			runLimit:  49970,
    78  			dataStack: [][]byte{{3}, {2}, {1}, {3}, {2}, {1}},
    79  		},
    80  	}, {
    81  		op: OP_2OVER,
    82  		startVM: &virtualMachine{
    83  			runLimit:  50000,
    84  			dataStack: [][]byte{{4}, {3}, {2}, {1}},
    85  		},
    86  		wantVM: &virtualMachine{
    87  			runLimit:  49980,
    88  			dataStack: [][]byte{{4}, {3}, {2}, {1}, {4}, {3}},
    89  		},
    90  	}, {
    91  		op: OP_2OVER,
    92  		startVM: &virtualMachine{
    93  			runLimit:  2,
    94  			dataStack: [][]byte{{4}, {3}, {2}, {1}},
    95  		},
    96  		wantErr: ErrRunLimitExceeded,
    97  	}, {
    98  		op: OP_2ROT,
    99  		startVM: &virtualMachine{
   100  			runLimit:  50000,
   101  			dataStack: [][]byte{{6}, {5}, {4}, {3}, {2}, {1}},
   102  		},
   103  		wantVM: &virtualMachine{
   104  			runLimit:  49998,
   105  			dataStack: [][]byte{{4}, {3}, {2}, {1}, {6}, {5}},
   106  		},
   107  	}, {
   108  		op: OP_2SWAP,
   109  		startVM: &virtualMachine{
   110  			runLimit:  50000,
   111  			dataStack: [][]byte{{4}, {3}, {2}, {1}},
   112  		},
   113  		wantVM: &virtualMachine{
   114  			runLimit:  49998,
   115  			dataStack: [][]byte{{2}, {1}, {4}, {3}},
   116  		},
   117  	}, {
   118  		op: OP_IFDUP,
   119  		startVM: &virtualMachine{
   120  			runLimit:  50000,
   121  			dataStack: [][]byte{{1}},
   122  		},
   123  		wantVM: &virtualMachine{
   124  			runLimit:  49990,
   125  			dataStack: [][]byte{{1}, {1}},
   126  		},
   127  	}, {
   128  		op: OP_IFDUP,
   129  		startVM: &virtualMachine{
   130  			runLimit:  50000,
   131  			dataStack: [][]byte{{}},
   132  		},
   133  		wantVM: &virtualMachine{
   134  			runLimit:  49999,
   135  			dataStack: [][]byte{{}},
   136  		},
   137  	}, {
   138  		op: OP_IFDUP,
   139  		startVM: &virtualMachine{
   140  			runLimit:  1,
   141  			dataStack: [][]byte{{1}},
   142  		},
   143  		wantErr: ErrRunLimitExceeded,
   144  	}, {
   145  		op: OP_DEPTH,
   146  		startVM: &virtualMachine{
   147  			runLimit:  50000,
   148  			dataStack: [][]byte{{1}},
   149  		},
   150  		wantVM: &virtualMachine{
   151  			runLimit:  49990,
   152  			dataStack: [][]byte{{1}, {1}},
   153  		},
   154  	}, {
   155  		op: OP_DEPTH,
   156  		startVM: &virtualMachine{
   157  			runLimit:  1,
   158  			dataStack: [][]byte{{1}},
   159  		},
   160  		wantErr: ErrRunLimitExceeded,
   161  	}, {
   162  		op: OP_DROP,
   163  		startVM: &virtualMachine{
   164  			runLimit:  50000,
   165  			dataStack: [][]byte{{1}},
   166  		},
   167  		wantVM: &virtualMachine{
   168  			runLimit:  50008,
   169  			dataStack: [][]byte{},
   170  		},
   171  	}, {
   172  		op: OP_DUP,
   173  		startVM: &virtualMachine{
   174  			runLimit:  50000,
   175  			dataStack: [][]byte{{1}},
   176  		},
   177  		wantVM: &virtualMachine{
   178  			runLimit:  49990,
   179  			dataStack: [][]byte{{1}, {1}},
   180  		},
   181  	}, {
   182  		op: OP_DUP,
   183  		startVM: &virtualMachine{
   184  			runLimit:  1,
   185  			dataStack: [][]byte{{1}},
   186  		},
   187  		wantErr: ErrRunLimitExceeded,
   188  	}, {
   189  		op: OP_NIP,
   190  		startVM: &virtualMachine{
   191  			runLimit:  50000,
   192  			dataStack: [][]byte{{2}, {1}},
   193  		},
   194  		wantVM: &virtualMachine{
   195  			runLimit:  50008,
   196  			dataStack: [][]byte{{1}},
   197  		},
   198  	}, {
   199  		op: OP_OVER,
   200  		startVM: &virtualMachine{
   201  			runLimit:  50000,
   202  			dataStack: [][]byte{{2}, {1}},
   203  		},
   204  		wantVM: &virtualMachine{
   205  			runLimit:  49990,
   206  			dataStack: [][]byte{{2}, {1}, {2}},
   207  		},
   208  	}, {
   209  		op: OP_OVER,
   210  		startVM: &virtualMachine{
   211  			runLimit:  1,
   212  			dataStack: [][]byte{{2}, {1}},
   213  		},
   214  		wantErr: ErrRunLimitExceeded,
   215  	}, {
   216  		op: OP_PICK,
   217  		startVM: &virtualMachine{
   218  			runLimit:  50000,
   219  			dataStack: [][]byte{{3}, {2}, {1}, {2}},
   220  		},
   221  		wantVM: &virtualMachine{
   222  			runLimit:  49998,
   223  			dataStack: [][]byte{{3}, {2}, {1}, {3}},
   224  		},
   225  	}, {
   226  		op: OP_PICK,
   227  		startVM: &virtualMachine{
   228  			runLimit:  2,
   229  			dataStack: [][]byte{{0xff, 0xff}, {2}, {1}, {2}},
   230  		},
   231  		wantErr: ErrRunLimitExceeded,
   232  	}, {
   233  		op: OP_ROLL,
   234  		startVM: &virtualMachine{
   235  			runLimit:  50000,
   236  			dataStack: [][]byte{{3}, {2}, {1}, {2}},
   237  		},
   238  		wantVM: &virtualMachine{
   239  			runLimit:  50007,
   240  			dataStack: [][]byte{{2}, {1}, {3}},
   241  		},
   242  	}, {
   243  		op: OP_ROT,
   244  		startVM: &virtualMachine{
   245  			runLimit:  50000,
   246  			dataStack: [][]byte{{3}, {2}, {1}},
   247  		},
   248  		wantVM: &virtualMachine{
   249  			runLimit:  49998,
   250  			dataStack: [][]byte{{2}, {1}, {3}},
   251  		},
   252  	}, {
   253  		op: OP_SWAP,
   254  		startVM: &virtualMachine{
   255  			runLimit:  50000,
   256  			dataStack: [][]byte{{2}, {1}},
   257  		},
   258  		wantVM: &virtualMachine{
   259  			runLimit:  49999,
   260  			dataStack: [][]byte{{1}, {2}},
   261  		},
   262  	}, {
   263  		op: OP_TUCK,
   264  		startVM: &virtualMachine{
   265  			runLimit:  50000,
   266  			dataStack: [][]byte{{2}, {1}},
   267  		},
   268  		wantVM: &virtualMachine{
   269  			runLimit:  49990,
   270  			dataStack: [][]byte{{1}, {2}, {1}},
   271  		},
   272  	}, {
   273  		op: OP_TUCK,
   274  		startVM: &virtualMachine{
   275  			runLimit:  1,
   276  			dataStack: [][]byte{{2}, {1}},
   277  		},
   278  		wantErr: ErrRunLimitExceeded,
   279  	}}
   280  	stackops := []Op{
   281  		OP_DEPTH, OP_FROMALTSTACK, OP_TOALTSTACK, OP_2DROP, OP_2DUP, OP_3DUP,
   282  		OP_2OVER, OP_2ROT, OP_2SWAP, OP_IFDUP, OP_DROP, OP_DUP, OP_NIP,
   283  		OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK,
   284  	}
   285  	for _, op := range stackops {
   286  		cases = append(cases, testStruct{
   287  			op:      op,
   288  			startVM: &virtualMachine{runLimit: 0},
   289  			wantErr: ErrRunLimitExceeded,
   290  		})
   291  	}
   292  
   293  	for i, c := range cases {
   294  		err := ops[c.op].fn(c.startVM)
   295  
   296  		if err != c.wantErr {
   297  			t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
   298  			continue
   299  		}
   300  		if c.wantErr != nil {
   301  			continue
   302  		}
   303  
   304  		if !testutil.DeepEqual(c.startVM, c.wantVM) {
   305  			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)
   306  		}
   307  	}
   308  }
   309  
   310  func TestStackUnderflow(t *testing.T) {
   311  	cases := []struct {
   312  		narg int // number of stack items required
   313  		op   func(*virtualMachine) error
   314  	}{
   315  		// bitwise
   316  		{1, opInvert},
   317  		{2, opAnd},
   318  		{2, opOr},
   319  		{2, opXor},
   320  		{2, opEqual},
   321  		{2, opEqualVerify},
   322  
   323  		// control
   324  		{1, opVerify},
   325  		{3, opCheckPredicate},
   326  		{1, opJumpIf},
   327  
   328  		// crypto
   329  		{1, opSha256},
   330  		{1, opSha3},
   331  		{3, opCheckSig},
   332  		{3, opCheckMultiSig}, // special, see also TestCryptoOps
   333  
   334  		// introspection
   335  		{5, opCheckOutput},
   336  
   337  		// numeric
   338  		{1, op1Add},
   339  		{1, op1Sub},
   340  		{1, op2Mul},
   341  		{1, op2Div},
   342  		{1, opNegate},
   343  		{1, opAbs},
   344  		{1, opNot},
   345  		{1, op0NotEqual},
   346  		{2, opAdd},
   347  		{2, opSub},
   348  		{2, opMul},
   349  		{2, opDiv},
   350  		{2, opMod},
   351  		{2, opLshift},
   352  		{2, opRshift},
   353  		{2, opBoolAnd},
   354  		{2, opBoolOr},
   355  		{2, opNumEqual},
   356  		{2, opNumEqualVerify},
   357  		{2, opNumNotEqual},
   358  		{2, opLessThan},
   359  		{2, opGreaterThan},
   360  		{2, opLessThanOrEqual},
   361  		{2, opGreaterThanOrEqual},
   362  		{2, opMin},
   363  		{2, opMax},
   364  		{3, opWithin},
   365  
   366  		// splice
   367  		{2, opCat},
   368  		{3, opSubstr},
   369  		{2, opLeft},
   370  		{2, opRight},
   371  		{1, opSize},
   372  		{2, opCatpushdata},
   373  
   374  		// stack
   375  		{1, opToAltStack},
   376  		{2, op2Drop},
   377  		{2, op2Dup},
   378  		{3, op3Dup},
   379  		{4, op2Over},
   380  		{6, op2Rot},
   381  		{4, op2Swap},
   382  		{1, opIfDup},
   383  		{1, opDrop},
   384  		{1, opDup},
   385  		{2, opNip},
   386  		{2, opOver},
   387  		{2, opPick}, // TODO(kr): special; check data-dependent # of pops
   388  		{2, opRoll}, // TODO(kr): special; check data-dependent # of pops
   389  		{3, opRot},
   390  		{2, opSwap},
   391  		{2, opTuck},
   392  	}
   393  
   394  	for _, test := range cases {
   395  		t.Run(funcName(test.op), func(t *testing.T) {
   396  
   397  			for i := 0; i < test.narg; i++ {
   398  				t.Run(fmt.Sprintf("%d args", i), func(t *testing.T) {
   399  
   400  					vm := &virtualMachine{
   401  						runLimit:  50000,
   402  						dataStack: make([][]byte, i),
   403  					}
   404  					err := test.op(vm)
   405  					if err != ErrDataStackUnderflow {
   406  						t.Errorf("err = %v, want ErrStackUnderflow", err)
   407  					}
   408  
   409  				})
   410  			}
   411  
   412  		})
   413  	}
   414  }
   415  
   416  func funcName(f interface{}) string {
   417  	v := reflect.ValueOf(f)
   418  	if v.Kind() != reflect.Func {
   419  		return ""
   420  	}
   421  	s := runtime.FuncForPC(v.Pointer()).Name()
   422  	return s[strings.LastIndex(s, ".")+1:]
   423  }