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