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

     1  package vm
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/davecgh/go-spew/spew"
     7  
     8  	"github.com/bytom/bytom/errors"
     9  	"github.com/bytom/bytom/testutil"
    10  )
    11  
    12  func TestOutputIDAndNonceOp(t *testing.T) {
    13  	// arbitrary
    14  	outputID := mustDecodeHex("0a60f9b12950c84c221012a808ef7782823b7e16b71fe2ba01811cda96a217df")
    15  
    16  	prog := []byte{uint8(OP_OUTPUTID)}
    17  	vm := &virtualMachine{
    18  		runLimit: 50000,
    19  		program:  prog,
    20  		context:  &Context{SpentOutputID: &outputID},
    21  	}
    22  	err := vm.step()
    23  	if err != nil {
    24  		t.Fatal(err)
    25  	}
    26  	gotVM := vm
    27  
    28  	expectedStack := [][]byte{outputID}
    29  	if !testutil.DeepEqual(gotVM.dataStack, expectedStack) {
    30  		t.Errorf("expected stack %v, got %v; vm is:\n%s", expectedStack, gotVM.dataStack, spew.Sdump(vm))
    31  	}
    32  
    33  	prog = []byte{uint8(OP_OUTPUTID)}
    34  	vm = &virtualMachine{
    35  		runLimit: 50000,
    36  		program:  prog,
    37  		context:  &Context{SpentOutputID: nil},
    38  	}
    39  	err = vm.step()
    40  	if err != ErrContext {
    41  		t.Errorf("expected ErrContext, got %v", err)
    42  	}
    43  }
    44  
    45  func TestBlockHeight(t *testing.T) {
    46  	var blockHeight uint64 = 6666
    47  
    48  	prog, err := Assemble("BLOCKHEIGHT 6666 NUMEQUAL")
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	vm := &virtualMachine{
    53  		runLimit: 50000,
    54  		program:  prog,
    55  		context:  &Context{BlockHeight: &blockHeight},
    56  	}
    57  	err = vm.run()
    58  	if err != nil {
    59  		t.Errorf("got error %s, expected none", err)
    60  	}
    61  	if vm.falseResult() {
    62  		t.Error("result is false, want success")
    63  	}
    64  
    65  	prog, err = Assemble("BLOCKHEIGHT 7777 NUMEQUAL")
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	vm = &virtualMachine{
    70  		runLimit: 50000,
    71  		program:  prog,
    72  		context:  &Context{BlockHeight: &blockHeight},
    73  	}
    74  	err = vm.run()
    75  	if err == nil && vm.falseResult() {
    76  		err = ErrFalseVMResult
    77  	}
    78  	switch err {
    79  	case nil:
    80  		t.Error("got ok result, expected failure")
    81  	case ErrFalseVMResult:
    82  		// ok
    83  	default:
    84  		t.Errorf("got error %s, expected ErrFalseVMResult", err)
    85  	}
    86  }
    87  
    88  func TestIntrospectionOps(t *testing.T) {
    89  	// arbitrary
    90  	entryID := mustDecodeHex("2e68d78cdeaa98944c12512cf9c719eb4881e9afb61e4b766df5f369aee6392c")
    91  	assetID := mustDecodeHex("0100000000000000000000000000000000000000000000000000000000000000")
    92  
    93  	type testStruct struct {
    94  		op      Op
    95  		startVM *virtualMachine
    96  		wantErr error
    97  		wantVM  *virtualMachine
    98  	}
    99  	cases := []testStruct{{
   100  		op: OP_CHECKOUTPUT,
   101  		startVM: &virtualMachine{
   102  			dataStack: [][]byte{
   103  				{0},
   104  				{1},
   105  				append([]byte{9}, make([]byte, 31)...),
   106  				{1},
   107  				[]byte("missingprog"),
   108  			},
   109  			context: &Context{
   110  				CheckOutput: func(uint64, uint64, []byte, uint64, []byte, bool) (bool, error) {
   111  					return false, nil
   112  				},
   113  			},
   114  		},
   115  		wantVM: &virtualMachine{
   116  			runLimit:     50062,
   117  			deferredCost: -78,
   118  			dataStack:    [][]byte{{}},
   119  		},
   120  	}, {
   121  		op: OP_CHECKOUTPUT,
   122  		startVM: &virtualMachine{
   123  			dataStack: [][]byte{
   124  				{4},
   125  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   126  				{7},
   127  				append([]byte{2}, make([]byte, 31)...),
   128  				Int64Bytes(-1),
   129  				[]byte("controlprog"),
   130  			},
   131  			context: &Context{},
   132  		},
   133  		wantErr: ErrBadValue,
   134  	}, {
   135  		op: OP_CHECKOUTPUT,
   136  		startVM: &virtualMachine{
   137  			dataStack: [][]byte{
   138  				{4},
   139  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   140  				Int64Bytes(-1),
   141  				append([]byte{2}, make([]byte, 31)...),
   142  				{1},
   143  				[]byte("controlprog"),
   144  			},
   145  			context: &Context{},
   146  		},
   147  		wantErr: ErrBadValue,
   148  	}, {
   149  		op: OP_CHECKOUTPUT,
   150  		startVM: &virtualMachine{
   151  			dataStack: [][]byte{
   152  				Int64Bytes(-1),
   153  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   154  				{7},
   155  				append([]byte{2}, make([]byte, 31)...),
   156  				{1},
   157  				[]byte("controlprog"),
   158  			},
   159  			context: &Context{},
   160  		},
   161  		wantErr: ErrBadValue,
   162  	}, {
   163  		op: OP_CHECKOUTPUT,
   164  		startVM: &virtualMachine{
   165  			dataStack: [][]byte{
   166  				{5},
   167  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   168  				{7},
   169  				append([]byte{2}, make([]byte, 31)...),
   170  				{1},
   171  				[]byte("controlprog"),
   172  			},
   173  			context: &Context{
   174  				CheckOutput: func(uint64, uint64, []byte, uint64, []byte, bool) (bool, error) {
   175  					return false, ErrBadValue
   176  				},
   177  			},
   178  		},
   179  		wantErr: ErrBadValue,
   180  	}, {
   181  		op: OP_CHECKOUTPUT,
   182  		startVM: &virtualMachine{
   183  			runLimit: 0,
   184  			dataStack: [][]byte{
   185  				{4},
   186  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   187  				{7},
   188  				append([]byte{2}, make([]byte, 31)...),
   189  				{1},
   190  				[]byte("controlprog"),
   191  			},
   192  			context: &Context{},
   193  		},
   194  		wantErr: ErrRunLimitExceeded,
   195  	}, {
   196  		op: OP_ASSET,
   197  		startVM: &virtualMachine{
   198  			context: &Context{AssetID: &assetID},
   199  		},
   200  		wantVM: &virtualMachine{
   201  			runLimit:     49959,
   202  			deferredCost: 40,
   203  			dataStack:    [][]byte{assetID},
   204  		},
   205  	}, {
   206  		op: OP_AMOUNT,
   207  		startVM: &virtualMachine{
   208  			context: &Context{Amount: uint64ptr(5)},
   209  		},
   210  		wantVM: &virtualMachine{
   211  			runLimit:     49990,
   212  			deferredCost: 9,
   213  			dataStack:    [][]byte{{5}},
   214  		},
   215  	}, {
   216  		op: OP_PROGRAM,
   217  		startVM: &virtualMachine{
   218  			program: []byte("spendprog"),
   219  			context: &Context{Code: []byte("spendprog")},
   220  		},
   221  		wantVM: &virtualMachine{
   222  			runLimit:     49982,
   223  			deferredCost: 17,
   224  			dataStack:    [][]byte{[]byte("spendprog")},
   225  		},
   226  	}, {
   227  		op: OP_PROGRAM,
   228  		startVM: &virtualMachine{
   229  			program:  []byte("issueprog"),
   230  			runLimit: 50000,
   231  			context:  &Context{Code: []byte("issueprog")},
   232  		},
   233  		wantVM: &virtualMachine{
   234  			runLimit:     49982,
   235  			deferredCost: 17,
   236  			dataStack:    [][]byte{[]byte("issueprog")},
   237  		},
   238  	}, {
   239  		op: OP_INDEX,
   240  		startVM: &virtualMachine{
   241  			context: &Context{DestPos: new(uint64)},
   242  		},
   243  		wantVM: &virtualMachine{
   244  			runLimit:     49991,
   245  			deferredCost: 8,
   246  			dataStack:    [][]byte{[]byte{}},
   247  		},
   248  	}, {
   249  		op: OP_ENTRYID,
   250  		startVM: &virtualMachine{
   251  			context: &Context{EntryID: entryID},
   252  		},
   253  		wantVM: &virtualMachine{
   254  			runLimit:     49959,
   255  			deferredCost: 40,
   256  			dataStack:    [][]byte{entryID},
   257  		},
   258  	}}
   259  
   260  	txops := []Op{
   261  		OP_CHECKOUTPUT, OP_ASSET, OP_AMOUNT, OP_PROGRAM,
   262  		OP_INDEX, OP_OUTPUTID,
   263  	}
   264  
   265  	for _, op := range txops {
   266  		cases = append(cases, testStruct{
   267  			op: op,
   268  			startVM: &virtualMachine{
   269  				runLimit: 0,
   270  				context:  &Context{},
   271  			},
   272  			wantErr: ErrRunLimitExceeded,
   273  		})
   274  	}
   275  
   276  	for i, c := range cases {
   277  		t.Logf("case %d", i)
   278  		prog := []byte{byte(c.op)}
   279  		vm := c.startVM
   280  		if c.wantErr != ErrRunLimitExceeded {
   281  			vm.runLimit = 50000
   282  		}
   283  		vm.program = prog
   284  		err := vm.run()
   285  		switch errors.Root(err) {
   286  		case c.wantErr:
   287  			// ok
   288  		case nil:
   289  			t.Errorf("case %d, op %s: got no error, want %v", i, ops[c.op].name, c.wantErr)
   290  		default:
   291  			t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
   292  		}
   293  		if c.wantErr != nil {
   294  			continue
   295  		}
   296  		gotVM := vm
   297  
   298  		c.wantVM.program = prog
   299  		c.wantVM.pc = 1
   300  		c.wantVM.nextPC = 1
   301  		c.wantVM.context = gotVM.context
   302  
   303  		if !testutil.DeepEqual(gotVM, c.wantVM) {
   304  			t.Errorf("case %d, op %s: unexpected vm result\n\tgot:  %+v\n\twant: %+v\nstartVM is:\n%s", i, ops[c.op].name, gotVM, c.wantVM, spew.Sdump(c.startVM))
   305  		}
   306  	}
   307  }
   308  
   309  func uint64ptr(n uint64) *uint64 { return &n }