diff --git a/cmd/evm/main.go b/cmd/evm/main.go
index 9f67e6628645d59de4cf295efff0fc1527ceecb8..8af0cebbb5263eade26e55f1b4cd7f1a8755a988 100644
--- a/cmd/evm/main.go
+++ b/cmd/evm/main.go
@@ -156,7 +156,7 @@ func run(ctx *cli.Context) error {
 		ret, _, err = runtime.Create(input, &runtime.Config{
 			Origin:   sender.Address(),
 			State:    statedb,
-			GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
+			GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
 			GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
 			Value:    common.Big(ctx.GlobalString(ValueFlag.Name)),
 			EVMConfig: vm.Config{
@@ -172,7 +172,7 @@ func run(ctx *cli.Context) error {
 		ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
 			Origin:   sender.Address(),
 			State:    statedb,
-			GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
+			GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
 			GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
 			Value:    common.Big(ctx.GlobalString(ValueFlag.Name)),
 			EVMConfig: vm.Config{
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 1680a32e02a584d6287858255312971d81237f67..c19770bfaab8373b1249f213bd17b61fa3eeff2e 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -205,7 +205,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
 	if err != nil {
 		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
 	}
-	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+	if uint64(len(extra)) > params.MaximumExtraDataSize {
 		glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
 		glog.V(logger.Debug).Infof("extra: %x\n", extra)
 		extra = nil
diff --git a/common/math/integer.go b/common/math/integer.go
new file mode 100644
index 0000000000000000000000000000000000000000..8162b19854dc1f4a370bd10be32175c7c3e2b91a
--- /dev/null
+++ b/common/math/integer.go
@@ -0,0 +1,25 @@
+package math
+
+import gmath "math"
+
+/*
+ * NOTE: The following methods need to be optimised using either bit checking or asm
+ */
+
+// SafeSub returns subtraction result and whether overflow occurred.
+func SafeSub(x, y uint64) (uint64, bool) {
+	return x - y, x < y
+}
+
+// SafeAdd returns the result and whether overflow occurred.
+func SafeAdd(x, y uint64) (uint64, bool) {
+	return x + y, y > gmath.MaxUint64-x
+}
+
+// SafeMul returns multiplication result and whether overflow occurred.
+func SafeMul(x, y uint64) (uint64, bool) {
+	if x == 0 {
+		return 0, false
+	}
+	return x * y, x != 0 && y != 0 && y > gmath.MaxUint64/x
+}
diff --git a/common/math/integer_test.go b/common/math/integer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..198114e5e14b8092dc1ba57ad3e04d903efdd713
--- /dev/null
+++ b/common/math/integer_test.go
@@ -0,0 +1,50 @@
+package math
+
+import (
+	gmath "math"
+	"testing"
+)
+
+type operation byte
+
+const (
+	sub operation = iota
+	add
+	mul
+)
+
+func TestOverflow(t *testing.T) {
+	for i, test := range []struct {
+		x        uint64
+		y        uint64
+		overflow bool
+		op       operation
+	}{
+		// add operations
+		{gmath.MaxUint64, 1, true, add},
+		{gmath.MaxUint64 - 1, 1, false, add},
+
+		// sub operations
+		{0, 1, true, sub},
+		{0, 0, false, sub},
+
+		// mul operations
+		{10, 10, false, mul},
+		{gmath.MaxUint64, 2, true, mul},
+		{gmath.MaxUint64, 1, false, mul},
+	} {
+		var overflows bool
+		switch test.op {
+		case sub:
+			_, overflows = SafeSub(test.x, test.y)
+		case add:
+			_, overflows = SafeAdd(test.x, test.y)
+		case mul:
+			_, overflows = SafeMul(test.x, test.y)
+		}
+
+		if test.overflow != overflows {
+			t.Errorf("%d failed. Expected test to be %v, got %v", i, test.overflow, overflows)
+		}
+	}
+}
diff --git a/core/bench_test.go b/core/bench_test.go
index 353d217fd4932aaba44df636789c49ef97e24d16..59b5ad75896d106e84f0caf2919af9644806e5b5 100644
--- a/core/bench_test.go
+++ b/core/bench_test.go
@@ -92,6 +92,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
 var (
 	ringKeys  = make([]*ecdsa.PrivateKey, 1000)
 	ringAddrs = make([]common.Address, len(ringKeys))
+	bigTxGas  = new(big.Int).SetUint64(params.TxGas)
 )
 
 func init() {
@@ -111,8 +112,8 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
 	return func(i int, gen *BlockGen) {
 		gas := CalcGasLimit(gen.PrevBlock(i - 1))
 		for {
-			gas.Sub(gas, params.TxGas)
-			if gas.Cmp(params.TxGas) < 0 {
+			gas.Sub(gas, bigTxGas)
+			if gas.Cmp(bigTxGas) < 0 {
 				break
 			}
 			to := (from + 1) % naccounts
@@ -120,7 +121,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
 				gen.TxNonce(ringAddrs[from]),
 				ringAddrs[to],
 				benchRootFunds,
-				params.TxGas,
+				bigTxGas,
 				nil,
 				nil,
 			)
diff --git a/core/block_validator.go b/core/block_validator.go
index 65f975345c74c3efc5f17de6cabc35c6691651d9..ee524b61f83e70427d24866d2f5f913fc4f433b4 100644
--- a/core/block_validator.go
+++ b/core/block_validator.go
@@ -204,7 +204,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
 //
 // See YP section 4.3.4. "Block Header Validity"
 func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
-	if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
+	if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
 		return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
 	}
 
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 16bea9d7c0eea68669270ba1e13f8780ad42ac67..99b155620b991423d7758f1a48dcd1bc07c81cbd 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -720,7 +720,7 @@ func TestFastVsFullChains(t *testing.T) {
 		// If the block number is multiple of 3, send a few bonus transactions to the miner
 		if i%3 == 2 {
 			for j := 0; j < i%4+1; j++ {
-				tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
+				tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), bigTxGas, nil, nil), signer, key)
 				if err != nil {
 					panic(err)
 				}
@@ -884,8 +884,8 @@ func TestChainTxReorgs(t *testing.T) {
 	// Create two transactions shared between the chains:
 	//  - postponed: transaction included at a later block in the forked chain
 	//  - swapped: transaction included at the same block number in the forked chain
-	postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
-	swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
+	postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
+	swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
 
 	// Create two transactions that will be dropped by the forked chain:
 	//  - pastDrop: transaction dropped retroactively from a past block
@@ -901,13 +901,13 @@ func TestChainTxReorgs(t *testing.T) {
 	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
-			pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
+			pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
 
 			gen.AddTx(pastDrop)  // This transaction will be dropped in the fork from below the split point
 			gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
 
 		case 2:
-			freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
+			freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
 
 			gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
 			gen.AddTx(swapped)   // This transaction will be swapped out at the exact height
@@ -926,18 +926,18 @@ func TestChainTxReorgs(t *testing.T) {
 	chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
-			pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
+			pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
 			gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
 
 		case 2:
 			gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
 			gen.AddTx(swapped)   // This transaction was swapped from the exact current spot in the original chain
 
-			freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
+			freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
 			gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
 
 		case 3:
-			futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
+			futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
 			gen.AddTx(futureAdd) // This transaction will be added after a full reorg
 		}
 	})
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index 2796817c01c67c4771b3f47647eaba2f9efabdf1..5c563de4690a4856d31e47062fa0bea84b2418d8 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -56,13 +56,13 @@ func ExampleGenerateChain() {
 		switch i {
 		case 0:
 			// In block 1, addr1 sends addr2 some ether.
-			tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
+			tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), bigTxGas, nil, nil), signer, key1)
 			gen.AddTx(tx)
 		case 1:
 			// In block 2, addr1 sends some more ether to addr2.
 			// addr2 passes it on to addr3.
-			tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
-			tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
+			tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)
+			tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
 			gen.AddTx(tx1)
 			gen.AddTx(tx2)
 		case 2:
diff --git a/core/state_transition.go b/core/state_transition.go
index 3cb7e500c5cfd692beca093a7e33e8f0752cf3ef..98dc8d9958ec2178b4d19d61ba857ee533a6625e 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -49,15 +49,16 @@ The state transitioning model does all all the necessary work to work out a vali
 6) Derive new state root
 */
 type StateTransition struct {
-	gp            *GasPool
-	msg           Message
-	gas, gasPrice *big.Int
-	initialGas    *big.Int
-	value         *big.Int
-	data          []byte
-	state         vm.StateDB
-
-	env *vm.EVM
+	gp         *GasPool
+	msg        Message
+	gas        uint64
+	gasPrice   *big.Int
+	initialGas *big.Int
+	value      *big.Int
+	data       []byte
+	state      vm.StateDB
+
+	evm *vm.EVM
 }
 
 // Message represents a message sent to a contract.
@@ -81,12 +82,14 @@ func MessageCreatesContract(msg Message) bool {
 
 // IntrinsicGas computes the 'intrinsic gas' for a message
 // with the given data.
+//
+// TODO convert to uint64
 func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
 	igas := new(big.Int)
 	if contractCreation && homestead {
-		igas.Set(params.TxGasContractCreation)
+		igas.SetUint64(params.TxGasContractCreation)
 	} else {
-		igas.Set(params.TxGas)
+		igas.SetUint64(params.TxGas)
 	}
 	if len(data) > 0 {
 		var nz int64
@@ -96,27 +99,26 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
 			}
 		}
 		m := big.NewInt(nz)
-		m.Mul(m, params.TxDataNonZeroGas)
+		m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas))
 		igas.Add(igas, m)
 		m.SetInt64(int64(len(data)) - nz)
-		m.Mul(m, params.TxDataZeroGas)
+		m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas))
 		igas.Add(igas, m)
 	}
 	return igas
 }
 
 // NewStateTransition initialises and returns a new state transition object.
-func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition {
+func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
 	return &StateTransition{
 		gp:         gp,
-		env:        env,
+		evm:        evm,
 		msg:        msg,
-		gas:        new(big.Int),
 		gasPrice:   msg.GasPrice(),
 		initialGas: new(big.Int),
 		value:      msg.Value(),
 		data:       msg.Data(),
-		state:      env.StateDB,
+		state:      evm.StateDB,
 	}
 }
 
@@ -127,8 +129,8 @@ func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition
 // the gas used (which includes gas refunds) and an error if it failed. An error always
 // indicates a core error meaning that the message would always fail for that particular
 // state and would never be accepted within a block.
-func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
-	st := NewStateTransition(env, msg, gp)
+func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
+	st := NewStateTransition(evm, msg, gp)
 
 	ret, _, gasUsed, err := st.TransitionDb()
 	return ret, gasUsed, err
@@ -157,21 +159,21 @@ func (self *StateTransition) to() vm.Account {
 	return self.state.GetAccount(*to)
 }
 
