From a96c8c8af969665cc0c357eef81d43b5b7285dfe Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Apr 2014 13:41:07 +0200 Subject: [PATCH] Added proper gas handling --- ethchain/closure.go | 5 +++-- ethchain/state_manager.go | 3 ++- ethchain/transaction.go | 12 ++++++------ ethchain/vm.go | 9 +++++---- ethchain/vm_test.go | 17 ++++++++++------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 0762e8f49..5c508179e 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -27,14 +27,15 @@ type Closure struct { State *State Gas *big.Int + Price *big.Int Value *big.Int Args []byte } // Create a new closure for the given data items -func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, script, state, gas, val, nil} +func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { + return &Closure{callee, object, script, state, gas, price, val, nil} } // Retuns the x element in data slice diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5e30d7280..75a78e9f3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -310,7 +310,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, @@ -318,6 +318,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, + //Price: tx.GasPrice, }) closure.Call(vm, nil, nil) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 78044e840..1e43a2bae 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,7 +13,7 @@ type Transaction struct { Recipient []byte Value *big.Int Gas *big.Int - Gasprice *big.Int + GasPrice *big.Int Data []byte Init []byte v byte @@ -24,11 +24,11 @@ type Transaction struct { } func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true} + return &Transaction{Value: value, GasPrice: gasprice, Data: script, Init: init, contractCreation: true} } func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} + return &Transaction{Recipient: to, Value: value, GasPrice: gasprice, Gas: gas, Data: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -46,7 +46,7 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, string(tx.Data)} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, string(tx.Data)} if tx.contractCreation { data = append(data, string(tx.Init)) } @@ -107,7 +107,7 @@ func (tx *Transaction) Sign(privk []byte) error { // [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] // [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -132,7 +132,7 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() - tx.Gasprice = decoder.Get(2).BigInt() + tx.GasPrice = decoder.Get(2).BigInt() tx.Gas = decoder.Get(3).BigInt() tx.Recipient = decoder.Get(4).Bytes() tx.Data = decoder.Get(5).Bytes() diff --git a/ethchain/vm.go b/ethchain/vm.go index 33d667457..85aefa685 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -71,7 +71,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // New stack (should this be shared?) stack := NewStack() require := func(m int) { - if stack.Len()-1 > m { + if stack.Len() < m { isRequireError = true panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) } @@ -105,7 +105,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // TODO Get each instruction cost properly gas := new(big.Int) useGas := func(amount *big.Int) { - gas.Add(gas, amount) + gas.Add(gas, new(big.Int).Mul(amount, closure.Price)) } switch op { @@ -142,6 +142,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + closure.Gas.Sub(closure.Gas, gas) switch op { case oLOG: @@ -411,7 +412,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // 0x60 range case oCREATE: case oCALL: - require(8) + require(7) // Closure addr addr := stack.Pop() // Pop gas and value of the stack. @@ -425,7 +426,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index a0add9532..f66f2a896 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -91,10 +91,10 @@ func TestRun4(t *testing.T) { exit() `), false) script := ethutil.Assemble(asm...) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) - state.UpdateContract(contract) + state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) asm, err = mutan.Compile(strings.NewReader(` @@ -122,12 +122,13 @@ func TestRun4(t *testing.T) { fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) + fmt.Println(account) c := MakeContract(callerTx, state) - callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) + callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), big.NewInt(10), big.NewInt(0)) vm := NewVm(state, RuntimeVars{ Origin: account.Address(), @@ -136,10 +137,12 @@ func TestRun4(t *testing.T) { Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Time: 1, Diff: big.NewInt(256), - // XXX Tx data? Could be just an argument to the closure instead - TxData: nil, }) - callerClosure.Call(vm, nil, nil) + _, e := callerClosure.Call(vm, nil, nil) + if e != nil { + fmt.Println("error", e) + } + fmt.Println(account) } func TestRun5(t *testing.T) {