From a96c8c8af969665cc0c357eef81d43b5b7285dfe Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Fri, 18 Apr 2014 13:41:07 +0200
Subject: 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(-)

(limited to 'ethchain')

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) {
-- 
cgit v1.2.3