-func (self *StateTransition) useGas(amount *big.Int) error {
-	if self.gas.Cmp(amount) < 0 {
+func (self *StateTransition) useGas(amount uint64) error {
+	if self.gas < amount {
 		return vm.ErrOutOfGas
 	}
-	self.gas.Sub(self.gas, amount)
+	self.gas -= amount
 
 	return nil
 }
 
-func (self *StateTransition) addGas(amount *big.Int) {
-	self.gas.Add(self.gas, amount)
-}
-
 func (self *StateTransition) buyGas() error {
 	mgas := self.msg.Gas()
+	if mgas.BitLen() > 64 {
+		return vm.ErrOutOfGas
+	}
+
 	mgval := new(big.Int).Mul(mgas, self.gasPrice)
 
 	sender := self.from()
@@ -181,7 +183,8 @@ func (self *StateTransition) buyGas() error {
 	if err := self.gp.SubGas(mgas); err != nil {
 		return err
 	}
-	self.addGas(mgas)
+	self.gas += mgas.Uint64()
+
 	self.initialGas.Set(mgas)
 	sender.SubBalance(mgval)
 	return nil
@@ -209,7 +212,9 @@ func (self *StateTransition) preCheck() (err error) {
 	return nil
 }
 
-// TransitionDb will move the state by applying the message against the given environment.
+// TransitionDb will transition the state by applying the current message and returning the result
+// including the required gas for the operation as well as the used gas. It returns an error if it
+// failed. An error indicates a consensus issue.
 func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) {
 	if err = self.preCheck(); err != nil {
 		return
@@ -217,26 +222,32 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
 	msg := self.msg
 	sender := self.from() // err checked in preCheck
 
-	homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber)
+	homestead := self.evm.ChainConfig().IsHomestead(self.evm.BlockNumber)
 	contractCreation := MessageCreatesContract(msg)
 	// Pay intrinsic gas
-	if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
+	// TODO convert to uint64
+	intrinsicGas := IntrinsicGas(self.data, contractCreation, homestead)
+	if intrinsicGas.BitLen() > 64 {
+		return nil, nil, nil, InvalidTxError(vm.ErrOutOfGas)
+	}
+
+	if err = self.useGas(intrinsicGas.Uint64()); err != nil {
 		return nil, nil, nil, InvalidTxError(err)
 	}
 
 	var (
-		vmenv = self.env
+		evm = self.evm
 		// vm errors do not effect consensus and are therefor
 		// not assigned to err, except for insufficient balance
 		// error.
 		vmerr error
 	)
 	if contractCreation {
-		ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
+		ret, _, self.gas, vmerr = evm.Create(sender, self.data, self.gas, self.value)
 	} else {
 		// Increment the nonce for the next transaction
 		self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
-		ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value)
+		ret, self.gas, vmerr = evm.Call(sender, self.to().Address(), self.data, self.gas, self.value)
 	}
 	if vmerr != nil {
 		glog.V(logger.Core).Infoln("vm returned with error:", err)
@@ -251,7 +262,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
 	requiredGas = new(big.Int).Set(self.gasUsed())
 
 	self.refundGas()
-	self.state.AddBalance(self.env.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
+	self.state.AddBalance(self.evm.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
 
 	return ret, requiredGas, self.gasUsed(), err
 }
@@ -260,20 +271,21 @@ func (self *StateTransition) refundGas() {
 	// Return eth for remaining gas to the sender account,
 	// exchanged at the original rate.
 	sender := self.from() // err already checked
-	remaining := new(big.Int).Mul(self.gas, self.gasPrice)
+	remaining := new(big.Int).Mul(new(big.Int).SetUint64(self.gas), self.gasPrice)
 	sender.AddBalance(remaining)
 
 	// Apply refund counter, capped to half of the used gas.
 	uhalf := remaining.Div(self.gasUsed(), common.Big2)
 	refund := common.BigMin(uhalf, self.state.GetRefund())
-	self.gas.Add(self.gas, refund)
+	self.gas += refund.Uint64()
+
 	self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
 
 	// Also return remaining gas to the block gas counter so it is
 	// available for the next transaction.
-	self.gp.AddGas(self.gas)
+	self.gp.AddGas(new(big.Int).SetUint64(self.gas))
 }
 
 func (self *StateTransition) gasUsed() *big.Int {
-	return new(big.Int).Sub(self.initialGas, self.gas)
+	return new(big.Int).Sub(self.initialGas, new(big.Int).SetUint64(self.gas))
 }
diff --git a/core/vm/common.go b/core/vm/common.go
index 2878b92d2a01548085412eb003e9944da062676d..b7b9a6a9c7e0d880306c15271e151acf03d49f64 100644
--- a/core/vm/common.go
+++ b/core/vm/common.go
@@ -21,28 +21,11 @@ import (
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/params"
-)
-
-// Type is the VM type accepted by **NewVm**
-type Type byte
-
-const (
-	StdVmTy Type = iota // Default standard VM
-	JitVmTy             // LLVM JIT VM
-	MaxVmTy
 )
 
 var (
-	Pow256 = common.BigPow(2, 256) // Pow256 is 2**256
-
 	U256 = common.U256 // Shortcut to common.U256
 	S256 = common.S256 // Shortcut to common.S256
-
-	Zero = common.Big0 // Shortcut to common.Big0
-	One  = common.Big1 // Shortcut to common.Big1
-
-	max = big.NewInt(math.MaxInt64) // Maximum 64 bit integer
 )
 
 // calculates the memory size required for a step
@@ -54,48 +37,6 @@ func calcMemSize(off, l *big.Int) *big.Int {
 	return new(big.Int).Add(off, l)
 }
 
-// calculates the quadratic gas
-func quadMemGas(mem *Memory, newMemSize, gas *big.Int) {
-	if newMemSize.Cmp(common.Big0) > 0 {
-		newMemSizeWords := toWordSize(newMemSize)
-		newMemSize.Mul(newMemSizeWords, u256(32))
-
-		if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
-			// be careful reusing variables here when changing.
-			// The order has been optimised to reduce allocation
-			oldSize := toWordSize(big.NewInt(int64(mem.Len())))
-			pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
-			linCoef := oldSize.Mul(oldSize, params.MemoryGas)
-			quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
-			oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
-
-			pow.Exp(newMemSizeWords, common.Big2, Zero)
-			linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
-			quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
-			newTotalFee := linCoef.Add(linCoef, quadCoef)
-
-			fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
-			gas.Add(gas, fee)
-		}
-	}
-}
-
-// Simple helper
-func u256(n int64) *big.Int {
-	return big.NewInt(n)
-}
-
-// Mainly used for print variables and passing to Print*
-func toValue(val *big.Int) interface{} {
-	// Let's assume a string on right padded zero's
-	b := val.Bytes()
-	if b[0] != 0 && b[len(b)-1] == 0x0 && b[len(b)-2] == 0x0 {
-		return string(b)
-	}
-
-	return val
-}
-
 // getData returns a slice from the data based on the start and size and pads
 // up to size with zero's. This function is overflow safe.
 func getData(data []byte, start, size *big.Int) []byte {
@@ -106,14 +47,17 @@ func getData(data []byte, start, size *big.Int) []byte {
 	return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
 }
 
-// useGas attempts to subtract the amount of gas and returns whether it was
-// successful
-func useGas(gas, amount *big.Int) bool {
-	if gas.Cmp(amount) < 0 {
-		return false
+// bigUint64 returns the integer casted to a uint64 and returns whether it
+// overflowed in the process.
+func bigUint64(v *big.Int) (uint64, bool) {
+	return v.Uint64(), v.BitLen() > 64
+}
+
+// toWordSize returns the ceiled word size required for memory expansion.
+func toWordSize(size uint64) uint64 {
+	if size > math.MaxUint64-31 {
+		return math.MaxUint64/32 + 1
 	}
 
-	// Sub the amount of gas from the remaining
-	gas.Sub(gas, amount)
-	return true
+	return (size + 31) / 32
 }
diff --git a/core/vm/contract.go b/core/vm/contract.go
index dfa93ab18b6cb71dc3a9a2bd204784b190f0411e..091106d84d77054007bd418126be139420fab3b2 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -24,7 +24,6 @@ import (
 
 // ContractRef is a reference to the contract's backing object
 type ContractRef interface {
-	ReturnGas(*big.Int)
 	Address() common.Address
 	Value() *big.Int
 	SetCode(common.Hash, []byte)
@@ -48,7 +47,8 @@ type Contract struct {
 	CodeAddr *common.Address
 	Input    []byte
 
-	value, Gas, UsedGas *big.Int
+	Gas   uint64
+	value *big.Int
 
 	Args []byte
 
@@ -56,7 +56,7 @@ type Contract struct {
 }
 
 // NewContract returns a new contract environment for the execution of EVM.
-func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *Contract {
+func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
 	c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
 
 	if parent, ok := caller.(*Contract); ok {
@@ -68,9 +68,8 @@ func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *C
 
 	// Gas should be a pointer so it can safely be reduced through the run
 	// This pointer will be off the state transition
-	c.Gas = gas //new(big.Int).Set(gas)
+	c.Gas = gas
 	c.value = new(big.Int).Set(value)
-	c.UsedGas = new(big.Int)
 
 	return c
 }
@@ -107,27 +106,13 @@ func (c *Contract) Caller() common.Address {
 	return c.CallerAddress
 }
 
-// Finalise finalises the contract and returning any remaining gas to the original
-// caller.
-func (c *Contract) Finalise() {
-	// Return the remaining gas to the caller
-	c.caller.ReturnGas(c.Gas)
-}
-
 // UseGas attempts the use gas and subtracts it and returns true on success
-func (c *Contract) UseGas(gas *big.Int) (ok bool) {
-	ok = useGas(c.Gas, gas)
-	if ok {
-		c.UsedGas.Add(c.UsedGas, gas)
+func (c *Contract) UseGas(gas uint64) (ok bool) {
+	if c.Gas < gas {
+		return false
 	}
-	return
-}
-
-// ReturnGas adds the given gas back to itself.
-func (c *Contract) ReturnGas(gas *big.Int) {
-	// Return the gas to the context
-	c.Gas.Add(c.Gas, gas)
-	c.UsedGas.Sub(c.UsedGas, gas)
+	c.Gas -= gas
+	return true
 }
 
 // Address returns the contracts address
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 9645d268fe12a352cc1a47fcf479ea2aa9e0ac08..593b6ca55c48dc75de2e5e839f58ff1ea9c7cdd3 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -17,8 +17,6 @@
 package vm
 
 import (
-	"math/big"
-
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/logger"
@@ -30,8 +28,8 @@ import (
 // requires a deterministic gas count based on the input size of the Run method of the
 // contract.
 type PrecompiledContract interface {
-	RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
-	Run(input []byte) []byte            // Run runs the precompiled contract
+	RequiredGas(inputSize int) uint64 // RequiredPrice calculates the contract gas use
+	Run(input []byte) []byte          // Run runs the precompiled contract
 }
 
 // Precompiled contains the default set of ethereum contracts
@@ -57,7 +55,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr
 // ECRECOVER implemented as a native contract
 type ecrecover struct{}
 
-func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
+func (c *ecrecover) RequiredGas(inputSize int) uint64 {
 	return params.EcrecoverGas
 }
 
@@ -92,10 +90,12 @@ func (c *ecrecover) Run(in []byte) []byte {
 // SHA256 implemented as a native contract
 type sha256 struct{}
 
-func (c *sha256) RequiredGas(inputSize int) *big.Int {
-	n := big.NewInt(int64(inputSize+31) / 32)
-	n.Mul(n, params.Sha256WordGas)
-	return n.Add(n, params.Sha256Gas)
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *sha256) RequiredGas(inputSize int) uint64 {
+	return uint64(inputSize+31)/32*params.Sha256WordGas + params.Sha256Gas
 }
 func (c *sha256) Run(in []byte) []byte {
 	return crypto.Sha256(in)
@@ -104,10 +104,12 @@ func (c *sha256) Run(in []byte) []byte {
 // RIPMED160 implemented as a native contract
 type ripemd160 struct{}
 
-func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
-	n := big.NewInt(int64(inputSize+31) / 32)
-	n.Mul(n, params.Ripemd160WordGas)
-	return n.Add(n, params.Ripemd160Gas)
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *ripemd160) RequiredGas(inputSize int) uint64 {
+	return uint64(inputSize+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas
 }
 func (c *ripemd160) Run(in []byte) []byte {
 	return common.LeftPadBytes(crypto.Ripemd160(in), 32)
@@ -116,11 +118,12 @@ func (c *ripemd160) Run(in []byte) []byte {
 // data copy implemented as a native contract
 type dataCopy struct{}
 
-func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
-	n := big.NewInt(int64(inputSize+31) / 32)
-	n.Mul(n, params.IdentityWordGas)
-
-	return n.Add(n, params.IdentityGas)
+// RequiredGas returns the gas required to execute the pre-compiled contract.
+//
+// This method does not require any overflow checking as the input size gas costs
+// required for anything significant is so high it's impossible to pay for.
+func (c *dataCopy) RequiredGas(inputSize int) uint64 {
+	return uint64(inputSize+31)/32*params.IdentityWordGas + params.IdentityGas
 }
 func (c *dataCopy) Run(in []byte) []byte {
 	return in
diff --git a/core/vm/environment.go b/core/vm/evm.go
similarity index 85%
rename from core/vm/environment.go
rename to core/vm/evm.go
index c19ef464bae801eb77c28bb3a1c73afe385976a7..0c5d998c2944dee449f917b9593bf9346e9e4961 100644
--- a/core/vm/environment.go
+++ b/core/vm/evm.go
@@ -17,7 +17,6 @@
 package vm
 
 import (
-	"fmt"
 	"math/big"
 	"sync/atomic"
 
@@ -102,24 +101,18 @@ func (evm *EVM) Cancel() {
 // Call executes the contract associated with the addr with the given input as parameters. It also handles any
 // necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
 // case of an execution error or failed value transfer.
-func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
+func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
 	if evm.vmConfig.NoRecursion && evm.depth > 0 {
-		caller.ReturnGas(gas)
-
-		return nil, nil
+		return nil, gas, nil
 	}
 
 	// Depth check execution. Fail if we're trying to execute above the
 	// limit.
-	if evm.depth > int(params.CallCreateDepth.Int64()) {
-		caller.ReturnGas(gas)
-
-		return nil, ErrDepth
+	if evm.depth > int(params.CallCreateDepth) {
+		return nil, gas, ErrDepth
 	}
 	if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
-		caller.ReturnGas(gas)
-
-		return nil, ErrInsufficientBalance
+		return nil, gas, ErrInsufficientBalance
 	}
 
 	var (
@@ -128,8 +121,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
 	)
 	if !evm.StateDB.Exist(addr) {
 		if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 {
-			caller.ReturnGas(gas)
-			return nil, nil
+			return nil, gas, nil
 		}
 
 		to = evm.StateDB.CreateAccount(addr)
@@ -143,7 +135,6 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
 	// only.
 	contract := NewContract(caller, to, value, gas)
 	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
-	defer contract.Finalise()
 
 	ret, err = evm.interpreter.Run(contract, input)
 	// When an error was returned by the EVM or when setting the creation code
@@ -154,7 +145,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
 
 		evm.StateDB.RevertToSnapshot(snapshot)
 	}
-	return ret, err
+	return ret, contract.Gas, err
 }
 
 // CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
@@ -162,24 +153,18 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas,
 // case of an execution error or failed value transfer.
 //
 // CallCode differs from Call in the sense that it executes the given address' code with the caller as context.
-func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
+func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
 	if evm.vmConfig.NoRecursion && evm.depth > 0 {
-		caller.ReturnGas(gas)
-
-		return nil, nil
+		return nil, gas, nil
 	}
 
 	// Depth check execution. Fail if we're trying to execute above the
 	// limit.
-	if evm.depth > int(params.CallCreateDepth.Int64()) {
-		caller.ReturnGas(gas)
-
-		return nil, ErrDepth
+	if evm.depth > int(params.CallCreateDepth) {
+		return nil, gas, ErrDepth
 	}
 	if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
-		caller.ReturnGas(gas)
-
-		return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, evm.StateDB.GetBalance(caller.Address()))
+		return nil, gas, ErrInsufficientBalance
 	}
 
 	var (
@@ -191,7 +176,6 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
 	// only.
 	contract := NewContract(caller, to, value, gas)
 	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
-	defer contract.Finalise()
 
 	ret, err = evm.interpreter.Run(contract, input)
 	if err != nil {
@@ -200,7 +184,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
 		evm.StateDB.RevertToSnapshot(snapshot)
 	}
 
-	return ret, err
+	return ret, contract.Gas, err
 }
 
 // DelegateCall executes the contract associated with the addr with the given input as parameters.
@@ -208,18 +192,15 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
 //
 // DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context
 // and the caller is set to the caller of the caller.
-func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) (ret []byte, err error) {
+func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
 	if evm.vmConfig.NoRecursion && evm.depth > 0 {
-		caller.ReturnGas(gas)
-
-		return nil, nil
+		return nil, gas, nil
 	}
 
 	// Depth check execution. Fail if we're trying to execute above the
 	// limit.
-	if evm.depth > int(params.CallCreateDepth.Int64()) {
-		caller.ReturnGas(gas)
-		return nil, ErrDepth
+	if evm.depth > int(params.CallCreateDepth) {
+		return nil, gas, ErrDepth
 	}
 
 	var (
@@ -230,7 +211,6 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
 	// Iinitialise a new contract and make initialise the delegate values
 	contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
 	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
-	defer contract.Finalise()
 
 	ret, err = evm.interpreter.Run(contract, input)
 	if err != nil {
@@ -239,28 +219,22 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
 		evm.StateDB.RevertToSnapshot(snapshot)
 	}
 
-	return ret, err
+	return ret, contract.Gas, err
 }
 
 // Create creates a new contract using code as deployment code.
-func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (ret []byte, contractAddr common.Address, err error) {
+func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
 	if evm.vmConfig.NoRecursion && evm.depth > 0 {
-		caller.ReturnGas(gas)
-
-		return nil, common.Address{}, nil
+		return nil, common.Address{}, gas, nil
 	}
 
 	// Depth check execution. Fail if we're trying to execute above the
 	// limit.
-	if evm.depth > int(params.CallCreateDepth.Int64()) {
-		caller.ReturnGas(gas)
-
-		return nil, common.Address{}, ErrDepth
+	if evm.depth > int(params.CallCreateDepth) {
+		return nil, common.Address{}, gas, ErrDepth
 	}
 	if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
-		caller.ReturnGas(gas)
-
-		return nil, common.Address{}, ErrInsufficientBalance
+		return nil, common.Address{}, gas, ErrInsufficientBalance
 	}
 
 	// Create a new account on the state
@@ -280,7 +254,6 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
 	// only.
 	contract := NewContract(caller, to, value, gas)
 	contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
-	defer contract.Finalise()
 
 	ret, err = evm.interpreter.Run(contract, nil)
 
@@ -291,9 +264,8 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
 	// be stored due to not enough gas set an error and let it be handled
 	// by the error checking condition below.
 	if err == nil && !maxCodeSizeExceeded {
-		dataGas := big.NewInt(int64(len(ret)))
-		dataGas.Mul(dataGas, params.CreateDataGas)
-		if contract.UseGas(dataGas) {
+		createDataGas := uint64(len(ret)) * params.CreateDataGas
+		if contract.UseGas(createDataGas) {
 			evm.StateDB.SetCode(contractAddr, ret)
 		} else {
 			err = ErrCodeStoreOutOfGas
@@ -305,11 +277,10 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
 	// when we're in homestead this also counts for code storage gas errors.
 	if maxCodeSizeExceeded ||
 		(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
-		contract.UseGas(contract.Gas)
 		evm.StateDB.RevertToSnapshot(snapshot)
 
 		// Nothing should be returned when an error is thrown.
-		return nil, contractAddr, err
+		return nil, contractAddr, 0, err
 	}
 	// If the vm returned with an error the return value should be set to nil.
 	// This isn't consensus critical but merely to for behaviour reasons such as
@@ -318,7 +289,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (re
 		ret = nil
 	}
 
-	return ret, contractAddr, err
+	return ret, contractAddr, contract.Gas, err
 }
 
 // ChainConfig returns the evmironment's chain configuration
diff --git a/core/vm/gas.go b/core/vm/gas.go
index cb225b6cac9bfda6adbe12c285df2528a85d4df6..dd64d5f178d27b678846d8677d9719bdfdfcef19 100644
--- a/core/vm/gas.go
+++ b/core/vm/gas.go
@@ -17,149 +17,42 @@
 package vm
 
 import (
-	"fmt"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/params"
 )
 
-var (
-	GasQuickStep   = big.NewInt(2)
-	GasFastestStep = big.NewInt(3)
-	GasFastStep    = big.NewInt(5)
-	GasMidStep     = big.NewInt(8)
-	GasSlowStep    = big.NewInt(10)
-	GasExtStep     = big.NewInt(20)
-
-	GasReturn = big.NewInt(0)
-	GasStop   = big.NewInt(0)
-
-	GasContractByte = big.NewInt(200)
-
-	n64 = big.NewInt(64)
+const (
+	GasQuickStep   uint64 = 2
+	GasFastestStep uint64 = 3
+	GasFastStep    uint64 = 5
+	GasMidStep     uint64 = 8
+	GasSlowStep    uint64 = 10
+	GasExtStep     uint64 = 20
+
+	GasReturn       uint64 = 0
+	GasStop         uint64 = 0
+	GasContractByte uint64 = 200
 )
 
 // calcGas returns the actual gas cost of the call.
 //
 // The cost of gas was changed during the homestead price change HF. To allow for EIP150
 // to be implemented. The returned gas is gas - base * 63 / 64.
-func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int {
-	if gasTable.CreateBySuicide != nil {
-		availableGas = new(big.Int).Sub(availableGas, base)
-		g := new(big.Int).Div(availableGas, n64)
-		g.Sub(availableGas, g)
-
-		if g.Cmp(callCost) < 0 {
-			return g
+func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) {
+	if gasTable.CreateBySuicide > 0 {
+		availableGas = availableGas - base
+		gas := availableGas - availableGas/64
+		// If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150
+		// is smaller than the requested amount. Therefor we return the new gas instead
+		// of returning an error.
+		if callCost.BitLen() > 64 || gas < callCost.Uint64() {
+			return gas, nil
 		}
 	}
-	return callCost
-}
-
-// baseCheck checks for any stack error underflows
-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 >= DUP1 && op <= DUP16 {
-		op = DUP1
-	}
-
-	if r, ok := _baseCheck[op]; ok {
-		err := stack.require(r.stackPop)
-		if err != nil {
-			return err
-		}
-
-		if r.stackPush > 0 && stack.len()-r.stackPop+r.stackPush > int(params.StackLimit.Int64()) {
-			return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
-		}
-
-		gas.Add(gas, r.gas)
+	if callCost.BitLen() > 64 {
+		return 0, errGasUintOverflow
 	}
-	return nil
-}
-
-// casts a arbitrary number to the amount of words (sets of 32 bytes)
-func toWordSize(size *big.Int) *big.Int {
-	tmp := new(big.Int)
-	tmp.Add(size, u256(31))
-	tmp.Div(tmp, u256(32))
-	return tmp
-}
-
-type req struct {
-	stackPop  int
-	gas       *big.Int
-	stackPush int
-}
 
-var _baseCheck = map[OpCode]req{
-	// opcode  |  stack pop | gas price | stack push
-	ADD:          {2, GasFastestStep, 1},
-	LT:           {2, GasFastestStep, 1},
-	GT:           {2, GasFastestStep, 1},
-	SLT:          {2, GasFastestStep, 1},
-	SGT:          {2, GasFastestStep, 1},
-	EQ:           {2, GasFastestStep, 1},
-	ISZERO:       {1, GasFastestStep, 1},
-	SUB:          {2, GasFastestStep, 1},
-	AND:          {2, GasFastestStep, 1},
-	OR:           {2, GasFastestStep, 1},
-	XOR:          {2, GasFastestStep, 1},
-	NOT:          {1, GasFastestStep, 1},
-	BYTE:         {2, GasFastestStep, 1},
-	CALLDATALOAD: {1, GasFastestStep, 1},
-	CALLDATACOPY: {3, GasFastestStep, 1},
-	MLOAD:        {1, GasFastestStep, 1},
-	MSTORE:       {2, GasFastestStep, 0},
-	MSTORE8:      {2, GasFastestStep, 0},
-	CODECOPY:     {3, GasFastestStep, 0},
-	MUL:          {2, GasFastStep, 1},
-	DIV:          {2, GasFastStep, 1},
-	SDIV:         {2, GasFastStep, 1},
-	MOD:          {2, GasFastStep, 1},
-	SMOD:         {2, GasFastStep, 1},
-	SIGNEXTEND:   {2, GasFastStep, 1},
-	ADDMOD:       {3, GasMidStep, 1},
-	MULMOD:       {3, GasMidStep, 1},
-	JUMP:         {1, GasMidStep, 0},
-	JUMPI:        {2, GasSlowStep, 0},
-	EXP:          {2, GasSlowStep, 1},
-	ADDRESS:      {0, GasQuickStep, 1},
-	ORIGIN:       {0, GasQuickStep, 1},
-	CALLER:       {0, GasQuickStep, 1},
-	CALLVALUE:    {0, GasQuickStep, 1},
-	CODESIZE:     {0, GasQuickStep, 1},
-	GASPRICE:     {0, GasQuickStep, 1},
-	COINBASE:     {0, GasQuickStep, 1},
-	TIMESTAMP:    {0, GasQuickStep, 1},
-	NUMBER:       {0, GasQuickStep, 1},
-	CALLDATASIZE: {0, GasQuickStep, 1},
-	DIFFICULTY:   {0, GasQuickStep, 1},
-	GASLIMIT:     {0, GasQuickStep, 1},
-	POP:          {1, GasQuickStep, 0},
-	PC:           {0, GasQuickStep, 1},
-	MSIZE:        {0, GasQuickStep, 1},
-	GAS:          {0, GasQuickStep, 1},
-	BLOCKHASH:    {1, GasExtStep, 1},
-	BALANCE:      {1, Zero, 1},
-	EXTCODESIZE:  {1, Zero, 1},
-	EXTCODECOPY:  {4, Zero, 0},
-	SLOAD:        {1, params.SloadGas, 1},
-	SSTORE:       {2, Zero, 0},
-	SHA3:         {2, params.Sha3Gas, 1},
-	CREATE:       {3, params.CreateGas, 1},
-	// Zero is calculated in the gasSwitch
-	CALL:         {7, Zero, 1},
-	CALLCODE:     {7, Zero, 1},
-	DELEGATECALL: {6, Zero, 1},
-	SELFDESTRUCT: {1, Zero, 0},
-	JUMPDEST:     {0, params.JumpdestGas, 0},
-	RETURN:       {2, Zero, 0},
-	PUSH1:        {0, GasFastestStep, 1},
-	DUP1:         {0, Zero, 1},
+	return callCost.Uint64(), nil
 }
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index 4d2c4e94aef81b23adf2489249738300481a2401..fba1eb066ec297cd263afbdbd654ff0b8eb157e6 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -1,56 +1,80 @@
 package vm
 
 import (
+	gmath "math"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/params"
 )
 
-func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int {
-	gas := new(big.Int)
-	if newMemSize.Cmp(common.Big0) > 0 {
-		newMemSizeWords := toWordSize(newMemSize)
-
-		if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
-			// be careful reusing variables here when changing.
-			// The order has been optimised to reduce allocation
-			oldSize := toWordSize(big.NewInt(int64(mem.Len())))
-			pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
-			linCoef := oldSize.Mul(oldSize, params.MemoryGas)
-			quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
-			oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
-
-			pow.Exp(newMemSizeWords, common.Big2, Zero)
-			linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
-			quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
-			newTotalFee := linCoef.Add(linCoef, quadCoef)
-
-			fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
-			gas.Add(gas, fee)
-		}
+// memoryGasCosts calculates the quadratic gas for memory expansion. It does so
+// only for the memory region that is expanded, not the total memory.
+func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
+	// The maximum that will fit in a uint64 is max_word_count - 1
+	// anything above that will result in an overflow.
+	if newMemSize > gmath.MaxUint64-32 {
+		return 0, errGasUintOverflow
+	}
+
+	if newMemSize == 0 {
+		return 0, nil
 	}
-	return gas
+
+	newMemSizeWords := toWordSize(newMemSize)
+	newMemSize = newMemSizeWords * 32
+
+	if newMemSize > uint64(mem.Len()) {
+		square := newMemSizeWords * newMemSizeWords
+		linCoef := newMemSizeWords * params.MemoryGas
+		quadCoef := square / params.QuadCoeffDiv
+		newTotalFee := linCoef + quadCoef
+
+		fee := newTotalFee - mem.lastGasCost
+		mem.lastGasCost = newTotalFee
+
+		return fee, nil
+	}
+	return 0, nil
 }
 
-func constGasFunc(gas *big.Int) gasFunc {
-	return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-		return gas
+func constGasFunc(gas uint64) gasFunc {
+	return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+		return gas, nil
 	}
 }
 
-func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := memoryGasCost(mem, memorySize)
-	gas.Add(gas, GasFastestStep)
-	words := toWordSize(stack.Back(2))
+func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+		return 0, errGasUintOverflow
+	}
 
-	return gas.Add(gas, words.Mul(words, params.CopyGas))
+	words, overflow := bigUint64(stack.Back(2))
+	if overflow {
+		return 0, errGasUintOverflow
+	}
+
+	if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
+		return 0, errGasUintOverflow
+	}
+
+	if gas, overflow = math.SafeAdd(gas, words); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
+func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	var (
 		y, x = stack.Back(1), stack.Back(0)
-		val  = env.StateDB.GetState(contract.Address(), common.BigToHash(x))
+		val  = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
 	)
 	// This checks for 3 scenario's and calculates gas accordingly
 	// 1. From a zero-value address to a non-zero value         (NEW VALUE)
@@ -58,189 +82,335 @@ func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, m
 	// 3. From a non-zero to a non-zero                         (CHANGE)
 	if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
 		// 0 => non 0
-		return new(big.Int).Set(params.SstoreSetGas)
+		return params.SstoreSetGas, nil
 	} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
-		env.StateDB.AddRefund(params.SstoreRefundGas)
+		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas))
 
-		return new(big.Int).Set(params.SstoreClearGas)
+		return params.SstoreClearGas, nil
 	} else {
 		// non 0 => non 0 (or 0 => 0)
-		return new(big.Int).Set(params.SstoreResetGas)
+		return params.SstoreResetGas, nil
 	}
 }
 
-func makeGasLog(n uint) gasFunc {
-	return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-		mSize := stack.Back(1)
+func makeGasLog(n uint64) gasFunc {
+	return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+		requestedSize, overflow := bigUint64(stack.Back(1))
+		if overflow {
+			return 0, errGasUintOverflow
+		}
 
-		gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas)
-		gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
-		gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
-		return gas
+		gas, err := memoryGasCost(mem, memorySize)
+		if err != nil {
+			return 0, err
+		}
+
+		if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
+			return 0, errGasUintOverflow
+		}
+		if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
+			return 0, errGasUintOverflow
+		}
+
+		var memorySizeGas uint64
+		if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
+			return 0, errGasUintOverflow
+		}
+		if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
+			return 0, errGasUintOverflow
+		}
+		return gas, nil
 	}
 }
 
-func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := memoryGasCost(mem, memorySize)
-	gas.Add(gas, params.Sha3Gas)
-	words := toWordSize(stack.Back(1))
-	return gas.Add(gas, words.Mul(words, params.Sha3WordGas))
-}
+func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var overflow bool
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
 
-func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := memoryGasCost(mem, memorySize)
-	gas.Add(gas, GasFastestStep)
-	words := toWordSize(stack.Back(2))
+	if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
+		return 0, errGasUintOverflow
+	}
 
-	return gas.Add(gas, words.Mul(words, params.CopyGas))
+	wordGas, overflow := bigUint64(stack.Back(1))
+	if overflow {
+		return 0, errGasUintOverflow
+	}
+	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
+		return 0, errGasUintOverflow
+	}
+	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := memoryGasCost(mem, memorySize)
-	gas.Add(gas, gt.ExtcodeCopy)
-	words := toWordSize(stack.Back(3))
+func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+		return 0, errGasUintOverflow
+	}
 
-	return gas.Add(gas, words.Mul(words, params.CopyGas))
+	wordGas, overflow := bigUint64(stack.Back(2))
+	if overflow {
+		return 0, errGasUintOverflow
+	}
+	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
+		return 0, errGasUintOverflow
+	}
+	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
+func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
+		return 0, errGasUintOverflow
+	}
+
+	wordGas, overflow := bigUint64(stack.Back(3))
+	if overflow {
+		return 0, errGasUintOverflow
+	}
+
+	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
+		return 0, errGasUintOverflow
+	}
+
+	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
+func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var overflow bool
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, errGasUintOverflow
+	}
+	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
+func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var overflow bool
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, errGasUintOverflow
+	}
+	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize))
+func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var overflow bool
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, errGasUintOverflow
+	}
+	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return gt.Balance
+func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var overflow bool
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+	if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return gt.ExtcodeSize
+func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.Balance, nil
 }
 
-func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return gt.SLoad
+func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.ExtcodeSize, nil
 }
 
-func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
-	gas := big.NewInt(expByteLen)
-	gas.Mul(gas, gt.ExpByte)
-	return gas.Add(gas, GasSlowStep)
+func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.SLoad, nil
 }
 
-func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := new(big.Int).Set(gt.Calls)
+func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
 
-	transfersValue := stack.Back(2).BitLen() > 0
 	var (
-		address = common.BigToAddress(stack.Back(1))
-		eip158  = env.ChainConfig().IsEIP158(env.BlockNumber)
+		gas      = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
+		overflow bool
+	)
+	if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
+}
+
+func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var (
+		gas            = gt.Calls
+		transfersValue = stack.Back(2).BitLen() > 0
+		address        = common.BigToAddress(stack.Back(1))
+		eip158         = evm.ChainConfig().IsEIP158(evm.BlockNumber)
 	)
 	if eip158 {
-		if env.StateDB.Empty(address) && transfersValue {
-			gas.Add(gas, params.CallNewAccountGas)
+		if evm.StateDB.Empty(address) && transfersValue {
+			gas += params.CallNewAccountGas
 		}
-	} else if !env.StateDB.Exist(address) {
-		gas.Add(gas, params.CallNewAccountGas)
+	} else if !evm.StateDB.Exist(address) {
+		gas += params.CallNewAccountGas
 	}
 	if transfersValue {
-		gas.Add(gas, params.CallValueTransferGas)
+		gas += params.CallValueTransferGas
+	}
+	memoryGas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
+		return 0, errGasUintOverflow
 	}
