Commit 73761f7a authored by obscuren's avatar obscuren

Closure call now returns the total usage as well

* Return the used gas value based on the UseGas and ReturnGas
parent 1c01e9c0
...@@ -22,8 +22,7 @@ type Closure struct { ...@@ -22,8 +22,7 @@ type Closure struct {
Script []byte Script []byte
State *State State *State
Gas *big.Int Gas, UsedGas, Price *big.Int
Price *big.Int
Args []byte Args []byte
} }
...@@ -74,10 +73,12 @@ func (c *Closure) Address() []byte { ...@@ -74,10 +73,12 @@ func (c *Closure) Address() []byte {
type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, error) {
c.Args = args c.Args = args
return vm.RunClosure(c, hook) ret, err := vm.RunClosure(c, hook)
return ret, c.UsedGas, err
} }
func (c *Closure) Return(ret []byte) []byte { func (c *Closure) Return(ret []byte) []byte {
...@@ -93,10 +94,23 @@ func (c *Closure) Return(ret []byte) []byte { ...@@ -93,10 +94,23 @@ func (c *Closure) Return(ret []byte) []byte {
return ret return ret
} }
func (c *Closure) UseGas(gas *big.Int) bool {
if c.Gas.Cmp(gas) < 0 {
return false
}
// Sub the amount of gas from the remaining
c.Gas.Sub(c.Gas, gas)
c.UsedGas.Add(c.UsedGas, gas)
return true
}
// Implement the Callee interface // Implement the Callee interface
func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
// Return the gas to the closure // Return the gas to the closure
c.Gas.Add(c.Gas, gas) c.Gas.Add(c.Gas, gas)
c.UsedGas.Sub(c.UsedGas, gas)
} }
func (c *Closure) Object() *StateObject { func (c *Closure) Object() *StateObject {
......
...@@ -106,7 +106,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra ...@@ -106,7 +106,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra
usedGas, err := sm.ApplyTransaction(state, block, tx) usedGas, err := sm.ApplyTransaction(state, block, tx)
if err != nil { if err != nil {
ethutil.Config.Log.Infoln(err) ethutil.Config.Log.Infoln(err)
continue //continue
} }
accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas))
...@@ -119,7 +119,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra ...@@ -119,7 +119,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra
return receipts, txs return receipts, txs
} }
func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) {
/* /*
Applies transactions to the given state and creates new Applies transactions to the given state and creates new
state objects where needed. state objects where needed.
...@@ -129,9 +129,17 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac ...@@ -129,9 +129,17 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac
assume there's a return value. The return value will be set to assume there's a return value. The return value will be set to
the script section of the state object. the script section of the state object.
*/ */
totalGasUsed := big.NewInt(0) var (
addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) }
gas = new(big.Int)
script []byte
)
totalGasUsed = big.NewInt(0)
// Apply the transaction to the current state // Apply the transaction to the current state
err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false)
addTotalGas(gas)
if tx.CreatesContract() { if tx.CreatesContract() {
if err == nil { if err == nil {
// Create a new state object and the transaction // Create a new state object and the transaction
...@@ -141,30 +149,32 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac ...@@ -141,30 +149,32 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac
// Evaluate the initialization script // Evaluate the initialization script
// and use the return value as the // and use the return value as the
// script section for the state object. // script section for the state object.
script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block)
addTotalGas(gas)
if err != nil { if err != nil {
return nil, fmt.Errorf("[STATE] Error during init script run %v", err) err = fmt.Errorf("[STATE] Error during init script run %v", err)
return
} }
contract.script = script contract.script = script
state.UpdateStateObject(contract) state.UpdateStateObject(contract)
} else { } else {
return nil, fmt.Errorf("[STATE] Unable to create contract") err = fmt.Errorf("[STATE] Unable to create contract")
} }
} else { } else {
return nil, fmt.Errorf("[STATE] contract creation tx:", err) err = fmt.Errorf("[STATE] contract creation tx: %v", err)
} }
} else { } else {
// Find the state object at the "recipient" address. If // Find the state object at the "recipient" address. If
// there's an object attempt to run the script. // there's an object attempt to run the script.
stateObject := state.GetStateObject(tx.Recipient) stateObject := state.GetStateObject(tx.Recipient)
if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { if err == nil && stateObject != nil && len(stateObject.Script()) > 0 {
sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block)
} else if err != nil { addTotalGas(gas)
return nil, fmt.Errorf("[STATE] process:", err)
} }
} }
return totalGasUsed, nil return
} }
func (sm *StateManager) Process(block *Block, dontReact bool) error { func (sm *StateManager) Process(block *Block, dontReact bool) error {
...@@ -349,7 +359,7 @@ func (sm *StateManager) Stop() { ...@@ -349,7 +359,7 @@ func (sm *StateManager) Stop() {
sm.bc.Stop() sm.bc.Stop()
} }
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) { func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) {
account := state.GetAccount(tx.Sender()) account := state.GetAccount(tx.Sender())
err = account.ConvertGas(tx.Gas, tx.GasPrice) err = account.ConvertGas(tx.Gas, tx.GasPrice)
...@@ -369,7 +379,7 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj ...@@ -369,7 +379,7 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj
Value: tx.Value, Value: tx.Value,
//Price: tx.GasPrice, //Price: tx.GasPrice,
}) })
ret, err = closure.Call(vm, tx.Data, nil) ret, gas, err = closure.Call(vm, tx.Data, nil)
// Update the account (refunds) // Update the account (refunds)
state.UpdateStateObject(account) state.UpdateStateObject(account)
......
...@@ -91,28 +91,37 @@ func (pool *TxPool) addTransaction(tx *Transaction) { ...@@ -91,28 +91,37 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
// Process transaction validates the Tx and processes funds from the // Process transaction validates the Tx and processes funds from the
// sender to the recipient. // sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
ethutil.Config.Log.Infoln(r) ethutil.Config.Log.Infoln(r)
err = fmt.Errorf("%v", r) err = fmt.Errorf("%v", r)
} }
}() }()
gas = new(big.Int)
addGas := func(g *big.Int) { gas.Add(gas, g) }
// Get the sender // Get the sender
sender := state.GetAccount(tx.Sender()) sender := state.GetAccount(tx.Sender())
if sender.Nonce != tx.Nonce { if sender.Nonce != tx.Nonce {
return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) err = fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce)
return
} }
txTotalBytes := big.NewInt(int64(len(tx.Data)))
txTotalBytes.Div(txTotalBytes, ethutil.Big32)
addGas(new(big.Int).Mul(txTotalBytes, GasSStore))
// Make sure there's enough in the sender's account. Having insufficient // Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it. // funds won't invalidate this transaction but simple ignores it.
//totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) //totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice))
if sender.Amount.Cmp(totAmount) < 0 { if sender.Amount.Cmp(totAmount) < 0 {
return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
return
} }
//fmt.Println(tx)
// Get the receiver // Get the receiver
receiver := state.GetAccount(tx.Recipient) receiver := state.GetAccount(tx.Recipient)
...@@ -120,6 +129,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract ...@@ -120,6 +129,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract
// Send Tx to self // Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
addGas(GasTx)
// Subtract the fee // Subtract the fee
sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice))
} else { } else {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment