From 37e6870f64437a212fde383ab1538ad1e7e2acd9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 18:39:05 +0100 Subject: wip --- vm/vm.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index f9efeed96..ed3379a44 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -54,6 +54,8 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I err = fmt.Errorf("%v", r) + } else { + fmt.Println(me.(*state.StateObject).Storage()) } }() } @@ -727,7 +729,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" => (%x) %v", receiver.Address()[:4], balance) - receiver.AddAmount(balance) + receiver.AddBalance(balance) statedb.Delete(context.Address()) fallthrough -- cgit v1.2.3 From b383ff0b96a1cf3df0b56f13b8d303ae4d4977ad Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 2 Mar 2015 16:32:02 +0100 Subject: New gas prices model --- vm/address.go | 18 ++--- vm/common.go | 64 ++++++++++++------ vm/vm.go | 209 +++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 178 insertions(+), 113 deletions(-) (limited to 'vm') 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) } } -- cgit v1.2.3 From 200f66537cdf21a69ddda74eedfee30c14fb6ba6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 2 Mar 2015 17:55:45 +0100 Subject: updated tests --- vm/vm.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index 791718fb2..e3b7df329 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -34,7 +34,7 @@ func New(env Environment) *Vm { lt = LogTyDiff } - return &Vm{debug: false, env: env, logTy: lt, Recoverable: true} + return &Vm{debug: true, env: env, logTy: lt, Recoverable: true} } func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { @@ -56,8 +56,6 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I err = fmt.Errorf("%v", r) - } else { - fmt.Println(me.(*state.StateObject).Storage()) } }() } @@ -668,7 +666,6 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } addr = ref.Address() - fmt.Printf("CREATE %X\n", addr) stack.Push(ethutil.BigD(addr)) } @@ -860,6 +857,8 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo // Stack Check, memory resize & gas phase switch op { + case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: + gas.Set(GasFastestStep) case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) stack.require(n) @@ -897,11 +896,12 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo g = GasStorageMod } gas.Set(g) - newMemSize = calcMemSize(stack.Peek(), u256(32)) case MLOAD: newMemSize = calcMemSize(stack.Peek(), u256(32)) case MSTORE8: newMemSize = calcMemSize(stack.Peek(), u256(1)) + case MSTORE: + newMemSize = calcMemSize(stack.Peek(), u256(32)) case RETURN: newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case SHA3: -- cgit v1.2.3 From c1ef19bef9d4207b5f7d6fc5ff40375a5f0d203b Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 3 Mar 2015 11:11:11 +0100 Subject: quad mem --- vm/common.go | 6 ++++-- vm/vm.go | 32 ++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) (limited to 'vm') 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)) } } -- cgit v1.2.3 From fa910966ede699f90b2760d7a11ac0ef5dbda029 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 3 Mar 2015 11:18:50 +0100 Subject: Redone rlp --- vm/vm.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index 9f8d5e8df..b9c7f73a8 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -844,7 +844,7 @@ func baseCheck(op OpCode, stack *Stack, gas *big.Int) { func toWordSize(size *big.Int) *big.Int { tmp := new(big.Int) - tmp.Add(tmp, u256(31)) + tmp.Add(size, u256(31)) tmp.Div(tmp, u256(32)) return tmp } @@ -951,9 +951,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo } if newMemSize.Cmp(ethutil.Big0) > 0 { - newMemSize.Add(newMemSize, u256(31)) - newMemSize.Div(newMemSize, u256(32)) - newMemSize.Mul(newMemSize, u256(32)) + newMemSize = toWordSize(newMemSize) if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { //memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) @@ -961,15 +959,14 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo //memGasUsage.Div(memGasUsage, u256(32)) //Old: full_memory_gas_cost = W + floor(W*W / 1024), W = words in memory + pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero) 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) + linCoef = new(big.Int).Mul(newMemSize, GasMemWord) quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom) newTotalFee := new(big.Int).Add(linCoef, quadCoef) -- cgit v1.2.3 From ba0a758d8c7c574047d5d4ece9fde0b42a62fc6f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 3 Mar 2015 11:56:43 +0100 Subject: Quad mem & log changes --- vm/common.go | 7 ++++--- vm/vm.go | 18 +++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 1202966fd..af458e599 100644 --- a/vm/common.go +++ b/vm/common.go @@ -41,13 +41,14 @@ var ( GasStorageGet = big.NewInt(50) GasStorageAdd = big.NewInt(20000) GasStorageMod = big.NewInt(5000) - GasLogBase = big.NewInt(2000) - GasLogTopic = big.NewInt(2000) + GasLogBase = big.NewInt(375) + GasLogTopic = big.NewInt(375) GasLogByte = big.NewInt(8) GasCreate = big.NewInt(32000) GasCreateByte = big.NewInt(300) GasCall = big.NewInt(40) - GasCallValueTransfer = big.NewInt(6700) + GasCallValueTransfer = big.NewInt(9000) + GasStipend = big.NewInt(2300) GasCallNewAccount = big.NewInt(25000) GasReturn = big.NewInt(0) GasStop = big.NewInt(0) diff --git a/vm/vm.go b/vm/vm.go index b9c7f73a8..03acb72d2 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -399,7 +399,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I stack.Push(ethutil.BigD(data)) - self.Printf(" => %x", data) + self.Printf(" => (%v) %x", size, data) // 0x30 range case ADDRESS: stack.Push(ethutil.BigD(context.Address())) @@ -690,6 +690,10 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + if len(value.Bytes()) > 0 { + gas.Add(gas, GasStipend) + } + var ( ret []byte err error @@ -938,7 +942,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo gas.Add(gas, GasCallNewAccount) } - if len(stack.data[stack.Len()-1].Bytes()) > 0 { + if len(stack.data[stack.Len()-3].Bytes()) > 0 { gas.Add(gas, GasCallValueTransfer) } } @@ -951,7 +955,8 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo } if newMemSize.Cmp(ethutil.Big0) > 0 { - newMemSize = toWordSize(newMemSize) + newMemSizeWords := toWordSize(newMemSize) + newMemSize.Mul(newMemSizeWords, u256(32)) if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { //memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) @@ -959,20 +964,19 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo //memGasUsage.Div(memGasUsage, u256(32)) //Old: full_memory_gas_cost = W + floor(W*W / 1024), W = words in memory - pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero) oldSize := toWordSize(big.NewInt(int64(mem.Len()))) + pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero) linCoef := new(big.Int).Mul(oldSize, GasMemWord) quadCoef := new(big.Int).Div(pow, GasQuadCoeffDenom) oldTotalFee := new(big.Int).Add(linCoef, quadCoef) - pow.Exp(newMemSize, ethutil.Big2, Zero) - linCoef = new(big.Int).Mul(newMemSize, GasMemWord) + pow.Exp(newMemSizeWords, ethutil.Big2, Zero) + linCoef = new(big.Int).Mul(newMemSizeWords, GasMemWord) quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom) newTotalFee := new(big.Int).Add(linCoef, quadCoef) gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee)) } - } return newMemSize, gas -- cgit v1.2.3 From fa831206c617b398c3b74a1b6589893cd9dde6bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 3 Mar 2015 13:29:52 +0100 Subject: Updated gast costs --- vm/common.go | 7 ++++--- vm/vm.go | 16 +++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index af458e599..919153335 100644 --- a/vm/common.go +++ b/vm/common.go @@ -45,7 +45,7 @@ var ( GasLogTopic = big.NewInt(375) GasLogByte = big.NewInt(8) GasCreate = big.NewInt(32000) - GasCreateByte = big.NewInt(300) + GasCreateByte = big.NewInt(200) GasCall = big.NewInt(40) GasCallValueTransfer = big.NewInt(9000) GasStipend = big.NewInt(2300) @@ -61,8 +61,9 @@ var ( GasQuadCoeffDenom = big.NewInt(512) GasContractByte = big.NewInt(200) GasTransaction = big.NewInt(21000) - GasTxDataNonzeroByte = big.NewInt(37) - GasTxZeroByte = big.NewInt(2) + GasTxDataNonzeroByte = big.NewInt(68) + GasTxDataZeroByte = big.NewInt(4) + GasTx = big.NewInt(21000) GasExp = big.NewInt(10) GasExpByte = big.NewInt(10) diff --git a/vm/vm.go b/vm/vm.go index 03acb72d2..bce8088ef 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -931,9 +931,9 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo 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)) + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) case CALL, CALLCODE: gas.Add(gas, stack.data[stack.Len()-1]) @@ -941,17 +941,16 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo if self.env.State().GetStateObject(stack.data[stack.Len()-2].Bytes()) == nil { gas.Add(gas, GasCallNewAccount) } + } - if len(stack.data[stack.Len()-3].Bytes()) > 0 { - gas.Add(gas, GasCallValueTransfer) - } + if len(stack.data[stack.Len()-3].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) - newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) } if newMemSize.Cmp(ethutil.Big0) > 0 { @@ -959,11 +958,6 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo newMemSize.Mul(newMemSizeWords, 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)) - - //Old: full_memory_gas_cost = W + floor(W*W / 1024), W = words in memory oldSize := toWordSize(big.NewInt(int64(mem.Len()))) pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero) linCoef := new(big.Int).Mul(oldSize, GasMemWord) -- cgit v1.2.3 From 88ff13c241faff1d58e47f12bd283c112de7225a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 5 Mar 2015 19:51:25 +0100 Subject: Spec changes. * All errors during state transition result in an invalid tx --- vm/vm.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index bce8088ef..ff4692ec8 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -408,7 +408,12 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I case BALANCE: addr := stack.Pop().Bytes() - balance := statedb.GetBalance(addr) + var balance *big.Int + if statedb.GetStateObject(addr) != nil { + balance = statedb.GetBalance(addr) + } else { + balance = base + } stack.Push(balance) -- cgit v1.2.3 From bdba044a8031d810555196cde1b97792fa2b8084 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 02:46:56 +0100 Subject: ethutil: remove Config variable Various functions throughout the codebase used it to grab settings. This has to stop because I want to use them without reading the config file. These functions can now be used without reading the config first: * ethdb.NewLDBDatabase * ethrepl.NewJSRepl * vm.New --- vm/vm.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index bce8088ef..165bb0329 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -30,10 +30,7 @@ type Vm struct { func New(env Environment) *Vm { lt := LogTyPretty - if ethutil.Config.Diff { - lt = LogTyDiff - } - + // lt = LogTyDiff return &Vm{debug: true, env: env, logTy: lt, Recoverable: true} } -- cgit v1.2.3 From ed84b58af57809a743e5be6f6ea53c079c50b765 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 6 Mar 2015 16:58:52 +0100 Subject: Debug option for VM & command line flag --- vm/common.go | 3 +++ vm/vm.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 919153335..b391bb8c2 100644 --- a/vm/common.go +++ b/vm/common.go @@ -9,6 +9,9 @@ import ( var vmlogger = logger.NewLogger("VM") +// Global Debug flag indicating Debug VM (full logging) +var Debug bool + type Type byte const ( diff --git a/vm/vm.go b/vm/vm.go index 837be8c4d..890a7dd2c 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -30,8 +30,8 @@ type Vm struct { func New(env Environment) *Vm { lt := LogTyPretty - // lt = LogTyDiff - return &Vm{debug: true, env: env, logTy: lt, Recoverable: true} + + return &Vm{debug: Debug, env: env, logTy: lt, Recoverable: true} } func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { -- cgit v1.2.3 From 19efebe91e354ad86c171e01c47f9c2f3ef5cf9f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 9 Mar 2015 11:28:35 +0100 Subject: Updated tests and fixed suicide --- vm/vm.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index 890a7dd2c..3647d7a5e 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -736,6 +736,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" => (%x) %v", receiver.Address()[:4], balance) receiver.AddBalance(balance) + statedb.Delete(context.Address()) fallthrough @@ -905,6 +906,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo g = GasStorageMod } gas.Set(g) + case SUICIDE: + if !statedb.IsDeleted(context.Address()) { + statedb.Refund(self.env.Origin(), RefundSuicide) + } case MLOAD: newMemSize = calcMemSize(stack.Peek(), u256(32)) case MSTORE8: -- cgit v1.2.3 From 9007f2bbdc3b38f8f005778467157db12056c17e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 10 Mar 2015 00:25:27 +0100 Subject: reworked stack --- vm/debugger.go | 9 -- vm/gas.go | 86 +++++++++++ vm/memory.go | 72 +++++++++ vm/stack.go | 170 ++++------------------ vm/vm.go | 451 +++++++++++++++++++++------------------------------------ 5 files changed, 352 insertions(+), 436 deletions(-) create mode 100644 vm/gas.go create mode 100644 vm/memory.go (limited to 'vm') diff --git a/vm/debugger.go b/vm/debugger.go index 9b08634c6..830a8f69d 100644 --- a/vm/debugger.go +++ b/vm/debugger.go @@ -1,10 +1 @@ package vm - -import "github.com/ethereum/go-ethereum/state" - -type Debugger interface { - BreakHook(step int, op OpCode, mem *Memory, stack *Stack, object *state.StateObject) bool - StepHook(step int, op OpCode, mem *Memory, stack *Stack, object *state.StateObject) bool - BreakPoints() []int64 - SetCode(byteCode []byte) -} diff --git a/vm/gas.go b/vm/gas.go new file mode 100644 index 000000000..a19afeb67 --- /dev/null +++ b/vm/gas.go @@ -0,0 +1,86 @@ +package vm + +import "math/big" + +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}, + CALLDATASIZE: {0, GasQuickStep}, + DIFFICULTY: {0, GasQuickStep}, + GASLIMIT: {0, GasQuickStep}, + POP: {0, GasQuickStep}, + PC: {0, GasQuickStep}, + MSIZE: {0, GasQuickStep}, + GAS: {0, GasQuickStep}, + BLOCKHASH: {1, GasExtStep}, + BALANCE: {0, GasExtStep}, + EXTCODESIZE: {1, GasExtStep}, + EXTCODECOPY: {4, GasExtStep}, + SLOAD: {1, GasStorageGet}, + SSTORE: {2, Zero}, + SHA3: {1, GasSha3Base}, + CREATE: {3, GasCreate}, + CALL: {7, GasCall}, + CALLCODE: {7, GasCall}, + JUMPDEST: {0, GasJumpDest}, + SUICIDE: {1, Zero}, + RETURN: {2, Zero}, +} + +func baseCheck(op OpCode, stack *stack, gas *big.Int) { + if r, ok := _baseCheck[op]; ok { + stack.require(r.stack) + + gas.Add(gas, r.gas) + } +} + +func toWordSize(size *big.Int) *big.Int { + tmp := new(big.Int) + tmp.Add(size, u256(31)) + tmp.Div(tmp, u256(32)) + return tmp +} diff --git a/vm/memory.go b/vm/memory.go new file mode 100644 index 000000000..2a1e6e1b9 --- /dev/null +++ b/vm/memory.go @@ -0,0 +1,72 @@ +package vm + +import "fmt" + +type Memory struct { + store []byte +} + +func NewMemory() *Memory { + return &Memory{nil} +} + +func (m *Memory) Set(offset, size uint64, value []byte) { + if len(value) > 0 { + totSize := offset + size + lenSize := uint64(len(m.store) - 1) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff-1) + // Resize slice + m.store = append(m.store, newSlice...) + } + } + copy(m.store[offset:offset+size], value) + } +} + +func (m *Memory) Resize(size uint64) { + if uint64(m.Len()) < size { + m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + } +} + +func (self *Memory) Get(offset, size int64) (cpy []byte) { + if size == 0 { + return nil + } + + if len(self.store) > int(offset) { + cpy = make([]byte, size) + copy(cpy, self.store[offset:offset+size]) + + return + } + + return +} + +func (m *Memory) Len() int { + return len(m.store) +} + +func (m *Memory) Data() []byte { + return m.store +} + +func (m *Memory) Print() { + fmt.Printf("### mem %d bytes ###\n", len(m.store)) + if len(m.store) > 0 { + addr := 0 + for i := 0; i+32 <= len(m.store); i += 32 { + fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) + addr++ + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("####################") +} diff --git a/vm/stack.go b/vm/stack.go index a9aafdb9d..a99cc1805 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -5,98 +5,53 @@ import ( "math/big" ) -type OpType int - -const ( - tNorm = iota - tData - tExtro - tCrypto -) - -type TxCallback func(opType OpType) bool - -// Simple push/pop stack mechanism -type Stack struct { - data []*big.Int -} - -func NewStack() *Stack { - return &Stack{} -} - -func (st *Stack) Data() []*big.Int { - return st.data -} - -func (st *Stack) Len() int { - return len(st.data) -} - -func (st *Stack) Pop() *big.Int { - str := st.data[len(st.data)-1] - - copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1]) - st.data = st.data[:len(st.data)-1] - - return str +func newStack() *stack { + return &stack{} } -func (st *Stack) Popn() (*big.Int, *big.Int) { - ints := st.data[len(st.data)-2:] - - copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2]) - st.data = st.data[:len(st.data)-2] - - return ints[0], ints[1] +type stack struct { + data []*big.Int + ptr int } -func (st *Stack) Peek() *big.Int { - str := st.data[len(st.data)-1] - - return str +func (st *stack) push(d *big.Int) { + if len(st.data) > st.ptr { + st.data[st.ptr] = d + } else { + st.data = append(st.data, d) + } + st.ptr++ } -func (st *Stack) Peekn() (*big.Int, *big.Int) { - ints := st.data[len(st.data)-2:] - - return ints[0], ints[1] +func (st *stack) pop() (ret *big.Int) { + st.ptr-- + ret = st.data[st.ptr] + return } -func (st *Stack) Swapn(n int) (*big.Int, *big.Int) { - st.data[len(st.data)-n], st.data[len(st.data)-1] = st.data[len(st.data)-1], st.data[len(st.data)-n] - - return st.data[len(st.data)-n], st.data[len(st.data)-1] +func (st *stack) len() int { + return st.ptr } -func (st *Stack) Dupn(n int) *big.Int { - st.Push(st.data[len(st.data)-n]) - - return st.Peek() +func (st *stack) swap(n int) { + st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n] } -func (st *Stack) Push(d *big.Int) { - st.data = append(st.data, new(big.Int).Set(d)) +func (st *stack) dup(n int) { + st.push(st.data[st.len()-n]) } -func (st *Stack) Get(amount *big.Int) []*big.Int { - // offset + size <= len(data) - length := big.NewInt(int64(len(st.data))) - if amount.Cmp(length) <= 0 { - start := new(big.Int).Sub(length, amount) - return st.data[start.Int64():length.Int64()] - } - - return nil +func (st *stack) peek() *big.Int { + return st.data[st.len()-1] } -func (st *Stack) require(n int) { - if st.Len() < n { - panic(fmt.Sprintf("stack underflow (%d <=> %d)", st.Len(), n)) +func (st *stack) require(n int) { + if st.len() < n { + panic(fmt.Sprintf("stack underflow (%d <=> %d)", len(st.data), n)) } } -func (st *Stack) Print() { +func (st *stack) Print() { fmt.Println("### stack ###") if len(st.data) > 0 { for i, val := range st.data { @@ -107,72 +62,3 @@ func (st *Stack) Print() { } fmt.Println("#############") } - -type Memory struct { - store []byte -} - -func NewMemory() *Memory { - return &Memory{nil} -} - -func (m *Memory) Set(offset, size uint64, value []byte) { - if len(value) > 0 { - totSize := offset + size - lenSize := uint64(len(m.store) - 1) - if totSize > lenSize { - // Calculate the diff between the sizes - diff := totSize - lenSize - if diff > 0 { - // Create a new empty slice and append it - newSlice := make([]byte, diff-1) - // Resize slice - m.store = append(m.store, newSlice...) - } - } - copy(m.store[offset:offset+size], value) - } -} - -func (m *Memory) Resize(size uint64) { - if uint64(m.Len()) < size { - m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) - } -} - -func (self *Memory) Get(offset, size int64) (cpy []byte) { - if size == 0 { - return nil - } - - if len(self.store) > int(offset) { - cpy = make([]byte, size) - copy(cpy, self.store[offset:offset+size]) - - return - } - - return -} - -func (m *Memory) Len() int { - return len(m.store) -} - -func (m *Memory) Data() []byte { - return m.store -} - -func (m *Memory) Print() { - fmt.Printf("### mem %d bytes ###\n", len(m.store)) - if len(m.store) > 0 { - addr := 0 - for i := 0; i+32 <= len(m.store); i += 32 { - fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) - addr++ - } - } else { - fmt.Println("-- empty --") - } - fmt.Println("####################") -} diff --git a/vm/vm.go b/vm/vm.go index 3647d7a5e..6f3945472 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -19,8 +19,6 @@ type Vm struct { // For logging debug bool - Dbg Debugger - BreakPoints []int64 Stepping bool Fn string @@ -66,10 +64,9 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I destinations = analyseJumpDests(context.Code) mem = NewMemory() - stack = NewStack() + stack = newStack() pc uint64 = 0 step = 0 - prevStep = 0 statedb = self.env.State() jump = func(from uint64, to *big.Int) { @@ -93,7 +90,6 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } for { - prevStep = step // The base for all big integer arithmetic base := new(big.Int) @@ -101,11 +97,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I // Get the memory location of pc op = context.GetOp(pc) - self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.Len()) - if self.Dbg != nil { - //self.Dbg.Step(self, op, mem, stack, context) - } - + self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len()) newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack) self.Printf("(g) %-3v (%v)", gas, context.Gas) @@ -125,40 +117,40 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I switch op { // 0x20 range case ADD: - x, y := stack.Popn() + x, y := stack.pop(), stack.pop() self.Printf(" %v + %v", y, x) - base.Add(y, x) + base.Add(x, y) U256(base) self.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) + // pop result back on the stack + stack.push(base) case SUB: - x, y := stack.Popn() + x, y := stack.pop(), stack.pop() self.Printf(" %v - %v", y, x) - base.Sub(y, x) + base.Sub(x, y) U256(base) self.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) + // pop result back on the stack + stack.push(base) case MUL: - x, y := stack.Popn() + x, y := stack.pop(), stack.pop() self.Printf(" %v * %v", y, x) - base.Mul(y, x) + base.Mul(x, y) U256(base) self.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) + // pop result back on the stack + stack.push(base) case DIV: - x, y := stack.Pop(), stack.Pop() + x, y := stack.pop(), stack.pop() self.Printf(" %v / %v", x, y) if y.Cmp(ethutil.Big0) != 0 { @@ -168,10 +160,10 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I U256(base) self.Printf(" = %v", base) - // Pop result back on the stack - stack.Push(base) + // pop result back on the stack + stack.push(base) case SDIV: - x, y := S256(stack.Pop()), S256(stack.Pop()) + x, y := S256(stack.pop()), S256(stack.pop()) self.Printf(" %v / %v", x, y) @@ -191,9 +183,9 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } self.Printf(" = %v", base) - stack.Push(base) + stack.push(base) case MOD: - x, y := stack.Pop(), stack.Pop() + x, y := stack.pop(), stack.pop() self.Printf(" %v %% %v", x, y) @@ -206,9 +198,9 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I U256(base) self.Printf(" = %v", base) - stack.Push(base) + stack.push(base) case SMOD: - x, y := S256(stack.Pop()), S256(stack.Pop()) + x, y := S256(stack.pop()), S256(stack.pop()) self.Printf(" %v %% %v", x, y) @@ -228,25 +220,25 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } self.Printf(" = %v", base) - stack.Push(base) + stack.push(base) case EXP: - x, y := stack.Popn() + x, y := stack.pop(), stack.pop() - self.Printf(" %v ** %v", y, x) + self.Printf(" %v ** %v", x, y) - base.Exp(y, x, Pow256) + base.Exp(x, y, Pow256) U256(base) self.Printf(" = %v", base) - stack.Push(base) + stack.push(base) case SIGNEXTEND: - back := stack.Pop().Uint64() + back := stack.pop().Uint64() if back < 31 { bit := uint(back*8 + 7) - num := stack.Pop() + num := stack.pop() mask := new(big.Int).Lsh(ethutil.Big1, bit) mask.Sub(mask, ethutil.Big1) if ethutil.BitTest(num, int(bit)) { @@ -259,91 +251,91 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" = %v", num) - stack.Push(num) + stack.push(num) } case NOT: - base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1) + base.Sub(Pow256, stack.pop()).Sub(base, ethutil.Big1) // Not needed base = U256(base) - stack.Push(base) + stack.push(base) case LT: - x, y := stack.Popn() - self.Printf(" %v < %v", y, x) + x, y := stack.pop(), stack.pop() + self.Printf(" %v < %v", x, y) // x < y - if y.Cmp(x) < 0 { - stack.Push(ethutil.BigTrue) + if x.Cmp(y) < 0 { + stack.push(ethutil.BigTrue) } else { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) } case GT: - x, y := stack.Popn() - self.Printf(" %v > %v", y, x) + x, y := stack.pop(), stack.pop() + self.Printf(" %v > %v", x, y) // x > y - if y.Cmp(x) > 0 { - stack.Push(ethutil.BigTrue) + if x.Cmp(y) > 0 { + stack.push(ethutil.BigTrue) } else { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) } case SLT: - y, x := S256(stack.Pop()), S256(stack.Pop()) - self.Printf(" %v < %v", y, x) + x, y := S256(stack.pop()), S256(stack.pop()) + self.Printf(" %v < %v", x, y) // x < y - if y.Cmp(S256(x)) < 0 { - stack.Push(ethutil.BigTrue) + if x.Cmp(S256(y)) < 0 { + stack.push(ethutil.BigTrue) } else { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) } case SGT: - y, x := S256(stack.Pop()), S256(stack.Pop()) - self.Printf(" %v > %v", y, x) + x, y := S256(stack.pop()), S256(stack.pop()) + self.Printf(" %v > %v", x, y) // x > y - if y.Cmp(x) > 0 { - stack.Push(ethutil.BigTrue) + if x.Cmp(y) > 0 { + stack.push(ethutil.BigTrue) } else { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) } case EQ: - x, y := stack.Popn() + x, y := stack.pop(), stack.pop() self.Printf(" %v == %v", y, x) // x == y if x.Cmp(y) == 0 { - stack.Push(ethutil.BigTrue) + stack.push(ethutil.BigTrue) } else { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) } case ISZERO: - x := stack.Pop() + x := stack.pop() if x.Cmp(ethutil.BigFalse) > 0 { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) } else { - stack.Push(ethutil.BigTrue) + stack.push(ethutil.BigTrue) } // 0x10 range case AND: - x, y := stack.Popn() + x, y := stack.pop(), stack.pop() self.Printf(" %v & %v", y, x) - stack.Push(base.And(y, x)) + stack.push(base.And(x, y)) case OR: - x, y := stack.Popn() - self.Printf(" %v | %v", y, x) + x, y := stack.pop(), stack.pop() + self.Printf(" %v | %v", x, y) - stack.Push(base.Or(y, x)) + stack.push(base.Or(x, y)) case XOR: - x, y := stack.Popn() - self.Printf(" %v ^ %v", y, x) + x, y := stack.pop(), stack.pop() + self.Printf(" %v ^ %v", x, y) - stack.Push(base.Xor(y, x)) + stack.push(base.Xor(x, y)) case BYTE: - val, th := stack.Popn() + th, val := stack.pop(), stack.pop() if th.Cmp(big.NewInt(32)) < 0 { byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) @@ -355,12 +347,12 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" => 0x%x", base.Bytes()) - stack.Push(base) + stack.push(base) case ADDMOD: - x := stack.Pop() - y := stack.Pop() - z := stack.Pop() + x := stack.pop() + y := stack.pop() + z := stack.pop() add := new(big.Int).Add(x, y) if len(z.Bytes()) > 0 { // NOT 0x0 @@ -371,12 +363,12 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" %v + %v %% %v = %v", x, y, z, base) - stack.Push(base) + stack.push(base) case MULMOD: - x := stack.Pop() - y := stack.Pop() - z := stack.Pop() + x := stack.pop() + y := stack.pop() + z := stack.pop() mul := new(big.Int).Mul(x, y) if len(z.Bytes()) > 0 { // NOT 0x0 @@ -387,24 +379,24 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" %v + %v %% %v = %v", x, y, z, base) - stack.Push(base) + stack.push(base) // 0x20 range case SHA3: - size, offset := stack.Popn() + size, offset := stack.pop(), stack.pop() data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64())) - stack.Push(ethutil.BigD(data)) + stack.push(ethutil.BigD(data)) self.Printf(" => (%v) %x", size, data) // 0x30 range case ADDRESS: - stack.Push(ethutil.BigD(context.Address())) + stack.push(ethutil.BigD(context.Address())) self.Printf(" => %x", context.Address()) case BALANCE: - addr := stack.Pop().Bytes() + addr := stack.pop().Bytes() var balance *big.Int if statedb.GetStateObject(addr) != nil { balance = statedb.GetBalance(addr) @@ -412,27 +404,27 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I balance = base } - stack.Push(balance) + stack.push(balance) self.Printf(" => %v (%x)", balance, addr) case ORIGIN: origin := self.env.Origin() - stack.Push(ethutil.BigD(origin)) + stack.push(ethutil.BigD(origin)) self.Printf(" => %x", origin) case CALLER: caller := context.caller.Address() - stack.Push(ethutil.BigD(caller)) + stack.push(ethutil.BigD(caller)) self.Printf(" => %x", caller) case CALLVALUE: - stack.Push(value) + stack.push(value) self.Printf(" => %v", value) case CALLDATALOAD: var ( - offset = stack.Pop() + offset = stack.pop() data = make([]byte, 32) lenData = big.NewInt(int64(len(callData))) ) @@ -446,18 +438,18 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" => 0x%x", data) - stack.Push(ethutil.BigD(data)) + stack.push(ethutil.BigD(data)) case CALLDATASIZE: l := int64(len(callData)) - stack.Push(big.NewInt(l)) + stack.push(big.NewInt(l)) self.Printf(" => %d", l) case CALLDATACOPY: var ( size = uint64(len(callData)) - mOff = stack.Pop().Uint64() - cOff = stack.Pop().Uint64() - l = stack.Pop().Uint64() + mOff = stack.pop().Uint64() + cOff = stack.pop().Uint64() + l = stack.pop().Uint64() ) if cOff > size { @@ -475,7 +467,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { - addr := stack.Pop().Bytes() + addr := stack.pop().Bytes() code = statedb.GetCode(addr) } else { @@ -483,21 +475,21 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } l := big.NewInt(int64(len(code))) - stack.Push(l) + stack.push(l) self.Printf(" => %d", l) case CODECOPY, EXTCODECOPY: var code []byte if op == EXTCODECOPY { - code = statedb.GetCode(stack.Pop().Bytes()) + code = statedb.GetCode(stack.pop().Bytes()) } else { code = context.Code } context := NewContext(nil, nil, code, ethutil.Big0, ethutil.Big0) var ( - mOff = stack.Pop().Uint64() - cOff = stack.Pop().Uint64() - l = stack.Pop().Uint64() + mOff = stack.pop().Uint64() + cOff = stack.pop().Uint64() + l = stack.pop().Uint64() ) codeCopy := context.GetCode(cOff, l) @@ -505,80 +497,80 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy) case GASPRICE: - stack.Push(context.Price) + stack.push(context.Price) self.Printf(" => %x", context.Price) // 0x40 range case BLOCKHASH: - num := stack.Pop() + num := stack.pop() n := new(big.Int).Sub(self.env.BlockNumber(), ethutil.Big257) if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 { - stack.Push(ethutil.BigD(self.env.GetHash(num.Uint64()))) + stack.push(ethutil.BigD(self.env.GetHash(num.Uint64()))) } else { - stack.Push(ethutil.Big0) + stack.push(ethutil.Big0) } - self.Printf(" => 0x%x", stack.Peek().Bytes()) + self.Printf(" => 0x%x", stack.peek().Bytes()) case COINBASE: coinbase := self.env.Coinbase() - stack.Push(ethutil.BigD(coinbase)) + stack.push(ethutil.BigD(coinbase)) self.Printf(" => 0x%x", coinbase) case TIMESTAMP: time := self.env.Time() - stack.Push(big.NewInt(time)) + stack.push(big.NewInt(time)) self.Printf(" => 0x%x", time) case NUMBER: number := self.env.BlockNumber() - stack.Push(U256(number)) + stack.push(U256(number)) self.Printf(" => 0x%x", number.Bytes()) case DIFFICULTY: difficulty := self.env.Difficulty() - stack.Push(difficulty) + stack.push(difficulty) self.Printf(" => 0x%x", difficulty.Bytes()) case GASLIMIT: self.Printf(" => %v", self.env.GasLimit()) - stack.Push(self.env.GasLimit()) + stack.push(self.env.GasLimit()) // 0x50 range case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: a := uint64(op - PUSH1 + 1) byts := context.GetRangeValue(pc+1, a) - // Push value to stack - stack.Push(ethutil.BigD(byts)) + // push value to stack + stack.push(ethutil.BigD(byts)) pc += a step += int(op) - int(PUSH1) + 1 self.Printf(" => 0x%x", byts) case POP: - stack.Pop() + stack.pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) - stack.Dupn(n) + stack.dup(n) - self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) + self.Printf(" => [%d] 0x%x", n, stack.peek().Bytes()) case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) - x, y := stack.Swapn(n) + stack.swap(n) - self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) + self.Printf(" => [%d]", n) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) topics := make([][]byte, n) - mSize, mStart := stack.Popn() + mStart, mSize := stack.pop(), stack.pop() for i := 0; i < n; i++ { - topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32) + topics[i] = ethutil.LeftPadBytes(stack.pop().Bytes(), 32) } data := mem.Get(mStart.Int64(), mSize.Int64()) @@ -587,41 +579,40 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I self.Printf(" => %v", log) case MLOAD: - offset := stack.Pop() + offset := stack.pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) - stack.Push(val) + stack.push(val) self.Printf(" => 0x%x", val.Bytes()) case MSTORE: // Store the value at stack top-1 in to memory at location stack top - // Pop value of the stack - val, mStart := stack.Popn() + // pop value of the stack + mStart, val := stack.pop(), stack.pop() mem.Set(mStart.Uint64(), 32, ethutil.BigToBytes(val, 256)) self.Printf(" => 0x%x", val) case MSTORE8: - off := stack.Pop() - val := stack.Pop() + off, val := stack.pop(), stack.pop() mem.store[off.Int64()] = byte(val.Int64() & 0xff) self.Printf(" => [%v] 0x%x", off, val) case SLOAD: - loc := stack.Pop() + loc := stack.pop() val := ethutil.BigD(statedb.GetState(context.Address(), loc.Bytes())) - stack.Push(val) + stack.push(val) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case SSTORE: - val, loc := stack.Popn() + loc, val := stack.pop(), stack.pop() statedb.SetState(context.Address(), loc.Bytes(), val) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: - jump(pc, stack.Pop()) + jump(pc, stack.pop()) continue case JUMPI: - cond, pos := stack.Popn() + pos, cond := stack.pop(), stack.pop() if cond.Cmp(ethutil.BigTrue) >= 0 { jump(pc, pos) @@ -633,19 +624,19 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I case JUMPDEST: case PC: - stack.Push(big.NewInt(int64(pc))) + stack.push(big.NewInt(int64(pc))) case MSIZE: - stack.Push(big.NewInt(int64(mem.Len()))) + stack.push(big.NewInt(int64(mem.Len()))) case GAS: - stack.Push(context.Gas) + stack.push(context.Gas) self.Printf(" => %x", context.Gas) // 0x60 range case CREATE: var ( - value = stack.Pop() - size, offset = stack.Popn() + value = stack.pop() + offset, size = stack.pop(), stack.pop() input = mem.Get(offset.Int64(), size.Int64()) gas = new(big.Int).Set(context.Gas) addr []byte @@ -655,7 +646,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I context.UseGas(context.Gas) ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value) if suberr != nil { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) self.Printf(" (*) 0x0 %v", suberr) } else { @@ -668,23 +659,19 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } addr = ref.Address() - stack.Push(ethutil.BigD(addr)) + stack.push(ethutil.BigD(addr)) } - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(context.Code) - } case CALL, CALLCODE: - gas := stack.Pop() - // Pop gas and value of the stack. - value, addr := stack.Popn() + gas := stack.pop() + // pop gas and value of the stack. + addr, value := stack.pop(), stack.pop() value = U256(value) - // Pop input size and offset - inSize, inOffset := stack.Popn() - // Pop return size and offset - retSize, retOffset := stack.Popn() + // pop input size and offset + inOffset, inSize := stack.pop(), stack.pop() + // pop return size and offset + retOffset, retSize := stack.pop(), stack.pop() address := ethutil.Address(addr.Bytes()) self.Printf(" => %x", address).Endl() @@ -707,30 +694,24 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I } if err != nil { - stack.Push(ethutil.BigFalse) + stack.push(ethutil.BigFalse) vmlogger.Debugln(err) } else { - stack.Push(ethutil.BigTrue) + stack.push(ethutil.BigTrue) mem.Set(retOffset.Uint64(), retSize.Uint64(), ret) } self.Printf("resume %x (%v)", context.Address(), context.Gas) - - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(context.Code) - } - case RETURN: - size, offset := stack.Popn() + offset, size := stack.pop(), stack.pop() ret := mem.Get(offset.Int64(), size.Int64()) self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl() return context.Return(ret), nil case SUICIDE: - receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) + receiver := statedb.GetOrNewStateObject(stack.pop().Bytes()) balance := statedb.GetBalance(context.Address()) self.Printf(" => (%x) %v", receiver.Address()[:4], balance) @@ -753,117 +734,17 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I pc++ self.Endl() - - if self.Dbg != nil { - for _, instrNo := range self.Dbg.BreakPoints() { - if pc == uint64(instrNo) { - self.Stepping = true - - if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(context.Address())) { - return nil, nil - } - } else if self.Stepping { - if !self.Dbg.StepHook(prevStep, op, mem, stack, statedb.GetStateObject(context.Address())) { - return nil, nil - } - } - } - } - } } -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}, - CALLDATASIZE: {0, GasQuickStep}, - DIFFICULTY: {0, GasQuickStep}, - GASLIMIT: {0, GasQuickStep}, - POP: {0, GasQuickStep}, - PC: {0, GasQuickStep}, - MSIZE: {0, GasQuickStep}, - GAS: {0, GasQuickStep}, - BLOCKHASH: {1, GasExtStep}, - BALANCE: {0, GasExtStep}, - EXTCODESIZE: {1, GasExtStep}, - EXTCODECOPY: {4, GasExtStep}, - SLOAD: {1, GasStorageGet}, - SSTORE: {2, Zero}, - SHA3: {1, GasSha3Base}, - CREATE: {3, GasCreate}, - CALL: {7, GasCall}, - CALLCODE: {7, GasCall}, - JUMPDEST: {0, GasJumpDest}, - SUICIDE: {1, Zero}, - RETURN: {2, Zero}, -} - -func baseCheck(op OpCode, stack *Stack, gas *big.Int) { - if r, ok := _baseCheck[op]; ok { - stack.require(r.stack) - - gas.Add(gas, r.gas) - } -} - -func toWordSize(size *big.Int) *big.Int { - tmp := new(big.Int) - tmp.Add(size, 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) { +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) - // Stack Check, memory resize & gas phase + // stack Check, memory resize & gas phase switch op { case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: gas.Set(GasFastestStep) @@ -879,7 +760,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo n := int(op - LOG0) stack.require(n + 2) - mSize, mStart := stack.Peekn() + mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] gas.Add(gas, GasLogBase) gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic)) @@ -887,12 +768,12 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo newMemSize = calcMemSize(mStart, mSize) case EXP: - gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()))), GasExpByte)) + gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte)) case SSTORE: stack.require(2) var g *big.Int - y, x := stack.Peekn() + y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] val := statedb.GetState(context.Address(), x.Bytes()) if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 @@ -911,51 +792,51 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo statedb.Refund(self.env.Origin(), RefundSuicide) } case MLOAD: - newMemSize = calcMemSize(stack.Peek(), u256(32)) + newMemSize = calcMemSize(stack.peek(), u256(32)) case MSTORE8: - newMemSize = calcMemSize(stack.Peek(), u256(1)) + newMemSize = calcMemSize(stack.peek(), u256(1)) case MSTORE: - newMemSize = calcMemSize(stack.Peek(), u256(32)) + newMemSize = calcMemSize(stack.peek(), u256(32)) case RETURN: - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) case SHA3: - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) - words := toWordSize(stack.data[stack.Len()-2]) + 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]) + newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) - words := toWordSize(stack.data[stack.Len()-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]) + newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) - words := toWordSize(stack.data[stack.Len()-3]) + 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]) + newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) - words := toWordSize(stack.data[stack.Len()-4]) + words := toWordSize(stack.data[stack.len()-4]) gas.Add(gas, words.Mul(words, GasCopyWord)) case CREATE: - newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) + newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) case CALL, CALLCODE: - gas.Add(gas, 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 { + if self.env.State().GetStateObject(stack.data[stack.len()-2].Bytes()) == nil { gas.Add(gas, GasCallNewAccount) } } - if len(stack.data[stack.Len()-3].Bytes()) > 0 { + if len(stack.data[stack.len()-3].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]) + 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) } -- cgit v1.2.3 From 0d64163fea3a266ceb71cb4c4ee5682052c9ca6c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 10 Mar 2015 01:13:06 +0100 Subject: Right pad zeros. Closes #446 --- vm/context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/context.go b/vm/context.go index b48f1a657..9ce07bc4a 100644 --- a/vm/context.go +++ b/vm/context.go @@ -58,7 +58,7 @@ func (c *Context) GetRangeValue(x, size uint64) []byte { x = uint64(math.Min(float64(x), float64(len(c.Code)))) y := uint64(math.Min(float64(x+size), float64(len(c.Code)))) - return ethutil.LeftPadBytes(c.Code[x:y], int(size)) + return ethutil.RightPadBytes(c.Code[x:y], int(size)) } func (c *Context) GetCode(x, size uint64) []byte { -- cgit v1.2.3