-	gas.Add(gas, memoryGasCost(mem, memorySize))
 
-	cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
+	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
+	if err != nil {
+		return 0, err
+	}
 	// Replace the stack item with the new gas calculation. This means that
 	// either the original item is left on the stack or the item is replaced by:
 	// (availableGas - gas) * 63 / 64
 	// We replace the stack item so that it's available when the opCall instruction is
 	// called. This information is otherwise lost due to the dependency on *current*
 	// available gas.
-	stack.data[stack.len()-1] = cg
+	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
 
-	return gas.Add(gas, cg)
+	if gas, overflow = math.SafeAdd(gas, cg); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := new(big.Int).Set(gt.Calls)
+func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	gas := gt.Calls
 	if stack.Back(2).BitLen() > 0 {
-		gas.Add(gas, params.CallValueTransferGas)
+		gas += params.CallValueTransferGas
+	}
+	memoryGas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
+		return 0, errGasUintOverflow
 	}
-	gas.Add(gas, memoryGasCost(mem, memorySize))
 
-	cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
+	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
+	if err != nil {
+		return 0, err
+	}
 	// Replace the stack item with the new gas calculation. This means that
 	// either the original item is left on the stack or the item is replaced by:
 	// (availableGas - gas) * 63 / 64
 	// We replace the stack item so that it's available when the opCall instruction is
 	// called. This information is otherwise lost due to the dependency on *current*
 	// available gas.
