Updated VM
This commit is contained in:
parent
a96c8c8af9
commit
6930260962
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type Callee interface {
|
||||
ReturnGas(*big.Int, *State)
|
||||
ReturnGas(*big.Int, *big.Int, *State)
|
||||
Address() []byte
|
||||
}
|
||||
|
||||
@ -83,18 +83,16 @@ func (c *Closure) Return(ret []byte) []byte {
|
||||
// If no callee is present return it to
|
||||
// the origin (i.e. contract or tx)
|
||||
if c.callee != nil {
|
||||
c.callee.ReturnGas(c.Gas, c.State)
|
||||
c.callee.ReturnGas(c.Gas, c.Price, c.State)
|
||||
} else {
|
||||
c.object.ReturnGas(c.Gas, c.State)
|
||||
// TODO incase it's a POST contract we gotta serialise the contract again.
|
||||
// But it's not yet defined
|
||||
c.object.ReturnGas(c.Gas, c.Price, c.State)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Implement the Callee interface
|
||||
func (c *Closure) ReturnGas(gas *big.Int, state *State) {
|
||||
func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
|
||||
// Return the gas to the closure
|
||||
c.Gas.Add(c.Gas, gas)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ethchain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ethereum/eth-go/ethutil"
|
||||
"math/big"
|
||||
)
|
||||
@ -70,8 +71,9 @@ func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) {
|
||||
}
|
||||
|
||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||
func (c *StateObject) ReturnGas(val *big.Int, state *State) {
|
||||
c.AddAmount(val)
|
||||
func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {
|
||||
remainder := new(big.Int).Mul(gas, price)
|
||||
c.AddAmount(remainder)
|
||||
}
|
||||
|
||||
func (c *StateObject) AddAmount(amount *big.Int) {
|
||||
@ -82,18 +84,33 @@ func (c *StateObject) SubAmount(amount *big.Int) {
|
||||
c.Amount.Sub(c.Amount, amount)
|
||||
}
|
||||
|
||||
func (c *StateObject) ConvertGas(gas, price *big.Int) error {
|
||||
total := new(big.Int).Mul(gas, price)
|
||||
if total.Cmp(c.Amount) > 0 {
|
||||
return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total)
|
||||
}
|
||||
|
||||
c.SubAmount(total)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the address of the contract/account
|
||||
func (c *StateObject) Address() []byte {
|
||||
return c.address
|
||||
}
|
||||
|
||||
// Returns the main script body
|
||||
func (c *StateObject) Script() []byte {
|
||||
return c.script
|
||||
}
|
||||
|
||||
// Returns the initialization script
|
||||
func (c *StateObject) Init() []byte {
|
||||
return c.initScript
|
||||
}
|
||||
|
||||
// State object encoding methods
|
||||
func (c *StateObject) RlpEncode() []byte {
|
||||
var root interface{}
|
||||
if c.state != nil {
|
||||
@ -113,6 +130,7 @@ func (c *StateObject) RlpDecode(data []byte) {
|
||||
c.script = decoder.Get(3).Bytes()
|
||||
}
|
||||
|
||||
// Converts an transaction in to a state object
|
||||
func MakeContract(tx *Transaction, state *State) *StateObject {
|
||||
// Create contract if there's no recipient
|
||||
if tx.IsContract() {
|
||||
|
@ -102,10 +102,9 @@ 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, new(big.Int).Mul(amount, closure.Price))
|
||||
gas.Add(gas, amount)
|
||||
}
|
||||
|
||||
switch op {
|
||||
@ -142,6 +141,8 @@ 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)
|
||||
}
|
||||
|
||||
// Sub the amount of gas from the remaining
|
||||
closure.Gas.Sub(closure.Gas, gas)
|
||||
|
||||
switch op {
|
||||
@ -157,7 +158,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
x, y := stack.Popn()
|
||||
// (x + y) % 2 ** 256
|
||||
base.Add(x, y)
|
||||
base.Mod(base, Pow256)
|
||||
// Pop result back on the stack
|
||||
stack.Push(base)
|
||||
case oSUB:
|
||||
@ -165,7 +165,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
x, y := stack.Popn()
|
||||
// (x - y) % 2 ** 256
|
||||
base.Sub(x, y)
|
||||
base.Mod(base, Pow256)
|
||||
// Pop result back on the stack
|
||||
stack.Push(base)
|
||||
case oMUL:
|
||||
@ -173,7 +172,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
x, y := stack.Popn()
|
||||
// (x * y) % 2 ** 256
|
||||
base.Mul(x, y)
|
||||
base.Mod(base, Pow256)
|
||||
// Pop result back on the stack
|
||||
stack.Push(base)
|
||||
case oDIV:
|
||||
@ -325,7 +323,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
case oCALLDATASIZE:
|
||||
stack.Push(big.NewInt(int64(len(closure.Args))))
|
||||
case oGASPRICE:
|
||||
// TODO
|
||||
stack.Push(closure.Price)
|
||||
|
||||
// 0x40 range
|
||||
case oPREVHASH:
|
||||
@ -340,6 +338,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
stack.Push(vm.vars.Diff)
|
||||
case oGASLIMIT:
|
||||
// TODO
|
||||
stack.Push(big.NewInt(0))
|
||||
|
||||
// 0x50 range
|
||||
case oPUSH: // Push PC+1 on to the stack
|
||||
@ -399,11 +398,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
case oJUMP:
|
||||
require(1)
|
||||
pc = stack.Pop()
|
||||
// Reduce pc by one because of the increment that's at the end of this for loop
|
||||
pc.Sub(pc, ethutil.Big1)
|
||||
case oJUMPI:
|
||||
require(2)
|
||||
cond, pos := stack.Popn()
|
||||
if cond.Cmp(ethutil.BigTrue) == 0 {
|
||||
pc = pos
|
||||
pc.Sub(pc, ethutil.Big1)
|
||||
}
|
||||
case oPC:
|
||||
stack.Push(pc)
|
||||
@ -421,10 +423,24 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
inSize, inOffset := stack.Popn()
|
||||
// Pop return size and offset
|
||||
retSize, retOffset := stack.Popn()
|
||||
// Make sure there's enough gas
|
||||
if closure.Gas.Cmp(gas) < 0 {
|
||||
stack.Push(ethutil.BigFalse)
|
||||
|
||||
break
|
||||
}
|
||||
// Get the arguments from the memory
|
||||
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
||||
// Fetch the contract which will serve as the closure body
|
||||
contract := vm.state.GetContract(addr.Bytes())
|
||||
|
||||
if contract != nil {
|
||||
// Prepay for the gas
|
||||
// If gas is set to 0 use all remaining gas for the next call
|
||||
if gas.Cmp(big.NewInt(0)) == 0 {
|
||||
gas = closure.Gas
|
||||
}
|
||||
closure.Gas.Sub(closure.Gas, gas)
|
||||
// Create a new callable closure
|
||||
closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value)
|
||||
// Executer the closure and get the return value (if any)
|
||||
@ -436,6 +452,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
}
|
||||
|
||||
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
||||
} else {
|
||||
ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes())
|
||||
stack.Push(ethutil.BigFalse)
|
||||
}
|
||||
case oRETURN:
|
||||
require(2)
|
||||
size, offset := stack.Popn()
|
||||
|
@ -86,9 +86,9 @@ func TestRun4(t *testing.T) {
|
||||
int32 a = 10
|
||||
int32 b = 20
|
||||
if a > b {
|
||||
int32 c = this.caller()
|
||||
int32 c = this.Caller()
|
||||
}
|
||||
exit()
|
||||
Exit()
|
||||
`), false)
|
||||
script := ethutil.Assemble(asm...)
|
||||
tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil)
|
||||
@ -103,8 +103,9 @@ func TestRun4(t *testing.T) {
|
||||
store[1000] = 10^20
|
||||
}
|
||||
|
||||
store[1001] = this.value() * 20
|
||||
store[this.origin()] = store[this.origin()] + 1000
|
||||
|
||||
store[1001] = this.Value() * 20
|
||||
store[this.Origin()] = store[this.Origin()] + 1000
|
||||
|
||||
if store[1001] > 20 {
|
||||
store[1001] = 10^50
|
||||
@ -112,8 +113,18 @@ func TestRun4(t *testing.T) {
|
||||
|
||||
int8 ret = 0
|
||||
int8 arg = 10
|
||||
store[1002] = "a46df28529eb8aa8b8c025b0b413c5f4b688352f"
|
||||
call(store[1002], 0, 100000000, arg, ret)
|
||||
Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret)
|
||||
|
||||
big t
|
||||
for int8 i = 0; i < 10; i++ {
|
||||
t = i
|
||||
}
|
||||
|
||||
if 10 > 20 {
|
||||
int8 shouldnt = 2
|
||||
} else {
|
||||
int8 should = 1
|
||||
}
|
||||
`), false)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@ -125,10 +136,17 @@ func TestRun4(t *testing.T) {
|
||||
callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil)
|
||||
|
||||
// Contract addr as test address
|
||||
gas := big.NewInt(1000)
|
||||
gasPrice := big.NewInt(10)
|
||||
account := NewAccount(ContractAddr, big.NewInt(10000000))
|
||||
fmt.Println(account)
|
||||
fmt.Println("account.Amount =", account.Amount)
|
||||
c := MakeContract(callerTx, state)
|
||||
callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), big.NewInt(10), big.NewInt(0))
|
||||
e := account.ConvertGas(gas, gasPrice)
|
||||
if e != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("account.Amount =", account.Amount)
|
||||
callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0))
|
||||
|
||||
vm := NewVm(state, RuntimeVars{
|
||||
Origin: account.Address(),
|
||||
@ -138,11 +156,11 @@ func TestRun4(t *testing.T) {
|
||||
Time: 1,
|
||||
Diff: big.NewInt(256),
|
||||
})
|
||||
_, e := callerClosure.Call(vm, nil, nil)
|
||||
_, e = callerClosure.Call(vm, nil, nil)
|
||||
if e != nil {
|
||||
fmt.Println("error", e)
|
||||
}
|
||||
fmt.Println(account)
|
||||
fmt.Println("account.Amount =", account.Amount)
|
||||
}
|
||||
|
||||
func TestRun5(t *testing.T) {
|
||||
@ -156,6 +174,5 @@ func TestRun5(t *testing.T) {
|
||||
}
|
||||
exit()
|
||||
`), false)
|
||||
script := ethutil.Assemble(asm...)
|
||||
fmt.Println(Disassemble(script))
|
||||
ethutil.Assemble(asm...)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user