aboutsummaryrefslogtreecommitdiffstats
path: root/vm
diff options
context:
space:
mode:
Diffstat (limited to 'vm')
-rw-r--r--vm/address.go18
-rw-r--r--vm/common.go64
-rw-r--r--vm/vm.go209
3 files changed, 178 insertions, 113 deletions
diff --git a/vm/address.go b/vm/address.go
index 1c9369ab7..b1345da8f 100644
--- a/vm/address.go
+++ b/vm/address.go
@@ -32,23 +32,23 @@ func PrecompiledContracts() map[string]*PrecompiledAccount {
// SHA256
string(ethutil.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
- n := big.NewInt(int64(l+31)/32 + 1)
- n.Mul(n, GasSha256)
- return n
+ n := big.NewInt(int64(l+31) / 32)
+ n.Mul(n, GasSha256Word)
+ return n.Add(n, GasSha256Base)
}, sha256Func},
// RIPEMD160
string(ethutil.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
- n := big.NewInt(int64(l+31)/32 + 1)
- n.Mul(n, GasRipemd)
- return n
+ n := big.NewInt(int64(l+31) / 32)
+ n.Mul(n, GasRipemdWord)
+ return n.Add(n, GasRipemdBase)
}, ripemd160Func},
string(ethutil.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
- n := big.NewInt(int64(l+31)/32 + 1)
- n.Mul(n, GasMemCpy)
+ n := big.NewInt(int64(l+31) / 32)
+ n.Mul(n, GasIdentityWord)
- return n
+ return n.Add(n, GasIdentityBase)
}, memCpy},
}
}
diff --git a/vm/common.go b/vm/common.go
index 45a7187a9..bc1353009 100644
--- a/vm/common.go
+++ b/vm/common.go
@@ -31,26 +31,48 @@ func NewVm(env Environment) VirtualMachine {
}
var (
- GasStep = big.NewInt(1)
- GasSha = big.NewInt(10)
- GasSLoad = big.NewInt(20)
- GasSStore = big.NewInt(100)
- GasSStoreRefund = big.NewInt(100)
- GasBalance = big.NewInt(20)
- GasCreate = big.NewInt(100)
- GasCall = big.NewInt(20)
- GasCreateByte = big.NewInt(5)
- GasSha3Byte = big.NewInt(10)
- GasSha256Byte = big.NewInt(50)
- GasRipemdByte = big.NewInt(50)
- GasMemory = big.NewInt(1)
- GasData = big.NewInt(5)
- GasTx = big.NewInt(500)
- GasLog = big.NewInt(32)
- GasSha256 = big.NewInt(50)
- GasRipemd = big.NewInt(50)
- GasEcrecover = big.NewInt(500)
- GasMemCpy = big.NewInt(1)
+ GasQuickStep = big.NewInt(2)
+ GasFastestStep = big.NewInt(3)
+ GasFastStep = big.NewInt(5)
+ GasMidStep = big.NewInt(8)
+ GasSlowStep = big.NewInt(10)
+ GasExtStep = big.NewInt(20)
+
+ GasStorageGet = big.NewInt(50)
+ GasStorageAdd = big.NewInt(20000)
+ GasStorageMod = big.NewInt(5000)
+ GasLogBase = big.NewInt(2000)
+ GasLogTopic = big.NewInt(2000)
+ GasLogData = big.NewInt(8)
+ GasCreate = big.NewInt(32000)
+ GasCreateByte = big.NewInt(300)
+ GasCall = big.NewInt(40)
+ GasCallValueTransfer = big.NewInt(6700)
+ GasCallNewAccount = big.NewInt(25000)
+ GasReturn = big.NewInt(0)
+ GasStop = big.NewInt(0)
+ GasJumpDest = big.NewInt(1)
+
+ RefundStorage = big.NewInt(15000)
+ RefundSuicide = big.NewInt(24000)
+
+ GasMemWord = big.NewInt(3)
+ GasQuadCoeffWord = big.NewInt(1)
+ GasContractByte = big.NewInt(200)
+ GasTransaction = big.NewInt(21000)
+ GasTxDataNonzeroByte = big.NewInt(37)
+ GasTxZeroByte = big.NewInt(2)
+
+ GasSha3Base = big.NewInt(30)
+ GasSha3Word = big.NewInt(6)
+ GasSha256Base = big.NewInt(60)
+ GasSha256Word = big.NewInt(12)
+ GasRipemdBase = big.NewInt(600)
+ GasRipemdWord = big.NewInt(12)
+ GasEcrecover = big.NewInt(3000)
+ GasIdentityBase = big.NewInt(15)
+ GasIdentityWord = big.NewInt(3)
+ GasCopyWord = big.NewInt(3)
Pow256 = ethutil.BigPow(2, 256)
@@ -59,6 +81,8 @@ var (
U256 = ethutil.U256
S256 = ethutil.S256
+
+ Zero = ethutil.Big0
)
const MaxCallDepth = 1025
diff --git a/vm/vm.go b/vm/vm.go
index b9282435e..791718fb2 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -769,27 +769,97 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
}
}
-func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
- gas := new(big.Int)
- addStepGasUsage := func(amount *big.Int) {
- if amount.Cmp(ethutil.Big0) >= 0 {
- gas.Add(gas, amount)
- }
+type req struct {
+ stack int
+ gas *big.Int
+}
+
+var _baseCheck = map[OpCode]req{
+ // Req Stack Gas price
+ ADD: {2, GasFastestStep},
+ LT: {2, GasFastestStep},
+ GT: {2, GasFastestStep},
+ SLT: {2, GasFastestStep},
+ SGT: {2, GasFastestStep},
+ EQ: {2, GasFastestStep},
+ ISZERO: {1, GasFastestStep},
+ SUB: {2, GasFastestStep},
+ AND: {2, GasFastestStep},
+ OR: {2, GasFastestStep},
+ XOR: {2, GasFastestStep},
+ NOT: {1, GasFastestStep},
+ BYTE: {2, GasFastestStep},
+ CALLDATALOAD: {1, GasFastestStep},
+ CALLDATACOPY: {3, GasFastestStep},
+ MLOAD: {1, GasFastestStep},
+ MSTORE: {2, GasFastestStep},
+ MSTORE8: {2, GasFastestStep},
+ CODECOPY: {3, GasFastestStep},
+ MUL: {2, GasFastStep},
+ DIV: {2, GasFastStep},
+ SDIV: {2, GasFastStep},
+ MOD: {2, GasFastStep},
+ SMOD: {2, GasFastStep},
+ SIGNEXTEND: {2, GasFastStep},
+ ADDMOD: {3, GasMidStep},
+ MULMOD: {3, GasMidStep},
+ JUMP: {1, GasMidStep},
+ JUMPI: {2, GasSlowStep},
+ EXP: {2, GasSlowStep},
+ ADDRESS: {0, GasQuickStep},
+ ORIGIN: {0, GasQuickStep},
+ CALLER: {0, GasQuickStep},
+ CALLVALUE: {0, GasQuickStep},
+ CODESIZE: {0, GasQuickStep},
+ GASPRICE: {0, GasQuickStep},
+ COINBASE: {0, GasQuickStep},
+ TIMESTAMP: {0, GasQuickStep},
+ NUMBER: {0, GasQuickStep},
+ DIFFICULTY: {0, GasQuickStep},
+ GASLIMIT: {0, GasQuickStep},
+ POP: {0, GasQuickStep},
+ PC: {0, GasQuickStep},
+ MSIZE: {0, GasQuickStep},
+ GAS: {0, GasQuickStep},
+ BLOCKHASH: {1, GasExtStep},
+ BALANCE: {0, GasExtStep},
+ EXTCODESIZE: {1, GasExtStep},
+ EXTCODECOPY: {4, GasExtStep},
+ SLOAD: {1, GasStorageGet},
+ SSTORE: {2, Zero},
+ SHA3: {1, GasSha3Base},
+ CREATE: {3, GasCreate},
+ CALL: {7, GasCall},
+ CALLCODE: {7, GasCall},
+ JUMPDEST: {0, GasJumpDest},
+ SUICIDE: {1, Zero},
+ RETURN: {2, Zero},
+}
+
+func baseCheck(op OpCode, stack *Stack, gas *big.Int) {
+ if r, ok := _baseCheck[op]; ok {
+ stack.require(r.stack)
+
+ gas.Add(gas, r.gas)
}
+}
- addStepGasUsage(GasStep)
+func toWordSize(size *big.Int) *big.Int {
+ tmp := new(big.Int)
+ tmp.Add(tmp, u256(31))
+ tmp.Div(tmp, u256(32))
+ return tmp
+}
+
+func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
+ var (
+ gas = new(big.Int)
+ newMemSize *big.Int = new(big.Int)
+ )
+ baseCheck(op, stack, gas)
- var newMemSize *big.Int = ethutil.Big0
- var additionalGas *big.Int = new(big.Int)
// Stack Check, memory resize & gas phase
switch op {
- // Stack checks only
- case ISZERO, CALLDATALOAD, POP, JUMP, NOT, EXTCODESIZE, BLOCKHASH: // 1
- stack.require(1)
- case JUMPI, ADD, SUB, DIV, MUL, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
- stack.require(2)
- case ADDMOD, MULMOD: // 3
- stack.require(3)
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)
@@ -800,112 +870,83 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
n := int(op - LOG0)
stack.require(n + 2)
- gas.Set(GasLog)
- addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog))
-
mSize, mStart := stack.Peekn()
- addStepGasUsage(mSize)
+
+ 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))
newMemSize = calcMemSize(mStart, mSize)
case EXP:
- stack.require(2)
-
- gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1)))
- // Gas only
- case STOP:
- gas.Set(ethutil.Big0)
- case SUICIDE:
- stack.require(1)
-
- gas.Set(ethutil.Big0)
- case SLOAD:
- stack.require(1)
-
- gas.Set(GasSLoad)
- // Memory resize & Gas
+ gas.Add(gas, big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes())+1)))
case SSTORE:
stack.require(2)
- var mult *big.Int
+ var g *big.Int
y, x := stack.Peekn()
val := statedb.GetState(context.Address(), x.Bytes())
if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0
- mult = ethutil.Big3
+ g = GasStorageAdd
} else if len(val) > 0 && len(y.Bytes()) == 0 {
- statedb.Refund(self.env.Origin(), GasSStoreRefund)
+ statedb.Refund(self.env.Origin(), RefundStorage)
- mult = ethutil.Big0
+ g = GasStorageMod
} else {
// non 0 => non 0 (or 0 => 0)
- mult = ethutil.Big1
+ g = GasStorageMod
}
- gas.Set(new(big.Int).Mul(mult, GasSStore))
- case BALANCE:
- stack.require(1)
- gas.Set(GasBalance)
- case MSTORE:
- stack.require(2)
+ gas.Set(g)
newMemSize = calcMemSize(stack.Peek(), u256(32))
case MLOAD:
- stack.require(1)
-
newMemSize = calcMemSize(stack.Peek(), u256(32))
case MSTORE8:
- stack.require(2)
newMemSize = calcMemSize(stack.Peek(), u256(1))
case RETURN:
- stack.require(2)
-
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
case SHA3:
- stack.require(2)
- gas.Set(GasSha)
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
- additionalGas.Set(stack.data[stack.Len()-2])
- case CALLDATACOPY:
- stack.require(3)
+ words := toWordSize(stack.data[stack.Len()-2])
+ gas.Add(gas, words.Mul(words, GasSha3Word))
+ case CALLDATACOPY:
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
- additionalGas.Set(stack.data[stack.Len()-3])
- case CODECOPY:
- stack.require(3)
+ words := toWordSize(stack.data[stack.Len()-3])
+ gas.Add(gas, words.Mul(words, GasCopyWord))
+ case CODECOPY:
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
- additionalGas.Set(stack.data[stack.Len()-3])
- case EXTCODECOPY:
- stack.require(4)
+ words := toWordSize(stack.data[stack.Len()-3])
+ gas.Add(gas, words.Mul(words, GasCopyWord))
+ case EXTCODECOPY:
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
- additionalGas.Set(stack.data[stack.Len()-4])
+
+ words := toWordSize(stack.data[stack.Len()-4])
+ gas.Add(gas, words.Mul(words, GasCopyWord))
+ case CREATE:
+ size := new(big.Int).Set(stack.data[stack.Len()-2])
+ gas.Add(gas, size.Mul(size, GasCreateByte))
case CALL, CALLCODE:
- stack.require(7)
- gas.Set(GasCall)
- addStepGasUsage(stack.data[stack.Len()-1])
+ gas.Add(gas, stack.data[stack.Len()-1])
+
+ if op == CALL {
+ if self.env.State().GetStateObject(stack.data[stack.Len()-2].Bytes()) == nil {
+ gas.Add(gas, GasCallNewAccount)
+ }
+
+ if len(stack.data[stack.Len()].Bytes()) > 0 {
+ gas.Add(gas, GasCallValueTransfer)
+ }
+ }
x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7])
y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5])
newMemSize = ethutil.BigMax(x, y)
- case CREATE:
- stack.require(3)
- gas.Set(GasCreate)
-
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
}
- switch op {
- case CALLDATACOPY, CODECOPY, EXTCODECOPY:
- additionalGas.Add(additionalGas, u256(31))
- additionalGas.Div(additionalGas, u256(32))
- addStepGasUsage(additionalGas)
- case SHA3:
- additionalGas.Add(additionalGas, u256(31))
- additionalGas.Div(additionalGas, u256(32))
- additionalGas.Mul(additionalGas, GasSha3Byte)
- addStepGasUsage(additionalGas)
- }
-
if newMemSize.Cmp(ethutil.Big0) > 0 {
newMemSize.Add(newMemSize, u256(31))
newMemSize.Div(newMemSize, u256(32))
@@ -913,10 +954,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
- memGasUsage.Mul(GasMemory, memGasUsage)
+ memGasUsage.Mul(GasMemWord, memGasUsage)
memGasUsage.Div(memGasUsage, u256(32))
- addStepGasUsage(memGasUsage)
+ gas.Add(gas, memGasUsage)
}
}