-	stack.data[stack.len()-1] = cg
+	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
 
-	return gas.Add(gas, cg)
+	if gas, overflow = math.SafeAdd(gas, cg); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
+func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	return memoryGasCost(mem, memorySize)
 }
 
-func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := new(big.Int)
+func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	var gas uint64
 	// EIP150 homestead gas reprice fork:
-	if env.ChainConfig().IsEIP150(env.BlockNumber) {
-		gas.Set(gt.Suicide)
+	if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
+		gas = gt.Suicide
 		var (
 			address = common.BigToAddress(stack.Back(0))
-			eip158  = env.ChainConfig().IsEIP158(env.BlockNumber)
+			eip158  = evm.ChainConfig().IsEIP158(evm.BlockNumber)
 		)
 
 		if eip158 {
 			// if empty and transfers value
-			if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
-				gas.Add(gas, gt.CreateBySuicide)
+			if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
+				gas += gt.CreateBySuicide
 			}
-		} else if !env.StateDB.Exist(address) {
-			gas.Add(gas, gt.CreateBySuicide)
+		} else if !evm.StateDB.Exist(address) {
+			gas += gt.CreateBySuicide
 		}
 	}
 
-	if !env.StateDB.HasSuicided(contract.Address()) {
-		env.StateDB.AddRefund(params.SuicideRefundGas)
+	if !evm.StateDB.HasSuicided(contract.Address()) {
+		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
 	}
-	return gas
+	return gas, nil
 }
 
-func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize))
+func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	gas, err := memoryGasCost(mem, memorySize)
+	if err != nil {
+		return 0, err
+	}
+	var overflow bool
+	if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
+		return 0, errGasUintOverflow
+	}
 
-	cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
+	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
+	if err != nil {
+		return 0, err
+	}
 	// Replace the stack item with the new gas calculation. This means that
 	// either the original item is left on the stack or the item is replaced by:
 	// (availableGas - gas) * 63 / 64
 	// We replace the stack item so that it's available when the opCall instruction is
 	// called.
-	stack.data[stack.len()-1] = cg
+	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
 
-	return gas.Add(gas, cg)
+	if gas, overflow = math.SafeAdd(gas, cg); overflow {
+		return 0, errGasUintOverflow
+	}
+	return gas, nil
 }
 
-func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return GasFastestStep
+func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return GasFastestStep, nil
 }
 
-func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return GasFastestStep
+func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return GasFastestStep, nil
 }
 
-func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
-	return GasFastestStep
+func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return GasFastestStep, nil
 }
diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cceb8928591618a29377a6556a9cdd6ec1c7296a
--- /dev/null
+++ b/core/vm/gas_table_test.go
@@ -0,0 +1,24 @@
+package vm
+
+import (
+	"math"
+	"testing"
+)
+
+func TestMemoryGasCost(t *testing.T) {
+	size := uint64(math.MaxUint64 - 64)
+	_, err := memoryGasCost(&Memory{}, size)
+	if err != nil {
+		t.Error("didn't expect error:", err)
+	}
+
+	_, err = memoryGasCost(&Memory{}, size+32)
+	if err != nil {
+		t.Error("didn't expect error:", err)
+	}
+
+	_, err = memoryGasCost(&Memory{}, size+33)
+	if err == nil {
+		t.Error("expected error")
+	}
+}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 3b1b06cca1bbe6b991b0565506f51eee9dedcc5f..39e5c058706ffadc9afe8e2b4b827c8dd688ba86 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -27,42 +27,56 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
-func opAdd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+var bigZero = new(big.Int)
+
+func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	stack.push(U256(x.Add(x, y)))
+
+	evm.interpreter.intPool.put(y)
+
 	return nil, nil
 }
 
-func opSub(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	stack.push(U256(x.Sub(x, y)))
+
+	evm.interpreter.intPool.put(y)
+
 	return nil, nil
 }
 
-func opMul(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	stack.push(U256(x.Mul(x, y)))
+
+	evm.interpreter.intPool.put(y)
+
 	return nil, nil
 }
 
-func opDiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	if y.Cmp(common.Big0) != 0 {
 		stack.push(U256(x.Div(x, y)))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(y)
+
 	return nil, nil
 }
 
-func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := S256(stack.pop()), S256(stack.pop())
 	if y.Cmp(common.Big0) == 0 {
 		stack.push(new(big.Int))
 		return nil, nil
 	} else {
 		n := new(big.Int)
-		if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
+		if evm.interpreter.intPool.get().Mul(x, y).Cmp(common.Big0) < 0 {
 			n.SetInt64(-1)
 		} else {
 			n.SetInt64(1)
@@ -73,20 +87,22 @@ func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta
 
 		stack.push(U256(res))
 	}
+	evm.interpreter.intPool.put(y)
 	return nil, nil
 }
 
-func opMod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	if y.Cmp(common.Big0) == 0 {
 		stack.push(new(big.Int))
 	} else {
 		stack.push(U256(x.Mod(x, y)))
 	}
+	evm.interpreter.intPool.put(y)
 	return nil, nil
 }
 
-func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := S256(stack.pop()), S256(stack.pop())
 
 	if y.Cmp(common.Big0) == 0 {
@@ -104,16 +120,20 @@ func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta
 
 		stack.push(U256(res))
 	}
+	evm.interpreter.intPool.put(y)
 	return nil, nil
 }
 
-func opExp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	base, exponent := stack.pop(), stack.pop()
 	stack.push(math.Exp(base, exponent))
+
+	evm.interpreter.intPool.put(base, exponent)
+
 	return nil, nil
 }
 
-func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	back := stack.pop()
 	if back.Cmp(big.NewInt(31)) < 0 {
 		bit := uint(back.Uint64()*8 + 7)
@@ -128,198 +148,231 @@ func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stac
 
 		stack.push(U256(num))
 	}
+
+	evm.interpreter.intPool.put(back)
 	return nil, nil
 }
 
-func opNot(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x := stack.pop()
 	stack.push(U256(x.Not(x)))
 	return nil, nil
 }
 
-func opLt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	if x.Cmp(y) < 0 {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
-func opGt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	if x.Cmp(y) > 0 {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
-func opSlt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := S256(stack.pop()), S256(stack.pop())
 	if x.Cmp(S256(y)) < 0 {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
-func opSgt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := S256(stack.pop()), S256(stack.pop())
 	if x.Cmp(y) > 0 {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
-func opEq(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	if x.Cmp(y) == 0 {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
-func opIszero(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x := stack.pop()
 	if x.Cmp(common.Big0) > 0 {
 		stack.push(new(big.Int))
 	} else {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
+
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
-func opAnd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	stack.push(x.And(x, y))
+
+	evm.interpreter.intPool.put(y)
 	return nil, nil
 }
-func opOr(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	stack.push(x.Or(x, y))
+
+	evm.interpreter.intPool.put(y)
 	return nil, nil
 }
-func opXor(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	stack.push(x.Xor(x, y))
+
+	evm.interpreter.intPool.put(y)
 	return nil, nil
 }
-func opByte(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	th, val := stack.pop(), stack.pop()
 	if th.Cmp(big.NewInt(32)) < 0 {
-		byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
+		byte := evm.interpreter.intPool.get().SetInt64(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
 		stack.push(byte)
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(th, val)
 	return nil, nil
 }
-func opAddmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y, z := stack.pop(), stack.pop(), stack.pop()
-	if z.Cmp(Zero) > 0 {
+	if z.Cmp(bigZero) > 0 {
 		add := x.Add(x, y)
 		add.Mod(add, z)
 		stack.push(U256(add))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(y, z)
 	return nil, nil
 }
-func opMulmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y, z := stack.pop(), stack.pop(), stack.pop()
-	if z.Cmp(Zero) > 0 {
+	if z.Cmp(bigZero) > 0 {
 		mul := x.Mul(x, y)
 		mul.Mod(mul, z)
 		stack.push(U256(mul))
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(y, z)
 	return nil, nil
 }
 
-func opSha3(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	offset, size := stack.pop(), stack.pop()
 	data := memory.Get(offset.Int64(), size.Int64())
 	hash := crypto.Keccak256(data)
 
-	if env.vmConfig.EnablePreimageRecording {
-		env.StateDB.AddPreimage(common.BytesToHash(hash), data)
+	if evm.vmConfig.EnablePreimageRecording {
+		evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
 	}
 
 	stack.push(common.BytesToBig(hash))
+
+	evm.interpreter.intPool.put(offset, size)
 	return nil, nil
 }
 
-func opAddress(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	stack.push(common.Bytes2Big(contract.Address().Bytes()))
 	return nil, nil
 }
 
-func opBalance(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	addr := common.BigToAddress(stack.pop())
-	balance := env.StateDB.GetBalance(addr)
+	balance := evm.StateDB.GetBalance(addr)
 
 	stack.push(new(big.Int).Set(balance))
 	return nil, nil
 }
 
-func opOrigin(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(env.Origin.Big())
+func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.Origin.Big())
 	return nil, nil
 }
 
-func opCaller(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	stack.push(contract.Caller().Big())
 	return nil, nil
 }
 
-func opCallValue(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(new(big.Int).Set(contract.value))
+func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().Set(contract.value))
 	return nil, nil
 }
 
-func opCalldataLoad(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCalldataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32)))
 	return nil, nil
 }
 
-func opCalldataSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(big.NewInt(int64(len(contract.Input))))
+func opCalldataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
 	return nil, nil
 }
 
-func opCalldataCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	var (
 		mOff = stack.pop()
 		cOff = stack.pop()
 		l    = stack.pop()
 	)
 	memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l))
+
+	evm.interpreter.intPool.put(mOff, cOff, l)
 	return nil, nil
 }
 
-func opExtCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	addr := common.BigToAddress(stack.pop())
-	l := big.NewInt(int64(env.StateDB.GetCodeSize(addr)))
-	stack.push(l)
+func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	a := stack.pop()
+
+	addr := common.BigToAddress(a)
+	a.SetInt64(int64(evm.StateDB.GetCodeSize(addr)))
+	stack.push(a)
+
 	return nil, nil
 }
 
-func opCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	l := big.NewInt(int64(len(contract.Code)))
+func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
 	stack.push(l)
 	return nil, nil
 }
 
-func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	var (
 		mOff = stack.pop()
 		cOff = stack.pop()
@@ -328,113 +381,129 @@ func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack
 	codeCopy := getData(contract.Code, cOff, l)
 
 	memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
+
+	evm.interpreter.intPool.put(mOff, cOff, l)
 	return nil, nil
 }
 
-func opExtCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	var (
 		addr = common.BigToAddress(stack.pop())
 		mOff = stack.pop()
 		cOff = stack.pop()
 		l    = stack.pop()
 	)
-	codeCopy := getData(env.StateDB.GetCode(addr), cOff, l)
+	codeCopy := getData(evm.StateDB.GetCode(addr), cOff, l)
 
 	memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
+
+	evm.interpreter.intPool.put(mOff, cOff, l)
+
 	return nil, nil
 }
 
