diff options
Diffstat (limited to 'vm')
-rw-r--r-- | vm/address.go | 18 | ||||
-rw-r--r-- | vm/common.go | 64 | ||||
-rw-r--r-- | vm/vm.go | 209 |
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 @@ -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) } } |