OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / vendor / github.com / bytom / protocol / vm / stack_test.go
diff --git a/vendor/github.com/bytom/protocol/vm/stack_test.go b/vendor/github.com/bytom/protocol/vm/stack_test.go
new file mode 100644 (file)
index 0000000..559c00d
--- /dev/null
@@ -0,0 +1,423 @@
+package vm
+
+import (
+       "fmt"
+       "reflect"
+       "runtime"
+       "strings"
+       "testing"
+
+       "github.com/bytom/testutil"
+)
+
+func TestStackOps(t *testing.T) {
+       type testStruct struct {
+               op      Op
+               startVM *virtualMachine
+               wantErr error
+               wantVM  *virtualMachine
+       }
+
+       cases := []testStruct{{
+               op: OP_TOALTSTACK,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49998,
+                       dataStack: [][]byte{},
+                       altStack:  [][]byte{{1}},
+               },
+       }, {
+               op: OP_FROMALTSTACK,
+               startVM: &virtualMachine{
+                       runLimit: 50000,
+                       altStack: [][]byte{{1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49998,
+                       altStack:  [][]byte{},
+                       dataStack: [][]byte{{1}},
+               },
+       }, {
+               op: OP_FROMALTSTACK,
+               startVM: &virtualMachine{
+                       runLimit: 50000,
+                       altStack: [][]byte{},
+               },
+               wantErr: ErrAltStackUnderflow,
+       }, {
+               op: OP_2DROP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{1}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  50016,
+                       dataStack: [][]byte{},
+               },
+       }, {
+               op: OP_2DUP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49980,
+                       dataStack: [][]byte{{2}, {1}, {2}, {1}},
+               },
+       }, {
+               op: OP_3DUP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{3}, {2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49970,
+                       dataStack: [][]byte{{3}, {2}, {1}, {3}, {2}, {1}},
+               },
+       }, {
+               op: OP_2OVER,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{4}, {3}, {2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49980,
+                       dataStack: [][]byte{{4}, {3}, {2}, {1}, {4}, {3}},
+               },
+       }, {
+               op: OP_2OVER,
+               startVM: &virtualMachine{
+                       runLimit:  2,
+                       dataStack: [][]byte{{4}, {3}, {2}, {1}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }, {
+               op: OP_2ROT,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{6}, {5}, {4}, {3}, {2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49998,
+                       dataStack: [][]byte{{4}, {3}, {2}, {1}, {6}, {5}},
+               },
+       }, {
+               op: OP_2SWAP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{4}, {3}, {2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49998,
+                       dataStack: [][]byte{{2}, {1}, {4}, {3}},
+               },
+       }, {
+               op: OP_IFDUP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49990,
+                       dataStack: [][]byte{{1}, {1}},
+               },
+       }, {
+               op: OP_IFDUP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49999,
+                       dataStack: [][]byte{{}},
+               },
+       }, {
+               op: OP_IFDUP,
+               startVM: &virtualMachine{
+                       runLimit:  1,
+                       dataStack: [][]byte{{1}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }, {
+               op: OP_DEPTH,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49990,
+                       dataStack: [][]byte{{1}, {1}},
+               },
+       }, {
+               op: OP_DEPTH,
+               startVM: &virtualMachine{
+                       runLimit:  1,
+                       dataStack: [][]byte{{1}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }, {
+               op: OP_DROP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  50008,
+                       dataStack: [][]byte{},
+               },
+       }, {
+               op: OP_DUP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49990,
+                       dataStack: [][]byte{{1}, {1}},
+               },
+       }, {
+               op: OP_DUP,
+               startVM: &virtualMachine{
+                       runLimit:  1,
+                       dataStack: [][]byte{{1}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }, {
+               op: OP_NIP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  50008,
+                       dataStack: [][]byte{{1}},
+               },
+       }, {
+               op: OP_OVER,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49990,
+                       dataStack: [][]byte{{2}, {1}, {2}},
+               },
+       }, {
+               op: OP_OVER,
+               startVM: &virtualMachine{
+                       runLimit:  1,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }, {
+               op: OP_PICK,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{3}, {2}, {1}, {2}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49998,
+                       dataStack: [][]byte{{3}, {2}, {1}, {3}},
+               },
+       }, {
+               op: OP_PICK,
+               startVM: &virtualMachine{
+                       runLimit:  2,
+                       dataStack: [][]byte{{0xff, 0xff}, {2}, {1}, {2}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }, {
+               op: OP_ROLL,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{3}, {2}, {1}, {2}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  50007,
+                       dataStack: [][]byte{{2}, {1}, {3}},
+               },
+       }, {
+               op: OP_ROT,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{3}, {2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49998,
+                       dataStack: [][]byte{{2}, {1}, {3}},
+               },
+       }, {
+               op: OP_SWAP,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49999,
+                       dataStack: [][]byte{{1}, {2}},
+               },
+       }, {
+               op: OP_TUCK,
+               startVM: &virtualMachine{
+                       runLimit:  50000,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantVM: &virtualMachine{
+                       runLimit:  49990,
+                       dataStack: [][]byte{{1}, {2}, {1}},
+               },
+       }, {
+               op: OP_TUCK,
+               startVM: &virtualMachine{
+                       runLimit:  1,
+                       dataStack: [][]byte{{2}, {1}},
+               },
+               wantErr: ErrRunLimitExceeded,
+       }}
+       stackops := []Op{
+               OP_DEPTH, OP_FROMALTSTACK, OP_TOALTSTACK, OP_2DROP, OP_2DUP, OP_3DUP,
+               OP_2OVER, OP_2ROT, OP_2SWAP, OP_IFDUP, OP_DROP, OP_DUP, OP_NIP,
+               OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK,
+       }
+       for _, op := range stackops {
+               cases = append(cases, testStruct{
+                       op:      op,
+                       startVM: &virtualMachine{runLimit: 0},
+                       wantErr: ErrRunLimitExceeded,
+               })
+       }
+
+       for i, c := range cases {
+               err := ops[c.op].fn(c.startVM)
+
+               if err != c.wantErr {
+                       t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
+                       continue
+               }
+               if c.wantErr != nil {
+                       continue
+               }
+
+               if !testutil.DeepEqual(c.startVM, c.wantVM) {
+                       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)
+               }
+       }
+}
+
+func TestStackUnderflow(t *testing.T) {
+       cases := []struct {
+               narg int // number of stack items required
+               op   func(*virtualMachine) error
+       }{
+               // bitwise
+               {1, opInvert},
+               {2, opAnd},
+               {2, opOr},
+               {2, opXor},
+               {2, opEqual},
+               {2, opEqualVerify},
+
+               // control
+               {1, opVerify},
+               {3, opCheckPredicate},
+               {1, opJumpIf},
+
+               // crypto
+               {1, opSha256},
+               {1, opSha3},
+               {3, opCheckSig},
+               {3, opCheckMultiSig}, // special, see also TestCryptoOps
+
+               // introspection
+               {5, opCheckOutput},
+
+               // numeric
+               {1, op1Add},
+               {1, op1Sub},
+               {1, op2Mul},
+               {1, op2Div},
+               {1, opNegate},
+               {1, opAbs},
+               {1, opNot},
+               {1, op0NotEqual},
+               {2, opAdd},
+               {2, opSub},
+               {2, opMul},
+               {2, opDiv},
+               {2, opMod},
+               {2, opLshift},
+               {2, opRshift},
+               {2, opBoolAnd},
+               {2, opBoolOr},
+               {2, opNumEqual},
+               {2, opNumEqualVerify},
+               {2, opNumNotEqual},
+               {2, opLessThan},
+               {2, opGreaterThan},
+               {2, opLessThanOrEqual},
+               {2, opGreaterThanOrEqual},
+               {2, opMin},
+               {2, opMax},
+               {3, opWithin},
+
+               // splice
+               {2, opCat},
+               {3, opSubstr},
+               {2, opLeft},
+               {2, opRight},
+               {1, opSize},
+               {2, opCatpushdata},
+
+               // stack
+               {1, opToAltStack},
+               {2, op2Drop},
+               {2, op2Dup},
+               {3, op3Dup},
+               {4, op2Over},
+               {6, op2Rot},
+               {4, op2Swap},
+               {1, opIfDup},
+               {1, opDrop},
+               {1, opDup},
+               {2, opNip},
+               {2, opOver},
+               {2, opPick}, // TODO(kr): special; check data-dependent # of pops
+               {2, opRoll}, // TODO(kr): special; check data-dependent # of pops
+               {3, opRot},
+               {2, opSwap},
+               {2, opTuck},
+       }
+
+       for _, test := range cases {
+               t.Run(funcName(test.op), func(t *testing.T) {
+
+                       for i := 0; i < test.narg; i++ {
+                               t.Run(fmt.Sprintf("%d args", i), func(t *testing.T) {
+
+                                       vm := &virtualMachine{
+                                               runLimit:  50000,
+                                               dataStack: make([][]byte, i),
+                                       }
+                                       err := test.op(vm)
+                                       if err != ErrDataStackUnderflow {
+                                               t.Errorf("err = %v, want ErrStackUnderflow", err)
+                                       }
+
+                               })
+                       }
+
+               })
+       }
+}
+
+func funcName(f interface{}) string {
+       v := reflect.ValueOf(f)
+       if v.Kind() != reflect.Func {
+               return ""
+       }
+       s := runtime.FuncForPC(v.Pointer()).Name()
+       return s[strings.LastIndex(s, ".")+1:]
+}