-func opGasprice(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(new(big.Int).Set(env.GasPrice))
+func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice))
 	return nil, nil
 }
 
-func opBlockhash(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	num := stack.pop()
 
-	n := new(big.Int).Sub(env.BlockNumber, common.Big257)
-	if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber) < 0 {
-		stack.push(env.GetHash(num.Uint64()).Big())
+	n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257)
+	if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
+		stack.push(evm.GetHash(num.Uint64()).Big())
 	} else {
 		stack.push(new(big.Int))
 	}
+
+	evm.interpreter.intPool.put(num, n)
 	return nil, nil
 }
 
-func opCoinbase(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(env.Coinbase.Big())
+func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.Coinbase.Big())
 	return nil, nil
 }
 
-func opTimestamp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(U256(new(big.Int).Set(env.Time)))
+func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(U256(new(big.Int).Set(evm.Time)))
 	return nil, nil
 }
 
-func opNumber(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(U256(new(big.Int).Set(env.BlockNumber)))
+func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(U256(new(big.Int).Set(evm.BlockNumber)))
 	return nil, nil
 }
 
-func opDifficulty(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(U256(new(big.Int).Set(env.Difficulty)))
+func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(U256(new(big.Int).Set(evm.Difficulty)))
 	return nil, nil
 }
 
-func opGasLimit(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(U256(new(big.Int).Set(env.GasLimit)))
+func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(U256(new(big.Int).Set(evm.GasLimit)))
 	return nil, nil
 }
 
-func opPop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.pop()
+func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	evm.interpreter.intPool.put(stack.pop())
 	return nil, nil
 }
 
-func opMload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	offset := stack.pop()
 	val := common.BigD(memory.Get(offset.Int64(), 32))
 	stack.push(val)
+
+	evm.interpreter.intPool.put(offset)
 	return nil, nil
 }
 
-func opMstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	// pop value of the stack
 	mStart, val := stack.pop(), stack.pop()
 	memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
+
+	evm.interpreter.intPool.put(mStart, val)
 	return nil, nil
 }
 
-func opMstore8(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	off, val := stack.pop().Int64(), stack.pop().Int64()
 	memory.store[off] = byte(val & 0xff)
+
 	return nil, nil
 }
 
-func opSload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	loc := common.BigToHash(stack.pop())
-	val := env.StateDB.GetState(contract.Address(), loc).Big()
+	val := evm.StateDB.GetState(contract.Address(), loc).Big()
 	stack.push(val)
 	return nil, nil
 }
 
-func opSstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	loc := common.BigToHash(stack.pop())
 	val := stack.pop()
-	env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
+	evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
+
+	evm.interpreter.intPool.put(val)
 	return nil, nil
 }
 
-func opJump(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	pos := stack.pop()
 	if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
 		nop := contract.GetOp(pos.Uint64())
 		return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
 	}
 	*pc = pos.Uint64()
+
+	evm.interpreter.intPool.put(pos)
 	return nil, nil
 }
-func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	pos, cond := stack.pop(), stack.pop()
 	if cond.Cmp(common.BigTrue) >= 0 {
 		if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
@@ -445,57 +514,62 @@ func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *St
 	} else {
 		*pc++
 	}
+
+	evm.interpreter.intPool.put(pos, cond)
 	return nil, nil
 }
-func opJumpdest(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	return nil, nil
 }
 
-func opPc(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(new(big.Int).SetUint64(*pc))
+func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().SetUint64(*pc))
 	return nil, nil
 }
 
-func opMsize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(big.NewInt(int64(memory.Len())))
+func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len())))
 	return nil, nil
 }
 
-func opGas(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(new(big.Int).Set(contract.Gas))
+func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas))
 	return nil, nil
 }
 
-func opCreate(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	var (
 		value        = stack.pop()
 		offset, size = stack.pop(), stack.pop()
 		input        = memory.Get(offset.Int64(), size.Int64())
-		gas          = new(big.Int).Set(contract.Gas)
+		gas          = contract.Gas
 	)
-	if env.ChainConfig().IsEIP150(env.BlockNumber) {
-		gas.Div(gas, n64)
-		gas = gas.Sub(contract.Gas, gas)
+	if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
+		gas -= gas / 64
 	}
 
 	contract.UseGas(gas)
-	_, addr, suberr := env.Create(contract, input, gas, value)
+	_, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
 	// Push item on the stack based on the returned error. If the ruleset is
 	// homestead we must check for CodeStoreOutOfGasError (homestead only
 	// rule) and treat as an error, if the ruleset is frontier we must
 	// ignore this error and pretend the operation was successful.
-	if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
+	if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
 		stack.push(new(big.Int))
 	} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
 		stack.push(new(big.Int))
 	} else {
 		stack.push(addr.Big())
 	}
+	contract.Gas += returnGas
+
+	evm.interpreter.intPool.put(value, offset, size)
+
 	return nil, nil
 }
 
-func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	gas := stack.pop()
+func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	gas := stack.pop().Uint64()
 	// pop gas and value of the stack.
 	addr, value := stack.pop(), stack.pop()
 	value = U256(value)
@@ -509,25 +583,26 @@ func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta
 	// Get the arguments from the memory
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
 
-	if len(value.Bytes()) > 0 {
-		gas.Add(gas, params.CallStipend)
+	if value.BitLen() > 0 {
+		gas += params.CallStipend
 	}
 
-	ret, err := env.Call(contract, address, args, gas, value)
-
+	ret, returnGas, err := evm.Call(contract, address, args, gas, value)
 	if err != nil {
 		stack.push(new(big.Int))
-
 	} else {
 		stack.push(big.NewInt(1))
 
 		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
 	}
+	contract.Gas += returnGas
+
+	evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
 	return nil, nil
 }
 
-func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	gas := stack.pop()
+func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	gas := stack.pop().Uint64()
 	// pop gas and value of the stack.
 	addr, value := stack.pop(), stack.pop()
 	value = U256(value)
@@ -541,12 +616,11 @@ func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack
 	// Get the arguments from the memory
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
 
-	if len(value.Bytes()) > 0 {
-		gas.Add(gas, params.CallStipend)
+	if value.BitLen() > 0 {
+		gas += params.CallStipend
 	}
 
-	ret, err := env.CallCode(contract, address, args, gas, value)
-
+	ret, returnGas, err := evm.CallCode(contract, address, args, gas, value)
 	if err != nil {
 		stack.push(new(big.Int))
 
@@ -555,46 +629,54 @@ func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack
 
 		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
 	}
+	contract.Gas += returnGas
+
+	evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
 	return nil, nil
 }
 
-func opDelegateCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	// if not homestead return an error. DELEGATECALL is not supported
 	// during pre-homestead.
-	if !env.ChainConfig().IsHomestead(env.BlockNumber) {
+	if !evm.ChainConfig().IsHomestead(evm.BlockNumber) {
 		return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL)
 	}
 
-	gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+	gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
 
 	toAddr := common.BigToAddress(to)
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
-	ret, err := env.DelegateCall(contract, toAddr, args, gas)
+
+	ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
 	if err != nil {
 		stack.push(new(big.Int))
 	} else {
 		stack.push(big.NewInt(1))
 		memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
 	}
+	contract.Gas += returnGas
+
+	evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize)
 	return nil, nil
 }
 
-func opReturn(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	offset, size := stack.pop(), stack.pop()
 	ret := memory.GetPtr(offset.Int64(), size.Int64())
 
+	evm.interpreter.intPool.put(offset, size)
 	return ret, nil
 }
 
-func opStop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	return nil, nil
 }
 
-func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	balance := env.StateDB.GetBalance(contract.Address())
-	env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
+func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	balance := evm.StateDB.GetBalance(contract.Address())
+	evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
 
-	env.StateDB.Suicide(contract.Address())
+	evm.StateDB.Suicide(contract.Address())
 
 	return nil, nil
 }
@@ -603,7 +685,7 @@ func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *
 
 // make log instruction function
 func makeLog(size int) executionFunc {
-	return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 		topics := make([]common.Hash, size)
 		mStart, mSize := stack.pop(), stack.pop()
 		for i := 0; i < size; i++ {
@@ -611,22 +693,24 @@ func makeLog(size int) executionFunc {
 		}
 
 		d := memory.Get(mStart.Int64(), mSize.Int64())
-		env.StateDB.AddLog(&types.Log{
+		evm.StateDB.AddLog(&types.Log{
 			Address: contract.Address(),
 			Topics:  topics,
 			Data:    d,
 			// This is a non-consensus field, but assigned here because
 			// core/state doesn't know the current block number.
-			BlockNumber: env.BlockNumber.Uint64(),
+			BlockNumber: evm.BlockNumber.Uint64(),
 		})
+
+		evm.interpreter.intPool.put(mStart, mSize)
 		return nil, nil
 	}
 }
 
 // make push instruction function
 func makePush(size uint64, bsize *big.Int) executionFunc {
-	return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-		byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize)
+	return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+		byts := getData(contract.Code, evm.interpreter.intPool.get().SetUint64(*pc+1), bsize)
 		stack.push(common.Bytes2Big(byts))
 		*pc += size
 		return nil, nil
@@ -635,7 +719,7 @@ func makePush(size uint64, bsize *big.Int) executionFunc {
 
 // make push instruction function
 func makeDup(size int64) executionFunc {
-	return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 		stack.dup(int(size))
 		return nil, nil
 	}
@@ -645,7 +729,7 @@ func makeDup(size int64) executionFunc {
 func makeSwap(size int64) executionFunc {
 	// switch n + 1 otherwise n would be swapped with n
 	size += 1
-	return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 		stack.swap(int(size))
 		return nil, nil
 	}
diff --git a/core/vm/int_pool_verifier.go b/core/vm/int_pool_verifier.go
new file mode 100644
index 0000000000000000000000000000000000000000..61c83ba7e9cd196beb8903cee7d29d161cc928aa
--- /dev/null
+++ b/core/vm/int_pool_verifier.go
@@ -0,0 +1,15 @@
+// +build VERIFY_EVM_INTEGER_POOL
+
+package vm
+
+import "fmt"
+
+const verifyPool = true
+
+func verifyIntegerPool(ip *intPool) {
+	for i, item := range ip.pool.data {
+		if item.Cmp(checkVal) != 0 {
+			panic(fmt.Sprintf("%d'th item failed aggressive pool check. Value was modified", i))
+		}
+	}
+}
diff --git a/core/vm/int_pool_verifier_empty.go b/core/vm/int_pool_verifier_empty.go
new file mode 100644
index 0000000000000000000000000000000000000000..982f8c6dd5adc5bfadb2b67124baf1a0f7bd6389
--- /dev/null
+++ b/core/vm/int_pool_verifier_empty.go
@@ -0,0 +1,7 @@
+// +build !VERIFY_EVM_INTEGER_POOL
+
+package vm
+
+const verifyPool = false
+
+func verifyIntegerPool(ip *intPool) {}
diff --git a/core/vm/vm.go b/core/vm/interpreter.go
similarity index 80%
rename from core/vm/vm.go
rename to core/vm/interpreter.go
index 05886a86397d4d24992ddc16ca32a1e6a58b42ef..46c6befefcb12078f2bca9e6ab6af278d471d912 100644
--- a/core/vm/vm.go
+++ b/core/vm/interpreter.go
@@ -23,6 +23,7 @@ import (
 	"time"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
@@ -60,6 +61,7 @@ type Interpreter struct {
 	env      *EVM
 	cfg      Config
 	gasTable params.GasTable
+	intPool  *intPool
 }
 
 // NewInterpreter returns a new instance of the Interpreter.
@@ -75,6 +77,7 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter {
 		env:      env,
 		cfg:      cfg,
 		gasTable: env.ChainConfig().GasTable(env.BlockNumber),
+		intPool:  newIntPool(),
 	}
 }
 
@@ -106,14 +109,18 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
 		// For optimisation reason we're using uint64 as the program counter.
 		// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible.
 		pc   = uint64(0) // program counter
-		cost *big.Int
+		cost uint64
 	)
 	contract.Input = input
 
 	// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
 	defer func() {
 		if err != nil && evm.cfg.Debug {
-			evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
+			// XXX For debugging
+			//fmt.Printf("%04d: %8v    cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err)
+			// TODO update the tracer
+			g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost)
+			evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err)
 		}
 	}()
 
@@ -147,34 +154,47 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e
 			return nil, err
 		}
 
-		var memorySize *big.Int
+		var memorySize uint64
 		// calculate the new memory size and expand the memory to fit
 		// the operation
 		if operation.memorySize != nil {
-			memorySize = operation.memorySize(stack)
+			memSize, overflow := bigUint64(operation.memorySize(stack))
+			if overflow {
+				return nil, errGasUintOverflow
+			}
 			// memory is expanded in words of 32 bytes. Gas
 			// is also calculated in words.
-			memorySize.Mul(toWordSize(memorySize), big.NewInt(32))
+			if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
+				return nil, errGasUintOverflow
+			}
 		}
 
 		if !evm.cfg.DisableGasMetering {
 			// consume the gas and return an error if not enough gas is available.
 			// cost is explicitly set so that the capture state defer method cas get the proper cost
-			cost = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
-			if !contract.UseGas(cost) {
+			cost, err = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize)
+			if err != nil || !contract.UseGas(cost) {
 				return nil, ErrOutOfGas
 			}
 		}
-		if memorySize != nil {
-			mem.Resize(memorySize.Uint64())
+		if memorySize > 0 {
+			mem.Resize(memorySize)
 		}
 
 		if evm.cfg.Debug {
-			evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err)
+			g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost)
+			evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err)
 		}
+		// XXX For debugging
+		//fmt.Printf("%04d: %8v    cost = %-8d stack = %-8d\n", pc, op, cost, stack.len())
 
 		// execute the operation
 		res, err := operation.execute(&pc, evm.env, contract, mem, stack)
