Added proper gas handling

pull/150/head
obscuren 11 years ago
parent c5729d7ecc
commit a96c8c8af9
  1. 5
      ethchain/closure.go
  2. 3
      ethchain/state_manager.go
  3. 12
      ethchain/transaction.go
  4. 9
      ethchain/vm.go
  5. 17
      ethchain/vm_test.go

@ -27,14 +27,15 @@ type Closure struct {
State *State State *State
Gas *big.Int Gas *big.Int
Price *big.Int
Value *big.Int Value *big.Int
Args []byte Args []byte
} }
// Create a new closure for the given data items // Create a new closure for the given data items
func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, val *big.Int) *Closure { func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure {
return &Closure{callee, object, script, state, gas, val, nil} return &Closure{callee, object, script, state, gas, price, val, nil}
} }
// Retuns the x element in data slice // Retuns the x element in data slice

@ -310,7 +310,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
}() }()
caller := sm.procState.GetAccount(tx.Sender()) 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{ vm := NewVm(sm.procState, RuntimeVars{
Origin: caller.Address(), Origin: caller.Address(),
BlockNumber: block.BlockInfo().Number, BlockNumber: block.BlockInfo().Number,
@ -318,6 +318,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
Coinbase: block.Coinbase, Coinbase: block.Coinbase,
Time: block.Time, Time: block.Time,
Diff: block.Difficulty, Diff: block.Difficulty,
//Price: tx.GasPrice,
}) })
closure.Call(vm, nil, nil) closure.Call(vm, nil, nil)

@ -13,7 +13,7 @@ type Transaction struct {
Recipient []byte Recipient []byte
Value *big.Int Value *big.Int
Gas *big.Int Gas *big.Int
Gasprice *big.Int GasPrice *big.Int
Data []byte Data []byte
Init []byte Init []byte
v byte v byte
@ -24,11 +24,11 @@ type Transaction struct {
} }
func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { 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 { 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 { func NewTransactionFromBytes(data []byte) *Transaction {
@ -46,7 +46,7 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
} }
func (tx *Transaction) Hash() []byte { 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 { if tx.contractCreation {
data = append(data, string(tx.Init)) 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, TO, DATA, V, R, S ]
// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] // [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ]
func (tx *Transaction) RlpData() interface{} { 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 { if tx.contractCreation {
data = append(data, tx.Init) data = append(data, tx.Init)
@ -132,7 +132,7 @@ func (tx *Transaction) RlpDecode(data []byte) {
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
tx.Nonce = decoder.Get(0).Uint() tx.Nonce = decoder.Get(0).Uint()
tx.Value = decoder.Get(1).BigInt() 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.Gas = decoder.Get(3).BigInt()
tx.Recipient = decoder.Get(4).Bytes() tx.Recipient = decoder.Get(4).Bytes()
tx.Data = decoder.Get(5).Bytes() tx.Data = decoder.Get(5).Bytes()

@ -71,7 +71,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// New stack (should this be shared?) // New stack (should this be shared?)
stack := NewStack() stack := NewStack()
require := func(m int) { require := func(m int) {
if stack.Len()-1 > m { if stack.Len() < m {
isRequireError = true isRequireError = true
panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) 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 // TODO Get each instruction cost properly
gas := new(big.Int) gas := new(big.Int)
useGas := func(amount *big.Int) { useGas := func(amount *big.Int) {
gas.Add(gas, amount) gas.Add(gas, new(big.Int).Mul(amount, closure.Price))
} }
switch op { 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) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas)
} }
closure.Gas.Sub(closure.Gas, gas)
switch op { switch op {
case oLOG: case oLOG:
@ -411,7 +412,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// 0x60 range // 0x60 range
case oCREATE: case oCREATE:
case oCALL: case oCALL:
require(8) require(7)
// Closure addr // Closure addr
addr := stack.Pop() addr := stack.Pop()
// Pop gas and value of the stack. // 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 // Fetch the contract which will serve as the closure body
contract := vm.state.GetContract(addr.Bytes()) contract := vm.state.GetContract(addr.Bytes())
// Create a new callable closure // 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) // Executer the closure and get the return value (if any)
ret, err := closure.Call(vm, args, hook) ret, err := closure.Call(vm, args, hook)
if err != nil { if err != nil {

@ -91,10 +91,10 @@ func TestRun4(t *testing.T) {
exit() exit()
`), false) `), false)
script := ethutil.Assemble(asm...) 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:] addr := tx.Hash()[12:]
contract := MakeContract(tx, state) contract := MakeContract(tx, state)
state.UpdateContract(contract) state.UpdateStateObject(contract)
fmt.Printf("%x\n", addr) fmt.Printf("%x\n", addr)
asm, err = mutan.Compile(strings.NewReader(` asm, err = mutan.Compile(strings.NewReader(`
@ -122,12 +122,13 @@ func TestRun4(t *testing.T) {
fmt.Println(asm) fmt.Println(asm)
callerScript := ethutil.Assemble(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 // Contract addr as test address
account := NewAccount(ContractAddr, big.NewInt(10000000)) account := NewAccount(ContractAddr, big.NewInt(10000000))
fmt.Println(account)
c := MakeContract(callerTx, state) 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{ vm := NewVm(state, RuntimeVars{
Origin: account.Address(), Origin: account.Address(),
@ -136,10 +137,12 @@ func TestRun4(t *testing.T) {
Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
Time: 1, Time: 1,
Diff: big.NewInt(256), 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) { func TestRun5(t *testing.T) {

Loading…
Cancel
Save