github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/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  			altStack: [][]byte{[]byte("statedata")},
   110  			context: &Context{
   111  				CheckOutput: func(uint64, uint64, []byte, uint64, []byte, [][]byte, bool) (bool, error) {
   112  					return false, nil
   113  				},
   114  			},
   115  		},
   116  		wantVM: &virtualMachine{
   117  			runLimit:     50062,
   118  			deferredCost: -78,
   119  			dataStack:    [][]byte{{}},
   120  			altStack:     [][]byte{[]byte("statedata")},
   121  		},
   122  	}, {
   123  		op: OP_CHECKOUTPUT,
   124  		startVM: &virtualMachine{
   125  			dataStack: [][]byte{
   126  				{5},
   127  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   128  				{7},
   129  				append([]byte{2}, make([]byte, 31)...),
   130  				{1},
   131  				[]byte("controlprog"),
   132  			},
   133  			altStack: [][]byte{[]byte("statedata")},
   134  			context: &Context{
   135  				CheckOutput: func(uint64, uint64, []byte, uint64, []byte, [][]byte, bool) (bool, error) {
   136  					return false, ErrBadValue
   137  				},
   138  			},
   139  		},
   140  		wantErr: ErrBadValue,
   141  	}, {
   142  		op: OP_CHECKOUTPUT,
   143  		startVM: &virtualMachine{
   144  			runLimit: 0,
   145  			dataStack: [][]byte{
   146  				{4},
   147  				mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
   148  				{7},
   149  				append([]byte{2}, make([]byte, 31)...),
   150  				{1},
   151  				[]byte("controlprog"),
   152  			},
   153  			altStack: [][]byte{[]byte("statedata")},
   154  			context:  &Context{},
   155  		},
   156  		wantErr: ErrRunLimitExceeded,
   157  	}, {
   158  		op: OP_ASSET,
   159  		startVM: &virtualMachine{
   160  			context: &Context{AssetID: &assetID},
   161  		},
   162  		wantVM: &virtualMachine{
   163  			runLimit:     49959,
   164  			deferredCost: 40,
   165  			dataStack:    [][]byte{assetID},
   166  		},
   167  	}, {
   168  		op: OP_AMOUNT,
   169  		startVM: &virtualMachine{
   170  			context: &Context{Amount: uint64ptr(5)},
   171  		},
   172  		wantVM: &virtualMachine{
   173  			runLimit:     49990,
   174  			deferredCost: 9,
   175  			dataStack:    [][]byte{{5}},
   176  		},
   177  	}, {
   178  		op: OP_PROGRAM,
   179  		startVM: &virtualMachine{
   180  			program: []byte("spendprog"),
   181  			context: &Context{Code: []byte("spendprog")},
   182  		},
   183  		wantVM: &virtualMachine{
   184  			runLimit:     49982,
   185  			deferredCost: 17,
   186  			dataStack:    [][]byte{[]byte("spendprog")},
   187  		},
   188  	}, {
   189  		op: OP_PROGRAM,
   190  		startVM: &virtualMachine{
   191  			program:  []byte("issueprog"),
   192  			runLimit: 50000,
   193  			context:  &Context{Code: []byte("issueprog")},
   194  		},
   195  		wantVM: &virtualMachine{
   196  			runLimit:     49982,
   197  			deferredCost: 17,
   198  			dataStack:    [][]byte{[]byte("issueprog")},
   199  		},
   200  	}, {
   201  		op: OP_INDEX,
   202  		startVM: &virtualMachine{
   203  			context: &Context{DestPos: new(uint64)},
   204  		},
   205  		wantVM: &virtualMachine{
   206  			runLimit:     49991,
   207  			deferredCost: 8,
   208  			dataStack:    [][]byte{[]byte{}},
   209  		},
   210  	}, {
   211  		op: OP_ENTRYID,
   212  		startVM: &virtualMachine{
   213  			context: &Context{EntryID: entryID},
   214  		},
   215  		wantVM: &virtualMachine{
   216  			runLimit:     49959,
   217  			deferredCost: 40,
   218  			dataStack:    [][]byte{entryID},
   219  		},
   220  	}}
   221  
   222  	txops := []Op{
   223  		OP_CHECKOUTPUT, OP_ASSET, OP_AMOUNT, OP_PROGRAM,
   224  		OP_INDEX, OP_OUTPUTID,
   225  	}
   226  
   227  	for _, op := range txops {
   228  		cases = append(cases, testStruct{
   229  			op: op,
   230  			startVM: &virtualMachine{
   231  				runLimit: 0,
   232  				context:  &Context{},
   233  			},
   234  			wantErr: ErrRunLimitExceeded,
   235  		})
   236  	}
   237  
   238  	for i, c := range cases {
   239  		t.Logf("case %d", i)
   240  		prog := []byte{byte(c.op)}
   241  		vm := c.startVM
   242  		if c.wantErr != ErrRunLimitExceeded {
   243  			vm.runLimit = 50000
   244  		}
   245  		vm.program = prog
   246  		err := vm.run()
   247  		switch errors.Root(err) {
   248  		case c.wantErr:
   249  			// ok
   250  		case nil:
   251  			t.Errorf("case %d, op %s: got no error, want %v", i, ops[c.op].name, c.wantErr)
   252  		default:
   253  			t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
   254  		}
   255  		if c.wantErr != nil {
   256  			continue
   257  		}
   258  		gotVM := vm
   259  
   260  		c.wantVM.program = prog
   261  		c.wantVM.pc = 1
   262  		c.wantVM.nextPC = 1
   263  		c.wantVM.context = gotVM.context
   264  
   265  		if !testutil.DeepEqual(gotVM, c.wantVM) {
   266  			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))
   267  		}
   268  	}
   269  }
   270  
   271  func uint64ptr(n uint64) *uint64 { return &n }