From c1ef19bef9d4207b5f7d6fc5ff40375a5f0d203b Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Tue, 3 Mar 2015 11:11:11 +0100
Subject: [PATCH] quad mem

---
 tests/helper/vm.go  | 23 ++++++++++++++++++++++-
 tests/vm/gh_test.go | 10 ++++------
 vm/common.go        |  6 ++++--
 vm/vm.go            | 32 ++++++++++++++++++++++++--------
 4 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/tests/helper/vm.go b/tests/helper/vm.go
index f1c1ffdfc..a1a1a98ca 100644
--- a/tests/helper/vm.go
+++ b/tests/helper/vm.go
@@ -28,6 +28,8 @@ type Env struct {
 	gasLimit   *big.Int
 
 	logs state.Logs
+
+	vmTest bool
 }
 
 func NewEnv(state *state.StateDB) *Env {
@@ -92,20 +94,38 @@ func (self *Env) vm(addr, data []byte, gas, price, value *big.Int) *core.Executi
 }
 
 func (self *Env) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
+	if self.vmTest && self.depth > 0 {
+		caller.ReturnGas(gas, price)
+
+		return nil, nil
+	}
 	exe := self.vm(addr, data, gas, price, value)
 	ret, err := exe.Call(addr, caller)
 	self.Gas = exe.Gas
 
 	return ret, err
+
 }
 func (self *Env) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
+	if self.vmTest && self.depth > 0 {
+		caller.ReturnGas(gas, price)
+	}
 	exe := self.vm(caller.Address(), data, gas, price, value)
 	return exe.Call(addr, caller)
 }
 
 func (self *Env) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
 	exe := self.vm(addr, data, gas, price, value)
-	return exe.Create(caller)
+	if self.vmTest {
+		caller.ReturnGas(gas, price)
+
+		nonce := self.state.GetNonce(caller.Address())
+		obj := self.state.GetOrNewStateObject(crypto.CreateAddress(caller.Address(), nonce))
+
+		return nil, nil, obj
+	} else {
+		return exe.Create(caller)
+	}
 }
 
 func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Logs, *big.Int, error) {
@@ -123,6 +143,7 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Log
 	caller := state.GetOrNewStateObject(from)
 
 	vmenv := NewEnvFromMap(state, env, exec)
+	vmenv.vmTest = true
 	vmenv.skipTransfer = true
 	vmenv.initial = true
 	ret, err := vmenv.Call(caller, to, data, gas, price, value)
diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go
index a23076b74..f8c42f09c 100644
--- a/tests/vm/gh_test.go
+++ b/tests/vm/gh_test.go
@@ -79,12 +79,10 @@ func RunVmTest(p string, t *testing.T) {
 	helper.CreateFileTests(t, p, &tests)
 
 	for name, test := range tests {
-		/*
-			helper.Logger.SetLogLevel(4)
-			if name != "log1_nonEmptyMem_logMemSize1_logMemStart31" {
-				continue
-			}
-		*/
+		helper.Logger.SetLogLevel(4)
+		if name != "env1" {
+			continue
+		}
 		db, _ := ethdb.NewMemDatabase()
 		statedb := state.New(nil, db)
 		for addr, account := range test.Pre {
diff --git a/vm/common.go b/vm/common.go
index bc1353009..1202966fd 100644
--- a/vm/common.go
+++ b/vm/common.go
@@ -43,7 +43,7 @@ var (
 	GasStorageMod        = big.NewInt(5000)
 	GasLogBase           = big.NewInt(2000)
 	GasLogTopic          = big.NewInt(2000)
-	GasLogData           = big.NewInt(8)
+	GasLogByte           = big.NewInt(8)
 	GasCreate            = big.NewInt(32000)
 	GasCreateByte        = big.NewInt(300)
 	GasCall              = big.NewInt(40)
@@ -57,11 +57,13 @@ var (
 	RefundSuicide = big.NewInt(24000)
 
 	GasMemWord           = big.NewInt(3)
-	GasQuadCoeffWord     = big.NewInt(1)
+	GasQuadCoeffDenom    = big.NewInt(512)
 	GasContractByte      = big.NewInt(200)
 	GasTransaction       = big.NewInt(21000)
 	GasTxDataNonzeroByte = big.NewInt(37)
 	GasTxZeroByte        = big.NewInt(2)
+	GasExp               = big.NewInt(10)
+	GasExpByte           = big.NewInt(10)
 
 	GasSha3Base     = big.NewInt(30)
 	GasSha3Word     = big.NewInt(6)
diff --git a/vm/vm.go b/vm/vm.go
index e3b7df329..9f8d5e8df 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -812,6 +812,7 @@ var _baseCheck = map[OpCode]req{
 	COINBASE:     {0, GasQuickStep},
 	TIMESTAMP:    {0, GasQuickStep},
 	NUMBER:       {0, GasQuickStep},
+	CALLDATASIZE: {0, GasQuickStep},
 	DIFFICULTY:   {0, GasQuickStep},
 	GASLIMIT:     {0, GasQuickStep},
 	POP:          {0, GasQuickStep},
@@ -862,9 +863,11 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
 	case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
 		n := int(op - SWAP1 + 2)
 		stack.require(n)
+		gas.Set(GasFastestStep)
 	case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
 		n := int(op - DUP1 + 1)
 		stack.require(n)
+		gas.Set(GasFastestStep)
 	case LOG0, LOG1, LOG2, LOG3, LOG4:
 		n := int(op - LOG0)
 		stack.require(n + 2)
@@ -873,11 +876,11 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
 
 		gas.Add(gas, GasLogBase)
 		gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
-		gas.Add(gas, new(big.Int).Mul(mSize, GasLogData))
+		gas.Add(gas, new(big.Int).Mul(mSize, GasLogByte))
 
 		newMemSize = calcMemSize(mStart, mSize)
 	case EXP:
-		gas.Add(gas, big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes())+1)))
+		gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()))), GasExpByte))
 	case SSTORE:
 		stack.require(2)
 
@@ -935,7 +938,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
 				gas.Add(gas, GasCallNewAccount)
 			}
 
-			if len(stack.data[stack.Len()].Bytes()) > 0 {
+			if len(stack.data[stack.Len()-1].Bytes()) > 0 {
 				gas.Add(gas, GasCallValueTransfer)
 			}
 		}
@@ -953,11 +956,24 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
 		newMemSize.Mul(newMemSize, u256(32))
 
 		if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
-			memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
-			memGasUsage.Mul(GasMemWord, memGasUsage)
-			memGasUsage.Div(memGasUsage, u256(32))
-
-			gas.Add(gas, memGasUsage)
+			//memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
+			//memGasUsage.Mul(GasMemWord, memGasUsage)
+			//memGasUsage.Div(memGasUsage, u256(32))
+
+			//Old: full_memory_gas_cost = W + floor(W*W / 1024), W = words in memory
+			oldSize := toWordSize(big.NewInt(int64(mem.Len())))
+			linCoef := new(big.Int).Mul(oldSize, GasMemWord)
+			pow := new(big.Int)
+			pow.Exp(oldSize, ethutil.Big2, Zero)
+			quadCoef := new(big.Int).Div(pow, GasQuadCoeffDenom)
+			oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
+
+			linCoef = new(big.Int).Mul(newMemSize, GasMemWord)
+			pow.Exp(newMemSize, ethutil.Big2, Zero)
+			quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom)
+			newTotalFee := new(big.Int).Add(linCoef, quadCoef)
+
+			gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee))
 		}
 
 	}
-- 
GitLab