diff --git a/core/vm/gas.go b/core/vm/gas.go
index c4d5e4c4e39565854e1ed178f44571ad2a1e45a9..e64810cd5ff06389fb8bde495c4871aa38042eb4 100644
--- a/core/vm/gas.go
+++ b/core/vm/gas.go
@@ -1,11 +1,9 @@
 package vm
 
-import "math/big"
-
-type req struct {
-	stack int
-	gas   *big.Int
-}
+import (
+	"fmt"
+	"math/big"
+)
 
 var (
 	GasQuickStep   = big.NewInt(2)
@@ -56,75 +54,30 @@ var (
 	GasCopyWord     = big.NewInt(3)
 )
 
-var _baseCheck = map[OpCode]req{
-	//       Req stack  Gas price
-	ADD:          {2, GasFastestStep},
-	LT:           {2, GasFastestStep},
-	GT:           {2, GasFastestStep},
-	SLT:          {2, GasFastestStep},
-	SGT:          {2, GasFastestStep},
-	EQ:           {2, GasFastestStep},
-	ISZERO:       {1, GasFastestStep},
-	SUB:          {2, GasFastestStep},
-	AND:          {2, GasFastestStep},
-	OR:           {2, GasFastestStep},
-	XOR:          {2, GasFastestStep},
-	NOT:          {1, GasFastestStep},
-	BYTE:         {2, GasFastestStep},
-	CALLDATALOAD: {1, GasFastestStep},
-	CALLDATACOPY: {3, GasFastestStep},
-	MLOAD:        {1, GasFastestStep},
-	MSTORE:       {2, GasFastestStep},
-	MSTORE8:      {2, GasFastestStep},
-	CODECOPY:     {3, GasFastestStep},
-	MUL:          {2, GasFastStep},
-	DIV:          {2, GasFastStep},
-	SDIV:         {2, GasFastStep},
-	MOD:          {2, GasFastStep},
-	SMOD:         {2, GasFastStep},
-	SIGNEXTEND:   {2, GasFastStep},
-	ADDMOD:       {3, GasMidStep},
-	MULMOD:       {3, GasMidStep},
-	JUMP:         {1, GasMidStep},
-	JUMPI:        {2, GasSlowStep},
-	EXP:          {2, GasSlowStep},
-	ADDRESS:      {0, GasQuickStep},
-	ORIGIN:       {0, GasQuickStep},
-	CALLER:       {0, GasQuickStep},
-	CALLVALUE:    {0, GasQuickStep},
-	CODESIZE:     {0, GasQuickStep},
-	GASPRICE:     {0, GasQuickStep},
-	COINBASE:     {0, GasQuickStep},
-	TIMESTAMP:    {0, GasQuickStep},
-	NUMBER:       {0, GasQuickStep},
-	CALLDATASIZE: {0, GasQuickStep},
-	DIFFICULTY:   {0, GasQuickStep},
-	GASLIMIT:     {0, GasQuickStep},
-	POP:          {0, GasQuickStep},
-	PC:           {0, GasQuickStep},
-	MSIZE:        {0, GasQuickStep},
-	GAS:          {0, GasQuickStep},
-	BLOCKHASH:    {1, GasExtStep},
-	BALANCE:      {0, GasExtStep},
-	EXTCODESIZE:  {1, GasExtStep},
-	EXTCODECOPY:  {4, GasExtStep},
-	SLOAD:        {1, GasStorageGet},
-	SSTORE:       {2, Zero},
-	SHA3:         {1, GasSha3Base},
-	CREATE:       {3, GasCreate},
-	CALL:         {7, GasCall},
-	CALLCODE:     {7, GasCall},
-	JUMPDEST:     {0, GasJumpDest},
-	SUICIDE:      {1, Zero},
-	RETURN:       {2, Zero},
-}
+func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
+	// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
+	// PUSH is also allowed to calculate the same price for all PUSHes
+	// DUP requirements are handled elsewhere (except for the stack limit check)
+	if op >= PUSH1 && op <= PUSH32 {
+		op = PUSH1
+	}
+	if op >= SWAP1 && op <= SWAP16 {
+		op = SWAP1
+	}
 
-func baseCheck(op OpCode, stack *stack, gas *big.Int) {
 	if r, ok := _baseCheck[op]; ok {
-		stack.require(r.stack)
+		err := stack.require(r.stackPop)
+		if err != nil {
+			return err
+		}
+
+		if r.stackPush && len(stack.data)-r.stackPop == 1024 {
+			return fmt.Errorf("stack limit reached (%d)", maxStack)
+		}
 
 		gas.Add(gas, r.gas)
 	}
+	return nil
 }
 
 func toWordSize(size *big.Int) *big.Int {
@@ -133,3 +86,74 @@ func toWordSize(size *big.Int) *big.Int {
 	tmp.Div(tmp, u256(32))
 	return tmp
 }
+
+type req struct {
+	stackPop  int
+	gas       *big.Int
+	stackPush bool
+}
+
+var _baseCheck = map[OpCode]req{
+	// opcode  |  stack pop | gas price | stack push
+	ADD:          {2, GasFastestStep, true},
+	LT:           {2, GasFastestStep, true},
+	GT:           {2, GasFastestStep, true},
+	SLT:          {2, GasFastestStep, true},
+	SGT:          {2, GasFastestStep, true},
+	EQ:           {2, GasFastestStep, true},
+	ISZERO:       {1, GasFastestStep, true},
+	SUB:          {2, GasFastestStep, true},
+	AND:          {2, GasFastestStep, true},
+	OR:           {2, GasFastestStep, true},
+	XOR:          {2, GasFastestStep, true},
+	NOT:          {1, GasFastestStep, true},
+	BYTE:         {2, GasFastestStep, true},
+	CALLDATALOAD: {1, GasFastestStep, true},
+	CALLDATACOPY: {3, GasFastestStep, true},
+	MLOAD:        {1, GasFastestStep, true},
+	MSTORE:       {2, GasFastestStep, false},
+	MSTORE8:      {2, GasFastestStep, false},
+	CODECOPY:     {3, GasFastestStep, false},
+	MUL:          {2, GasFastStep, true},
+	DIV:          {2, GasFastStep, true},
+	SDIV:         {2, GasFastStep, true},
+	MOD:          {2, GasFastStep, true},
+	SMOD:         {2, GasFastStep, true},
+	SIGNEXTEND:   {2, GasFastStep, true},
+	ADDMOD:       {3, GasMidStep, true},
+	MULMOD:       {3, GasMidStep, true},
+	JUMP:         {1, GasMidStep, false},
+	JUMPI:        {2, GasSlowStep, false},
+	EXP:          {2, GasSlowStep, true},
+	ADDRESS:      {0, GasQuickStep, true},
+	ORIGIN:       {0, GasQuickStep, true},
+	CALLER:       {0, GasQuickStep, true},
+	CALLVALUE:    {0, GasQuickStep, true},
+	CODESIZE:     {0, GasQuickStep, true},
+	GASPRICE:     {0, GasQuickStep, true},
+	COINBASE:     {0, GasQuickStep, true},
+	TIMESTAMP:    {0, GasQuickStep, true},
+	NUMBER:       {0, GasQuickStep, true},
+	CALLDATASIZE: {0, GasQuickStep, true},
+	DIFFICULTY:   {0, GasQuickStep, true},
+	GASLIMIT:     {0, GasQuickStep, true},
+	POP:          {1, GasQuickStep, false},
+	PC:           {0, GasQuickStep, true},
+	MSIZE:        {0, GasQuickStep, true},
+	GAS:          {0, GasQuickStep, true},
+	BLOCKHASH:    {1, GasExtStep, true},
+	BALANCE:      {0, GasExtStep, true},
+	EXTCODESIZE:  {1, GasExtStep, true},
+	EXTCODECOPY:  {4, GasExtStep, false},
+	SLOAD:        {1, GasStorageGet, true},
+	SSTORE:       {2, Zero, false},
+	SHA3:         {1, GasSha3Base, true},
+	CREATE:       {3, GasCreate, true},
+	CALL:         {7, GasCall, true},
+	CALLCODE:     {7, GasCall, true},
+	JUMPDEST:     {0, GasJumpDest, false},
+	SUICIDE:      {1, Zero, false},
+	RETURN:       {2, Zero, false},
+	PUSH1:        {0, GasFastStep, true},
+	DUP1:         {0, Zero, true},
+}
diff --git a/core/vm/memory.go b/core/vm/memory.go
index f5984d82f1f7e4f03e29bcc9015b1267c0ef4e26..a80a6aae088551f3ac72b7ea567f27d88b853822 100644
--- a/core/vm/memory.go
+++ b/core/vm/memory.go
@@ -15,28 +15,32 @@ func NewMemory() *Memory {
 }
 
 func (m *Memory) Set(offset, size uint64, value []byte) {
-	// If the length of the store is 0 this is a complete failure
-	// memory size is set prior to calling this method so enough size
-	// should always be available.
-	if len(m.store) == 0 {
+	// length of store may never be less than offset + size.
+	// The store should be resized PRIOR to setting the memory
+	if size > uint64(len(m.store)) {
 		panic("INVALID memory: store empty")
 	}
 
-	value = common.RightPadBytes(value, int(size))
+	// It's possible the offset is greater than 0 and size equals 0. This is because
+	// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
+	if size > 0 {
+		copy(m.store[offset:offset+size], common.RightPadBytes(value, int(size)))
+	}
 
-	totSize := offset + size
-	lenSize := int64(len(m.store) - 1)
-	if totSize > lenSize {
-		// Calculate the diff between the sizes
-		diff := totSize - lenSize
-		if diff > 0 {
-			// Create a new empty slice and append it
-			newSlice := make([]byte, diff-1)
-			// Resize slice
-			m.store = append(m.store, newSlice...)
+	/*
+		totSize := offset + size
+		lenSize := uint64(len(m.store) - 1)
+		if totSize > lenSize {
+			// Calculate the diff between the sizes
+			diff := totSize - lenSize
+			if diff > 0 {
+				// Create a new empty slice and append it
+				newSlice := make([]byte, diff-1)
+				// Resize slice
+				m.store = append(m.store, newSlice...)
+			}
 		}
-	}
-	copy(m.store[offset:offset+size], value)
+	*/
 }
 
 func (m *Memory) Resize(size uint64) {
diff --git a/core/vm/stack.go b/core/vm/stack.go
index 1e093476bf692337974066e60e5b4f970f0a0daf..168637708255d76f61777df2edec0ef76973b42d 100644
--- a/core/vm/stack.go
+++ b/core/vm/stack.go
@@ -17,10 +17,7 @@ type stack struct {
 }
 
 func (st *stack) push(d *big.Int) {
-	if len(st.data) == maxStack {
-		panic(fmt.Sprintf("stack limit reached (%d)", maxStack))
-	}
-
+	// NOTE push limit (1024) is checked in baseCheck
 	stackItem := new(big.Int).Set(d)
 	if len(st.data) > st.ptr {
 		st.data[st.ptr] = stackItem
@@ -52,10 +49,11 @@ func (st *stack) peek() *big.Int {
 	return st.data[st.len()-1]
 }
 
-func (st *stack) require(n int) {
+func (st *stack) require(n int) error {
 	if st.len() < n {
-		panic(fmt.Sprintf("stack underflow (%d <=> %d)", len(st.data), n))
+		return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
 	}
+	return nil
 }
 
 func (st *stack) Print() {
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 562689dca1bbf55a161c02acf1a555b8aa18e64e..0618446c278bd030e11b8c88e0130b52ef21053d 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -45,20 +45,32 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 
 	self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl()
 
-	if self.Recoverable {
-		// Recover from any require exception
-		defer func() {
-			if r := recover(); r != nil {
-				self.Printf(" %v", r).Endl()
+	/*
+		if self.Recoverable {
+			// Recover from any require exception
+			defer func() {
+				if r := recover(); r != nil {
+					self.Printf(" %v", r).Endl()
 
-				context.UseGas(context.Gas)
+					context.UseGas(context.Gas)
 
-				ret = context.Return(nil)
+					ret = context.Return(nil)
 
-				err = fmt.Errorf("%v", r)
-			}
-		}()
-	}
+					err = fmt.Errorf("%v", r)
+				}
+			}()
+		}
+	*/
+
+	defer func() {
+		if err != nil {
+			self.Printf(" %v", err).Endl()
+			// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
+			context.UseGas(context.Gas)
+
+			ret = context.Return(nil)
+		}
+	}()
 
 	if context.CodeAddr != nil {
 		if p := Precompiled[context.CodeAddr.Str()]; p != nil {
@@ -76,18 +88,20 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 		step                = 0
 		statedb             = self.env.State()
 
-		jump = func(from uint64, to *big.Int) {
+		jump = func(from uint64, to *big.Int) error {
 			p := to.Uint64()
 
 			nop := context.GetOp(p)
 			if !destinations.Has(p) {
-				panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p))
+				return fmt.Errorf("invalid jump destination (%v) %v", nop, p)
 			}
 
 			self.Printf(" ~> %v", to)
 			pc = to.Uint64()
 
 			self.Endl()
+
+			return nil
 		}
 	)
 
@@ -105,7 +119,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 		op = context.GetOp(pc)
 
 		self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
-		newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
+		newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
+		if err != nil {
+			return nil, err
+		}
 
 		self.Printf("(g) %-3v (%v)", gas, context.Gas)
 
@@ -600,14 +617,18 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 
 			self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
 		case JUMP:
-			jump(pc, stack.pop())
+			if err := jump(pc, stack.pop()); err != nil {
+				return nil, err
+			}
 
 			continue
 		case JUMPI:
 			pos, cond := stack.pop(), stack.pop()
 
 			if cond.Cmp(common.BigTrue) >= 0 {
-				jump(pc, pos)
+				if err := jump(pc, pos); err != nil {
+					return nil, err
+				}
 
 				continue
 			}
@@ -720,7 +741,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 		default:
 			self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
 
-			panic(fmt.Errorf("Invalid opcode %x", op))
+			return nil, fmt.Errorf("Invalid opcode %x", op)
 		}
 
 		pc++
@@ -729,28 +750,38 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
 	}
 }
 
-func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int) {
+func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
 	var (
 		gas                 = new(big.Int)
 		newMemSize *big.Int = new(big.Int)
 	)
-	baseCheck(op, stack, gas)
+	err := baseCheck(op, stack, gas)
+	if err != nil {
+		return nil, nil, err
+	}
 
 	// stack Check, memory resize & gas phase
 	switch op {
-	case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
-		gas.Set(GasFastestStep)
 	case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
 		n := int(op - SWAP1 + 2)
-		stack.require(n)
+		err := stack.require(n)
+		if err != nil {
+			return nil, nil, err
+		}
 		gas.Set(GasFastestStep)
 	case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
 		n := int(op - DUP1 + 1)
-		stack.require(n)
+		err := stack.require(n)
+		if err != nil {
+			return nil, nil, err
+		}
 		gas.Set(GasFastestStep)
 	case LOG0, LOG1, LOG2, LOG3, LOG4:
 		n := int(op - LOG0)
-		stack.require(n + 2)
+		err := stack.require(n + 2)
+		if err != nil {
+			return nil, nil, err
+		}
 
 		mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
 
@@ -762,7 +793,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
 	case EXP:
 		gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
 	case SSTORE:
-		stack.require(2)
+		err := stack.require(2)
+		if err != nil {
+			return nil, nil, err
+		}
 
 		var g *big.Int
 		y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
@@ -853,7 +887,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
 		}
 	}
 
-	return newMemSize, gas
+	return newMemSize, gas, nil
 }
 
 func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
@@ -869,7 +903,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
 
 		tmp := new(big.Int).Set(context.Gas)
 
-		panic(OOG(gas, tmp).Error())
+		return nil, OOG(gas, tmp)
 	}
 }