+		// verifyPool is a build flag. Pool verification makes sure the integrity
+		// of the integer pool by comparing values to a default value.
+		if verifyPool {
+			verifyIntegerPool(evm.intPool)
+		}
 		switch {
 		case err != nil:
 			return nil, err
diff --git a/core/vm/virtual_machine.go b/core/vm/intpool.go
similarity index 53%
rename from core/vm/virtual_machine.go
rename to core/vm/intpool.go
index 62910888464b22d412fe87f1857ea4ec548b7178..4f1228e14976586829cba0bf50dfb7f680c30261 100644
--- a/core/vm/virtual_machine.go
+++ b/core/vm/intpool.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The go-ethereum Authors
+// Copyright 2017 The go-ethereum Authors
 // This file is part of the go-ethereum library.
 //
 // The go-ethereum library is free software: you can redistribute it and/or modify
@@ -16,7 +16,34 @@
 
 package vm
 
-// VirtualMachine is an EVM interface
-type VirtualMachine interface {
-	Run(*Contract, []byte) ([]byte, error)
+import "math/big"
+
+var checkVal = big.NewInt(-42)
+
+// intPool is a pool of big integers that
+// can be reused for all big.Int operations.
+type intPool struct {
+	pool *Stack
+}
+
+func newIntPool() *intPool {
+	return &intPool{pool: newstack()}
+}
+
+func (p *intPool) get() *big.Int {
+	if p.pool.len() > 0 {
+		return p.pool.pop()
+	}
+	return new(big.Int)
+}
+func (p *intPool) put(is ...*big.Int) {
+	for _, i := range is {
+		// verifyPool is a build flag. Pool verification makes sure the integrity
+		// of the integer pool by comparing values to a default value.
+		if verifyPool {
+			i.Set(checkVal)
+		}
+
+		p.pool.push(i)
+	}
 }
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 073798274593dde4ff337a0bf717ae22ca8bed33..ed30100ac149e299b568af9bba68a24731dbfe36 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -17,6 +17,7 @@
 package vm
 
 import (
+	"errors"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/params"
@@ -24,11 +25,13 @@ import (
 
 type (
 	executionFunc       func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
-	gasFunc             func(params.GasTable, *EVM, *Contract, *Stack, *Memory, *big.Int) *big.Int
+	gasFunc             func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
 	stackValidationFunc func(*Stack) error
 	memorySizeFunc      func(*Stack) *big.Int
 )
 
+var errGasUintOverflow = errors.New("gas uint64 overflow")
+
 type operation struct {
 	// op is the operation function
 	execute executionFunc
@@ -54,7 +57,7 @@ func NewJumpTable() [256]operation {
 	return [256]operation{
 		STOP: {
 			execute:       opStop,
-			gasCost:       constGasFunc(new(big.Int)),
+			gasCost:       constGasFunc(0),
 			validateStack: makeStackFunc(0, 0),
 			halts:         true,
 			valid:         true,
@@ -62,139 +65,139 @@ func NewJumpTable() [256]operation {
 		ADD: {
 			execute:       opAdd,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		MUL: {
 			execute:       opMul,
 			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SUB: {
 			execute:       opSub,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		DIV: {
 			execute:       opDiv,
 			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SDIV: {
 			execute:       opSdiv,
 			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		MOD: {
 			execute:       opMod,
 			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SMOD: {
 			execute:       opSmod,
 			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		ADDMOD: {
 			execute:       opAddmod,
 			gasCost:       constGasFunc(GasMidStep),
-			validateStack: makeStackFunc(3, -2),
+			validateStack: makeStackFunc(3, 1),
 			valid:         true,
 		},
 		MULMOD: {
 			execute:       opMulmod,
 			gasCost:       constGasFunc(GasMidStep),
-			validateStack: makeStackFunc(3, -2),
+			validateStack: makeStackFunc(3, 1),
 			valid:         true,
 		},
 		EXP: {
 			execute:       opExp,
 			gasCost:       gasExp,
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SIGNEXTEND: {
 			execute:       opSignExtend,
 			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		LT: {
 			execute:       opLt,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		GT: {
 			execute:       opGt,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SLT: {
 			execute:       opSlt,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SGT: {
 			execute:       opSgt,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		EQ: {
 			execute:       opEq,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		ISZERO: {
 			execute:       opIszero,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		AND: {
 			execute:       opAnd,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		XOR: {
 			execute:       opXor,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		OR: {
 			execute:       opOr,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		NOT: {
 			execute:       opNot,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		BYTE: {
 			execute:       opByte,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			valid:         true,
 		},
 		SHA3: {
 			execute:       opSha3,
 			gasCost:       gasSha3,
-			validateStack: makeStackFunc(2, -1),
+			validateStack: makeStackFunc(2, 1),
 			memorySize:    memorySha3,
 			valid:         true,
 		},
@@ -207,7 +210,7 @@ func NewJumpTable() [256]operation {
 		BALANCE: {
 			execute:       opBalance,
 			gasCost:       gasBalance,
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		ORIGIN: {
@@ -231,7 +234,7 @@ func NewJumpTable() [256]operation {
 		CALLDATALOAD: {
 			execute:       opCalldataLoad,
 			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		CALLDATASIZE: {
@@ -243,7 +246,7 @@ func NewJumpTable() [256]operation {
 		CALLDATACOPY: {
 			execute:       opCalldataCopy,
 			gasCost:       gasCalldataCopy,
-			validateStack: makeStackFunc(3, -3),
+			validateStack: makeStackFunc(3, 0),
 			memorySize:    memoryCalldataCopy,
 			valid:         true,
 		},
@@ -256,7 +259,7 @@ func NewJumpTable() [256]operation {
 		CODECOPY: {
 			execute:       opCodeCopy,
 			gasCost:       gasCodeCopy,
-			validateStack: makeStackFunc(3, -3),
+			validateStack: makeStackFunc(3, 0),
 			memorySize:    memoryCodeCopy,
 			valid:         true,
 		},
@@ -269,20 +272,20 @@ func NewJumpTable() [256]operation {
 		EXTCODESIZE: {
 			execute:       opExtCodeSize,
 			gasCost:       gasExtCodeSize,
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		EXTCODECOPY: {
 			execute:       opExtCodeCopy,
 			gasCost:       gasExtCodeCopy,
-			validateStack: makeStackFunc(4, -4),
+			validateStack: makeStackFunc(4, 0),
 			memorySize:    memoryExtCodeCopy,
 			valid:         true,
 		},
 		BLOCKHASH: {
 			execute:       opBlockhash,
 			gasCost:       constGasFunc(GasExtStep),
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		COINBASE: {
@@ -318,20 +321,20 @@ func NewJumpTable() [256]operation {
 		POP: {
 			execute:       opPop,
 			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(1, -1),
+			validateStack: makeStackFunc(1, 0),
 			valid:         true,
 		},
 		MLOAD: {
 			execute:       opMload,
 			gasCost:       gasMLoad,
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			memorySize:    memoryMLoad,
 			valid:         true,
 		},
 		MSTORE: {
 			execute:       opMstore,
 			gasCost:       gasMStore,
-			validateStack: makeStackFunc(2, -2),
+			validateStack: makeStackFunc(2, 0),
 			memorySize:    memoryMStore,
 			valid:         true,
 		},
@@ -339,33 +342,33 @@ func NewJumpTable() [256]operation {
 			execute:       opMstore8,
 			gasCost:       gasMStore8,
 			memorySize:    memoryMStore8,
-			validateStack: makeStackFunc(2, -2),
+			validateStack: makeStackFunc(2, 0),
 
 			valid: true,
 		},
 		SLOAD: {
 			execute:       opSload,
 			gasCost:       gasSLoad,
-			validateStack: makeStackFunc(1, 0),
+			validateStack: makeStackFunc(1, 1),
 			valid:         true,
 		},
 		SSTORE: {
 			execute:       opSstore,
 			gasCost:       gasSStore,
-			validateStack: makeStackFunc(2, -2),
+			validateStack: makeStackFunc(2, 0),
 			valid:         true,
 		},
 		JUMP: {
 			execute:       opJump,
 			gasCost:       constGasFunc(GasMidStep),
-			validateStack: makeStackFunc(1, -1),
+			validateStack: makeStackFunc(1, 0),
 			jumps:         true,
 			valid:         true,
 		},
 		JUMPI: {
 			execute:       opJumpi,
 			gasCost:       constGasFunc(GasSlowStep),
-			validateStack: makeStackFunc(2, -2),
+			validateStack: makeStackFunc(2, 0),
 			jumps:         true,
 			valid:         true,
 		},
@@ -780,63 +783,63 @@ func NewJumpTable() [256]operation {
 		LOG0: {
 			execute:       makeLog(0),
 			gasCost:       makeGasLog(0),
-			validateStack: makeStackFunc(2, -2),
+			validateStack: makeStackFunc(2, 0),
 			memorySize:    memoryLog,
 			valid:         true,
 		},
 		LOG1: {
 			execute:       makeLog(1),
 			gasCost:       makeGasLog(1),
-			validateStack: makeStackFunc(3, -3),
+			validateStack: makeStackFunc(3, 0),
 			memorySize:    memoryLog,
 			valid:         true,
 		},
 		LOG2: {
 			execute:       makeLog(2),
 			gasCost:       makeGasLog(2),
-			validateStack: makeStackFunc(4, -4),
+			validateStack: makeStackFunc(4, 0),
 			memorySize:    memoryLog,
 			valid:         true,
 		},
 		LOG3: {
 			execute:       makeLog(3),
 			gasCost:       makeGasLog(3),
-			validateStack: makeStackFunc(5, -5),
+			validateStack: makeStackFunc(5, 0),
 			memorySize:    memoryLog,
 			valid:         true,
 		},
 		LOG4: {
 			execute:       makeLog(4),
 			gasCost:       makeGasLog(4),
-			validateStack: makeStackFunc(6, -6),
+			validateStack: makeStackFunc(6, 0),
 			memorySize:    memoryLog,
 			valid:         true,
 		},
 		CREATE: {
 			execute:       opCreate,
 			gasCost:       gasCreate,
-			validateStack: makeStackFunc(3, -2),
+			validateStack: makeStackFunc(3, 1),
 			memorySize:    memoryCreate,
 			valid:         true,
 		},
 		CALL: {
 			execute:       opCall,
 			gasCost:       gasCall,
-			validateStack: makeStackFunc(7, -6),
+			validateStack: makeStackFunc(7, 1),
 			memorySize:    memoryCall,
 			valid:         true,
 		},
 		CALLCODE: {
 			execute:       opCallCode,
 			gasCost:       gasCallCode,
-			validateStack: makeStackFunc(7, -6),
+			validateStack: makeStackFunc(7, 1),
 			memorySize:    memoryCall,
 			valid:         true,
 		},
 		RETURN: {
 			execute:       opReturn,
 			gasCost:       gasReturn,
-			validateStack: makeStackFunc(2, -2),
+			validateStack: makeStackFunc(2, 0),
 			memorySize:    memoryReturn,
 			halts:         true,
 			valid:         true,
@@ -844,14 +847,14 @@ func NewJumpTable() [256]operation {
 		DELEGATECALL: {
 			execute:       opDelegateCall,
 			gasCost:       gasDelegateCall,
-			validateStack: makeStackFunc(6, -5),
+			validateStack: makeStackFunc(6, 1),
 			memorySize:    memoryDelegateCall,
 			valid:         true,
 		},
 		SELFDESTRUCT: {
 			execute:       opSuicide,
 			gasCost:       gasSuicide,
-			validateStack: makeStackFunc(1, -1),
+			validateStack: makeStackFunc(1, 0),
 			halts:         true,
 			valid:         true,
 		},
diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go
index 1d0bd96fad2115ece493f7e25d154c4f39f42117..ca60cba43e8fa763fc6eafd8ad6d39d974354c25 100644
--- a/core/vm/logger_test.go
+++ b/core/vm/logger_test.go
@@ -56,7 +56,7 @@ func TestStoreCapture(t *testing.T) {
 		logger   = NewStructLogger(nil)
 		mem      = NewMemory()
 		stack    = newstack()
-		contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), new(big.Int))
+		contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
 	)
 	stack.push(big.NewInt(1))
 	stack.push(big.NewInt(0))
@@ -78,7 +78,7 @@ func TestStorageCapture(t *testing.T) {
 	t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it")
 	var (
 		ref      = &dummyContractRef{}
-		contract = NewContract(ref, ref, new(big.Int), new(big.Int))
+		contract = NewContract(ref, ref, new(big.Int), 0)
 		env      = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
 		logger   = NewStructLogger(nil)
 		mem      = NewMemory()
diff --git a/core/vm/memory.go b/core/vm/memory.go
index d01188417377e8a19e562ef00bed0be9da0ca868..99a84d2271584453dc7b27b58dbe38446e70cae6 100644
--- a/core/vm/memory.go
+++ b/core/vm/memory.go
@@ -20,11 +20,12 @@ import "fmt"
 
 // Memory implements a simple memory model for the ethereum virtual machine.
 type Memory struct {
-	store []byte
+	store       []byte
+	lastGasCost uint64
 }
 
 func NewMemory() *Memory {
-	return &Memory{nil}
+	return &Memory{}
 }
 
 // Set sets offset + size to value
diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go
index a25c6d71c6359fd1381a397986069d18f592d636..9aa88e6690de811b9f324c9bdc4125ade8e37924 100644
--- a/core/vm/runtime/env.go
+++ b/core/vm/runtime/env.go
@@ -36,7 +36,7 @@ func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM {
 		BlockNumber: cfg.BlockNumber,
 		Time:        cfg.Time,
 		Difficulty:  cfg.Difficulty,
-		GasLimit:    cfg.GasLimit,
+		GasLimit:    new(big.Int).SetUint64(cfg.GasLimit),
 		GasPrice:    new(big.Int),
 	}
 
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index b5adb982c363d38f1de1afe2829dd9b1cb6fe7af..cf46603dbd895c6dd0f02b5dc6fc3b51a1b57aa2 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -17,6 +17,7 @@
 package runtime
 
 import (
+	"math"
 	"math/big"
 	"time"
 
@@ -37,7 +38,7 @@ type Config struct {
 	Coinbase    common.Address
 	BlockNumber *big.Int
 	Time        *big.Int
-	GasLimit    *big.Int
+	GasLimit    uint64
 	GasPrice    *big.Int
 	Value       *big.Int
 	DisableJit  bool // "disable" so it's enabled by default
@@ -68,8 +69,8 @@ func setDefaults(cfg *Config) {
 	if cfg.Time == nil {
 		cfg.Time = big.NewInt(time.Now().Unix())
 	}
-	if cfg.GasLimit == nil {
-		cfg.GasLimit = new(big.Int).Set(common.MaxBig)
+	if cfg.GasLimit == 0 {
+		cfg.GasLimit = math.MaxUint64
 	}
 	if cfg.GasPrice == nil {
 		cfg.GasPrice = new(big.Int)
@@ -112,7 +113,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
 	receiver.SetCode(crypto.Keccak256Hash(code), code)
 
 	// Call the code with the given configuration.
-	ret, err := vmenv.Call(
+	ret, _, err := vmenv.Call(
 		sender,
 		receiver.Address(),
 		input,
@@ -140,12 +141,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
 	)
 
 	// Call the code with the given configuration.
-	return vmenv.Create(
+	code, address, _, err := vmenv.Create(
 		sender,
 		input,
 		cfg.GasLimit,
 		cfg.Value,
 	)
+	return code, address, err
 }
 
 // Call executes the code given by the contract's address. It will return the
@@ -160,7 +162,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
 
 	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
 	// Call the code with the given configuration.
-	ret, err := vmenv.Call(
+	ret, _, err := vmenv.Call(
 		sender,
 		address,
 		input,
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index 1e618b688af4ba89172300d40543a94f44dbf610..8ad74a89ab201691c81e249314b91847fd4ef4ac 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -39,8 +39,8 @@ func TestDefaults(t *testing.T) {
 	if cfg.Time == nil {
 		t.Error("expected time to be non nil")
 	}
-	if cfg.GasLimit == nil {
-		t.Error("expected time to be non nil")
+	if cfg.GasLimit == 0 {
+		t.Error("didn't expect gaslimit to be zero")
 	}
 	if cfg.GasPrice == nil {
 		t.Error("expected time to be non nil")
diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go
index eed8805f23662338dde148155232fbd9a09fc4b6..ddc41fed23c5d4c7c94bfd655c2ead3131b9b369 100644
--- a/core/vm/stack_table.go
+++ b/core/vm/stack_table.go
@@ -6,13 +6,13 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
-func makeStackFunc(pop, diff int) stackValidationFunc {
+func makeStackFunc(pop, push int) stackValidationFunc {
 	return func(stack *Stack) error {
 		if err := stack.require(pop); err != nil {
 			return err
 		}
 
-		if int64(stack.len()+diff) > params.StackLimit.Int64() {
+		if stack.len()+push-pop > int(params.StackLimit) {
 			return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
 		}
 		return nil
@@ -20,9 +20,9 @@ func makeStackFunc(pop, diff int) stackValidationFunc {
 }
 
 func makeDupStackFunc(n int) stackValidationFunc {
-	return makeStackFunc(n, 1)
+	return makeStackFunc(n, n+1)
 }
 
 func makeSwapStackFunc(n int) stackValidationFunc {
-	return makeStackFunc(n, 0)
+	return makeStackFunc(n, n)
 }
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 1174588ea7e6c11c46d5dc1a11be220123a6c684..72ed76cc4a6681756f16ba08fbcce6957dcb361a 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -106,14 +106,14 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
 	return b.eth.blockchain.GetTdByHash(blockHash)
 }
 
-func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) {
+func (b *EthApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
 	statedb := state.(EthApiState).state
 	from := statedb.GetOrNewStateObject(msg.From())
 	from.SetBalance(common.MaxBig)
 	vmError := func() error { return nil }
 
 	context := core.NewEVMContext(msg, header, b.eth.BlockChain())
-	return vm.NewEVM(context, statedb, b.eth.chainConfig, vm.Config{}), vmError, nil
+	return vm.NewEVM(context, statedb, b.eth.chainConfig, vmCfg), vmError, nil
 }
 
 func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
diff --git a/eth/bind.go b/eth/bind.go
index a9864b3677c00a8ddcc35992abd07802463af84f..2ee9f2bf7bc22bc72ea71cc84bb01718fb384bcb 100644
--- a/eth/bind.go
+++ b/eth/bind.go
@@ -69,7 +69,7 @@ func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Add
 // against the pending block, not the stable head of the chain.
 func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) {
 	out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum))
-	return common.FromHex(out), err
+	return out, err
 }
 
 // ContractCall implements bind.ContractCaller executing an Ethereum contract
@@ -77,7 +77,7 @@ func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg
 // against the pending block, not the stable head of the chain.
 func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
 	out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber)
-	return common.FromHex(out), err
+	return out, err
 }
 
 func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs {
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 9be4bd87d0f8304418f2ac3e6204c3ce1d4928fd..7e2952439a966aa3d3c50494805b8ddba205ab8d 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -49,12 +49,12 @@ var (
 	MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request
 	MaxStateFetch   = 384 // Amount of node state values to allow fetching per request
 
-	MaxForkAncestry  = 3 * params.EpochDuration.Uint64() // Maximum chain reorganisation
-	rttMinEstimate   = 2 * time.Second                   // Minimum round-trip time to target for download requests
-	rttMaxEstimate   = 20 * time.Second                  // Maximum rount-trip time to target for download requests
-	rttMinConfidence = 0.1                               // Worse confidence factor in our estimated RTT value
-	ttlScaling       = 3                                 // Constant scaling factor for RTT -> TTL conversion
-	ttlLimit         = time.Minute                       // Maximum TTL allowance to prevent reaching crazy timeouts
+	MaxForkAncestry  = 3 * params.EpochDuration // Maximum chain reorganisation
+	rttMinEstimate   = 2 * time.Second          // Minimum round-trip time to target for download requests
+	rttMaxEstimate   = 20 * time.Second         // Maximum rount-trip time to target for download requests
+	rttMinConfidence = 0.1                      // Worse confidence factor in our estimated RTT value
+	ttlScaling       = 3                        // Constant scaling factor for RTT -> TTL conversion
+	ttlLimit         = time.Minute              // Maximum TTL allowance to prevent reaching crazy timeouts
 
 	qosTuningPeers   = 5    // Number of peers to tune based on (best peers)
 	qosConfidenceCap = 10   // Number of peers above which not to modify RTT confidence
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index b156c471df9349242e95bdf817ca4eb8f3dea001..a9ea797eacc368c23d85be0b0a9ca7248c9c3183 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -119,7 +119,7 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren
 		// If the block number is multiple of 3, send a bonus transaction to the miner
 		if parent == dl.genesis && i%3 == 0 {
 			signer := types.MakeSigner(params.TestChainConfig, block.Number())
-			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey)
+			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey)
 			if err != nil {
 				panic(err)
 			}
diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go
index 2e28541ab3f67ab3096fb9edc38dea4e667c4a88..7a94241c66137443b835e2d7131a30c141b0fa60 100644
--- a/eth/fetcher/fetcher_test.go
+++ b/eth/fetcher/fetcher_test.go
@@ -51,7 +51,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common
 		// If the block number is multiple of 3, send a bonus transaction to the miner
 		if parent == genesis && i%3 == 0 {
 			signer := types.MakeSigner(params.TestChainConfig, block.Number())
-			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey)
+			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey)
 			if err != nil {
 				panic(err)
 			}
diff --git a/eth/handler_test.go b/eth/handler_test.go
index 8a5d7173b339f65f05f5dadd511fbe710223342c..03d5404a4d71a609a523fcd096a238e735f03de2 100644
--- a/eth/handler_test.go
+++ b/eth/handler_test.go
@@ -36,6 +36,8 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
+var bigTxGas = new(big.Int).SetUint64(params.TxGas)
+
 // Tests that protocol versions and modes of operations are matched up properly.
 func TestProtocolCompatibility(t *testing.T) {
 	// Define the compatibility chart
@@ -312,13 +314,13 @@ func testGetNodeData(t *testing.T, protocol int) {
 		switch i {
 		case 0:
 			// In block 1, the test bank sends account #1 some ether.
-			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
 			block.AddTx(tx)
 		case 1:
 			// In block 2, the test bank sends some more ether to account #1.
 			// acc1Addr passes it on to account #2.
-			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
-			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
+			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
 			block.AddTx(tx1)
 			block.AddTx(tx2)
 		case 2:
@@ -404,13 +406,13 @@ func testGetReceipt(t *testing.T, protocol int) {
 		switch i {
 		case 0:
 			// In block 1, the test bank sends account #1 some ether.
-			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
 			block.AddTx(tx)
 		case 1:
 			// In block 2, the test bank sends some more ether to account #1.
 			// acc1Addr passes it on to account #2.
-			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
-			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
+			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
 			block.AddTx(tx1)
 			block.AddTx(tx2)
 		case 2:
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index cf82cc86657f2b14d520ecd970fe461aa570748f..6b11cbc97d521f07e327cec6a12dd5eec4327390 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -48,6 +48,8 @@ import (
 
 const defaultGas = 90000
 
+var emptyHex = "0x"
+
 // PublicEthereumAPI provides an API to access Ethereum related information.
 // It offers only methods that operate on public data that is freely available to anyone.
 type PublicEthereumAPI struct {
@@ -574,12 +576,12 @@ type CallArgs struct {
 	Data     hexutil.Bytes   `json:"data"`
 }
 
-func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) {
+func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) {
 	defer func(start time.Time) { glog.V(logger.Debug).Infof("call took %v", time.Since(start)) }(time.Now())
 
 	state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
 	if state == nil || err != nil {
-		return "0x", common.Big0, err
+		return nil, common.Big0, err
 	}
 	// Set sender address or use a default if none specified
 	addr := args.From
@@ -589,40 +591,60 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
 				addr = accounts[0].Address
 			}
 		}
-	} else {
-		addr = args.From
 	}
 	// Set default gas & gas price if none were set
 	gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt()
-	if gas.Cmp(common.Big0) == 0 {
+	if gas.BitLen() == 0 {
 		gas = big.NewInt(50000000)
 	}
-	if gasPrice.Cmp(common.Big0) == 0 {
+	if gasPrice.BitLen() == 0 {
 		gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
 	}
+
+	// Create new call message
 	msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false)
 
-	// Execute the call and return
-	vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
-	if err != nil {
-		return "0x", common.Big0, err
+	// Setup context so it may be cancelled the call has completed
+	// or, in case of unmetered gas, setup a context with a timeout.
+	var cancel context.CancelFunc
+	if vmCfg.DisableGasMetering {
+		ctx, cancel = context.WithTimeout(ctx, time.Second*5)
+	} else {
+		ctx, cancel = context.WithCancel(ctx)
 	}
+	// Make sure the context is cancelled when the call has completed
+	// this makes sure resources are cleaned up.
+	defer func() { cancel() }()
+
+	// Get a new instance of the EVM.
+	evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg)
+	if err != nil {
+		return nil, common.Big0, err
+	}
+	// Wait for the context to be done and cancel the evm. Even if the
+	// EVM has finished, cancelling may be done (repeatedly)
+	go func() {
+		select {
+		case <-ctx.Done():
+			evm.Cancel()
+		}
+	}()
+
+	// Setup the gas pool (also for unmetered requests)
+	// and apply the message.
 	gp := new(core.GasPool).AddGas(common.MaxBig)
-	res, gas, err := core.ApplyMessage(vmenv, msg, gp)
+	res, gas, err := core.ApplyMessage(evm, msg, gp)
 	if err := vmError(); err != nil {
-		return "0x", common.Big0, err
-	}
-	if len(res) == 0 { // backwards compatibility
-		return "0x", gas, err
+		return nil, common.Big0, err
 	}
-	return common.ToHex(res), gas, err
+	return res, gas, err
 }
 
 // Call executes the given transaction on the state for the given block number.
 // It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
-func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) {
-	result, _, err := s.doCall(ctx, args, blockNr)
-	return result, err
+func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
+	result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true})
+	return (hexutil.Bytes)(result), err
 }
 
 // EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
@@ -644,7 +666,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*
 		mid := (hi + lo) / 2
 		(*big.Int)(&args.Gas).SetUint64(mid)
 
-		_, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber)
+		_, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
 
 		// If the transaction became invalid or used all the gas (failed), raise the gas limit
 		if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 {
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index ebb14a5b5c3e4a2b0cba8b4b68c1fff3051d0816..214214f5110a85bc90f2220a9b6cf10563d6225d 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -51,7 +51,7 @@ type Backend interface {
 	GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
 	GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
 	GetTd(blockHash common.Hash) *big.Int
-	GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (*vm.EVM, func() error, error)
+	GetEVM(ctx context.Context, msg core.Message, state State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error)
 	// TxPool API
 	SendTx(ctx context.Context, signedTx *types.Transaction) error
 	RemoveTx(txHash common.Hash)
diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go
index 65a23f55e7ef9e605e158bddfed0519834fdf9e7..693afe802f27ddb8e81434c5543abd13871a8859 100644
--- a/internal/ethapi/tracer_test.go
+++ b/internal/ethapi/tracer_test.go
@@ -45,7 +45,7 @@ func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
 func runTrace(tracer *JavascriptTracer) (interface{}, error) {
 	env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
 
-	contract := vm.NewContract(account{}, account{}, big.NewInt(0), big.NewInt(10000))
+	contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
 	contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
 
 	_, err := env.Interpreter().Run(contract, []byte{})
@@ -134,7 +134,7 @@ func TestHaltBetweenSteps(t *testing.T) {
 	}
 
 	env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
-	contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), big.NewInt(0))
+	contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
 
 	tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil)
 	timeout := errors.New("stahp")
diff --git a/les/api_backend.go b/les/api_backend.go
index 3a71ac4e02da92b4634165a42fdeb6ff5cdd57fb..ed2a7cd13e7350d6c9762b8b8df862dbe524a171 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -88,7 +88,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
 	return b.eth.blockchain.GetTdByHash(blockHash)
 }
 
-func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) {
+func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
 	stateDb := state.(*light.LightState).Copy()
 	addr := msg.From()
 	from, err := stateDb.GetOrNewStateObject(ctx, addr)
@@ -99,7 +99,7 @@ func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state et
 
 	vmstate := light.NewVMState(ctx, stateDb)
 	context := core.NewEVMContext(msg, header, b.eth.blockchain)
-	return vm.NewEVM(context, vmstate, b.eth.chainConfig, vm.Config{}), vmstate.Error, nil
+	return vm.NewEVM(context, vmstate, b.eth.chainConfig, vmCfg), vmstate.Error, nil
 }
 
 func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
diff --git a/les/helper_test.go b/les/helper_test.go
index e0b7558eeb61cce1d564d79c7e443465cae9f36a..2c6f34a92eb284ac4d66bb63d5f10f781253a370 100644
--- a/les/helper_test.go
+++ b/les/helper_test.go
@@ -57,6 +57,8 @@ var (
 	testContractDeployed     = uint64(2)
 
 	testBufLimit = uint64(100)
+
+	bigTxGas = new(big.Int).SetUint64(params.TxGas)
 )
 
 /*
@@ -80,15 +82,15 @@ func testChainGen(i int, block *core.BlockGen) {
 	switch i {
 	case 0:
 		// In block 1, the test bank sends account #1 some ether.
-		tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+		tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
 		block.AddTx(tx)
 	case 1:
 		// In block 2, the test bank sends some more ether to account #1.
 		// acc1Addr passes it on to account #2.
 		// acc1Addr creates a test contract.
-		tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
+		tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
 		nonce := block.TxNonce(acc1Addr)
-		tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+		tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
 		nonce++
 		tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key)
 		testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
diff --git a/light/odr_test.go b/light/odr_test.go
index a2f969acb3be2de099d8d3e4d03015336ed86d5b..a76050a299e13f964aa7b7e4bcfd047dd22661b5 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -49,6 +49,8 @@ var (
 
 	testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056")
 	testContractAddr common.Address
+
+	bigTxGas = new(big.Int).SetUint64(params.TxGas)
 )
 
 type testOdr struct {
@@ -205,15 +207,15 @@ func testChainGen(i int, block *core.BlockGen) {
 	switch i {
 	case 0:
 		// In block 1, the test bank sends account #1 some ether.
-		tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
+		tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
 		block.AddTx(tx)
 	case 1:
 		// In block 2, the test bank sends some more ether to account #1.
 		// acc1Addr passes it on to account #2.
 		// acc1Addr creates a test contract.
-		tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
+		tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
 		nonce := block.TxNonce(acc1Addr)
-		tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
+		tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
 		nonce++
 		tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key)
 		testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
diff --git a/light/txpool_test.go b/light/txpool_test.go
index d8f04e61735696f9ad03705c939178e046d97380..af2dcbbef17f327e297c0a72997f98b6a9378a61 100644
--- a/light/txpool_test.go
+++ b/light/txpool_test.go
@@ -77,7 +77,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) {
 
 func TestTxPool(t *testing.T) {
 	for i := range testTx {
-		testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
+		testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
 	}
 
 	var (
diff --git a/miner/miner.go b/miner/miner.go
index 61cd3e049942e266fc1b25fd741466c1fde01b18..83059f4b1d3a9f381cb936992abcc5a1fdf51163 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -171,7 +171,7 @@ func (self *Miner) HashRate() (tot int64) {
 }
 
 func (self *Miner) SetExtra(extra []byte) error {
-	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+	if uint64(len(extra)) > params.MaximumExtraDataSize {
 		return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
 	}
 	self.worker.setExtra(extra)
diff --git a/params/gas_table.go b/params/gas_table.go
index 093dacc8b3f749faeea4c6784e51e85ccc48c03c..a06053904169ffdfce9c1c8426cbc6890ba2ce52 100644
--- a/params/gas_table.go
+++ b/params/gas_table.go
@@ -16,41 +16,35 @@
 
 package params
 
-import "math/big"
-
 type GasTable struct {
-	ExtcodeSize *big.Int
-	ExtcodeCopy *big.Int
-	Balance     *big.Int
-	SLoad       *big.Int
-	Calls       *big.Int
-	Suicide     *big.Int
+	ExtcodeSize uint64
+	ExtcodeCopy uint64
+	Balance     uint64
+	SLoad       uint64
+	Calls       uint64
+	Suicide     uint64
 
-	ExpByte *big.Int
+	ExpByte uint64
 
 	// CreateBySuicide occurs when the
 	// refunded account is one that does
 	// not exist. This logic is similar
 	// to call. May be left nil. Nil means
 	// not charged.
-	CreateBySuicide *big.Int
+	CreateBySuicide uint64
 }
 
 var (
 	// GasTableHomestead contain the gas prices for
 	// the homestead phase.
 	GasTableHomestead = GasTable{
-		ExtcodeSize: big.NewInt(20),
-		ExtcodeCopy: big.NewInt(20),
-		Balance:     big.NewInt(20),
-		SLoad:       big.NewInt(50),
-		Calls:       big.NewInt(40),
-		Suicide:     big.NewInt(0),
-		ExpByte:     big.NewInt(10),
-
-		// explicitly set to nil to indicate
-		// this rule does not apply to homestead.
-		CreateBySuicide: nil,
+		ExtcodeSize: 20,
+		ExtcodeCopy: 20,
+		Balance:     20,
+		SLoad:       50,
+		Calls:       40,
+		Suicide:     0,
+		ExpByte:     10,
 	}
 
 	// GasTableHomestead contain the gas re-prices for
@@ -58,26 +52,26 @@ var (
 	//
 	// TODO rename to GasTableEIP150
 	GasTableHomesteadGasRepriceFork = GasTable{
-		ExtcodeSize: big.NewInt(700),
-		ExtcodeCopy: big.NewInt(700),
-		Balance:     big.NewInt(400),
-		SLoad:       big.NewInt(200),
-		Calls:       big.NewInt(700),
-		Suicide:     big.NewInt(5000),
-		ExpByte:     big.NewInt(10),
+		ExtcodeSize: 700,
+		ExtcodeCopy: 700,
+		Balance:     400,
+		SLoad:       200,
+		Calls:       700,
+		Suicide:     5000,
+		ExpByte:     10,
 
-		CreateBySuicide: big.NewInt(25000),
+		CreateBySuicide: 25000,
 	}
 
 	GasTableEIP158 = GasTable{
-		ExtcodeSize: big.NewInt(700),
-		ExtcodeCopy: big.NewInt(700),
-		Balance:     big.NewInt(400),
-		SLoad:       big.NewInt(200),
-		Calls:       big.NewInt(700),
-		Suicide:     big.NewInt(5000),
-		ExpByte:     big.NewInt(50),
+		ExtcodeSize: 700,
+		ExtcodeCopy: 700,
+		Balance:     400,
+		SLoad:       200,
+		Calls:       700,
+		Suicide:     5000,
+		ExpByte:     50,
 
-		CreateBySuicide: big.NewInt(25000),
+		CreateBySuicide: 25000,
 	}
 )
diff --git a/params/protocol_params.go b/params/protocol_params.go
index f5b6bedeb7b9890c75ac08b87be53a5f7e68e1bd..f48bf4992d87b89f8c57eff3edd3e6d49da0c267 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -18,56 +18,58 @@ package params
 
 import "math/big"
 
-var (
-	MaximumExtraDataSize   = big.NewInt(32)     // Maximum size extra data may be after Genesis.
-	ExpByteGas             = big.NewInt(10)     // Times ceil(log256(exponent)) for the EXP instruction.
-	SloadGas               = big.NewInt(50)     // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
-	CallValueTransferGas   = big.NewInt(9000)   // Paid for CALL when the value transfer is non-zero.
-	CallNewAccountGas      = big.NewInt(25000)  // Paid for CALL when the destination address didn't exist prior.
-	TxGas                  = big.NewInt(21000)  // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
-	TxGasContractCreation  = big.NewInt(53000)  // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
-	TxDataZeroGas          = big.NewInt(4)      // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
-	DifficultyBoundDivisor = big.NewInt(2048)   // The bound divisor of the difficulty, used in the update calculations.
-	QuadCoeffDiv           = big.NewInt(512)    // Divisor for the quadratic particle of the memory cost equation.
-	GenesisDifficulty      = big.NewInt(131072) // Difficulty of the Genesis block.
-	DurationLimit          = big.NewInt(13)     // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
-	SstoreSetGas           = big.NewInt(20000)  // Once per SLOAD operation.
-	LogDataGas             = big.NewInt(8)      // Per byte in a LOG* operation's data.
-	CallStipend            = big.NewInt(2300)   // Free gas given at beginning of call.
-	EcrecoverGas           = big.NewInt(3000)   //
-	Sha256WordGas          = big.NewInt(12)     //
-
-	MinGasLimit     = big.NewInt(5000)                  // Minimum the gas limit may ever be.
-	GenesisGasLimit = big.NewInt(4712388)               // Gas limit of the Genesis block.
-	TargetGasLimit  = new(big.Int).Set(GenesisGasLimit) // The artificial target
+const (
+	MaximumExtraDataSize  uint64 = 32    // Maximum size extra data may be after Genesis.
+	ExpByteGas            uint64 = 10    // Times ceil(log256(exponent)) for the EXP instruction.
+	SloadGas              uint64 = 50    // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
+	CallValueTransferGas  uint64 = 9000  // Paid for CALL when the value transfer is non-zero.
+	CallNewAccountGas     uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
+	TxGas                 uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
+	TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
+	TxDataZeroGas         uint64 = 4     // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
+	QuadCoeffDiv          uint64 = 512   // Divisor for the quadratic particle of the memory cost equation.
+	SstoreSetGas          uint64 = 20000 // Once per SLOAD operation.
+	LogDataGas            uint64 = 8     // Per byte in a LOG* operation's data.
+	CallStipend           uint64 = 2300  // Free gas given at beginning of call.
+	EcrecoverGas          uint64 = 3000  //
+	Sha256WordGas         uint64 = 12    //
 
-	Sha3Gas              = big.NewInt(30)     // Once per SHA3 operation.
-	Sha256Gas            = big.NewInt(60)     //
-	IdentityWordGas      = big.NewInt(3)      //
-	Sha3WordGas          = big.NewInt(6)      // Once per word of the SHA3 operation's data.
-	SstoreResetGas       = big.NewInt(5000)   // Once per SSTORE operation if the zeroness changes from zero.
-	SstoreClearGas       = big.NewInt(5000)   // Once per SSTORE operation if the zeroness doesn't change.
-	SstoreRefundGas      = big.NewInt(15000)  // Once per SSTORE operation if the zeroness changes to zero.
-	JumpdestGas          = big.NewInt(1)      // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
-	IdentityGas          = big.NewInt(15)     //
-	GasLimitBoundDivisor = big.NewInt(1024)   // The bound divisor of the gas limit, used in update calculations.
-	EpochDuration        = big.NewInt(30000)  // Duration between proof-of-work epochs.
-	CallGas              = big.NewInt(40)     // Once per CALL operation & message call transaction.
-	CreateDataGas        = big.NewInt(200)    //
-	Ripemd160Gas         = big.NewInt(600)    //
-	Ripemd160WordGas     = big.NewInt(120)    //
-	MinimumDifficulty    = big.NewInt(131072) // The minimum that the difficulty may ever be.
-	CallCreateDepth      = big.NewInt(1024)   // Maximum depth of call/create stack.
-	ExpGas               = big.NewInt(10)     // Once per EXP instruction.
-	LogGas               = big.NewInt(375)    // Per LOG* operation.
-	CopyGas              = big.NewInt(3)      //
-	StackLimit           = big.NewInt(1024)   // Maximum size of VM stack allowed.
-	TierStepGas          = big.NewInt(0)      // Once per operation, for a selection of them.
-	LogTopicGas          = big.NewInt(375)    // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
-	CreateGas            = big.NewInt(32000)  // Once per CREATE operation & contract-creation transaction.
-	SuicideRefundGas     = big.NewInt(24000)  // Refunded following a suicide operation.
-	MemoryGas            = big.NewInt(3)      // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
-	TxDataNonZeroGas     = big.NewInt(68)     // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
+	Sha3Gas          uint64 = 30    // Once per SHA3 operation.
+	Sha256Gas        uint64 = 60    //
+	IdentityWordGas  uint64 = 3     //
+	Sha3WordGas      uint64 = 6     // Once per word of the SHA3 operation's data.
+	SstoreResetGas   uint64 = 5000  // Once per SSTORE operation if the zeroness changes from zero.
+	SstoreClearGas   uint64 = 5000  // Once per SSTORE operation if the zeroness doesn't change.
+	SstoreRefundGas  uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero.
+	JumpdestGas      uint64 = 1     // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
+	IdentityGas      uint64 = 15    //
+	EpochDuration    uint64 = 30000 // Duration between proof-of-work epochs.
+	CallGas          uint64 = 40    // Once per CALL operation & message call transaction.
+	CreateDataGas    uint64 = 200   //
+	Ripemd160Gas     uint64 = 600   //
+	Ripemd160WordGas uint64 = 120   //
+	CallCreateDepth  uint64 = 1024  // Maximum depth of call/create stack.
+	ExpGas           uint64 = 10    // Once per EXP instruction
+	LogGas           uint64 = 375   // Per LOG* operation.
+	CopyGas          uint64 = 3     //
+	StackLimit       uint64 = 1024  // Maximum size of VM stack allowed.
+	TierStepGas      uint64 = 0     // Once per operation, for a selection of them.
+	LogTopicGas      uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
+	CreateGas        uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
+	SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation.
+	MemoryGas        uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
+	TxDataNonZeroGas uint64 = 68    // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
 
 	MaxCodeSize = 24576
 )
+
+var (
+	GasLimitBoundDivisor   = big.NewInt(1024)                  // The bound divisor of the gas limit, used in update calculations.
+	MinGasLimit            = big.NewInt(5000)                  // Minimum the gas limit may ever be.
+	GenesisGasLimit        = big.NewInt(4712388)               // Gas limit of the Genesis block.
+	TargetGasLimit         = new(big.Int).Set(GenesisGasLimit) // The artificial target
+	DifficultyBoundDivisor = big.NewInt(2048)                  // The bound divisor of the difficulty, used in the update calculations.
+	GenesisDifficulty      = big.NewInt(131072)                // Difficulty of the Genesis block.
+	MinimumDifficulty      = big.NewInt(131072)                // The minimum that the difficulty may ever be.
+	DurationLimit          = big.NewInt(13)                    // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
+)
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 470eb7cb7f5bf997293eac891f52ee24a662f443..01539de03e5c902471b1191a22dd9d0cbddfa486 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -146,7 +146,7 @@ func runBlockTests(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, bt map[s
 	}
 
 	for name, test := range bt {
-		if skipTest[name] {
+		if skipTest[name] /*|| name != "CallingCanonicalContractFromFork_CALLCODE"*/ {
 			glog.Infoln("Skipping block test", name)
 			continue
 		}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 5469a4c71be47447c455dde8f9c4c1d485169a9a..e8ab29d1433087dc4be1a605b1df7be8ea09450c 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -108,7 +108,7 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski
 	}
 
 	for name, test := range tests {
-		if skipTest[name] {
+		if skipTest[name] /*|| name != "JUMPDEST_Attack"*/ {
 			glog.Infoln("Skipping state test", name)
 			continue
 		}
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index 25e55886f4a8f4fbb416580d9d5f37f1dd656944..1edf0e425aacc7bee4e69d0771cd66f022a2e9b6 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -129,7 +129,7 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error {
 	}
 
 	for name, test := range tests {
-		if skipTest[name] /*|| name != "loop_stacklimit_1021"*/ {
+		if skipTest[name] /*|| name != "exp0"*/ {
 			glog.Infoln("Skipping VM test", name)
 			continue
 		}
@@ -229,6 +229,6 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type
 	vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
 
 	environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
-	ret, err := environment.Call(caller, to, data, gas, value)
-	return ret, statedb.Logs(), gas, err
+	ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value)
+	return ret, statedb.Logs(), new(big.Int).SetUint64(g), err
 }