forked from cerc-io/plugeth
Implemented POST
This commit is contained in:
parent
cdbc3ecc2a
commit
3f904bf3ac
@ -278,6 +278,15 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context
|
|||||||
|
|
||||||
ret, _, err = callerClosure.Call(vm, self.tx.Data)
|
ret, _, err = callerClosure.Call(vm, self.tx.Data)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// Execute POSTs
|
||||||
|
for e := vm.Queue().Front(); e != nil; e = e.Next() {
|
||||||
|
msg := e.Value.(*ethvm.Message)
|
||||||
|
|
||||||
|
msg.Exec(transactor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +245,7 @@ func (self *StateObject) Copy() *StateObject {
|
|||||||
stateObject.InitCode = ethutil.CopyBytes(self.InitCode)
|
stateObject.InitCode = ethutil.CopyBytes(self.InitCode)
|
||||||
stateObject.storage = self.storage.Copy()
|
stateObject.storage = self.storage.Copy()
|
||||||
stateObject.gasPool.Set(self.gasPool)
|
stateObject.gasPool.Set(self.gasPool)
|
||||||
|
stateObject.remove = self.remove
|
||||||
|
|
||||||
return stateObject
|
return stateObject
|
||||||
}
|
}
|
||||||
@ -271,6 +272,11 @@ func (c *StateObject) Init() Code {
|
|||||||
return c.InitCode
|
return c.InitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To satisfy ClosureRef
|
||||||
|
func (self *StateObject) Object() *StateObject {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
// Debug stuff
|
// Debug stuff
|
||||||
func (self *StateObject) CreateOutputForDiff() {
|
func (self *StateObject) CreateOutputForDiff() {
|
||||||
fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Balance.Bytes(), self.Nonce)
|
fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Balance.Bytes(), self.Nonce)
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
type ClosureRef interface {
|
type ClosureRef interface {
|
||||||
ReturnGas(*big.Int, *big.Int)
|
ReturnGas(*big.Int, *big.Int)
|
||||||
Address() []byte
|
Address() []byte
|
||||||
|
Object() *ethstate.StateObject
|
||||||
GetStorage(*big.Int) *ethutil.Value
|
GetStorage(*big.Int) *ethutil.Value
|
||||||
SetStorage(*big.Int, *ethutil.Value)
|
SetStorage(*big.Int, *ethutil.Value)
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,7 @@ const (
|
|||||||
CREATE = 0xf0
|
CREATE = 0xf0
|
||||||
CALL = 0xf1
|
CALL = 0xf1
|
||||||
RETURN = 0xf2
|
RETURN = 0xf2
|
||||||
|
POST = 0xf3
|
||||||
|
|
||||||
// 0x70 range - other
|
// 0x70 range - other
|
||||||
LOG = 0xfe // XXX Unofficial
|
LOG = 0xfe // XXX Unofficial
|
||||||
@ -438,6 +439,7 @@ var OpCodes = map[string]byte{
|
|||||||
"CREATE": 0xf0,
|
"CREATE": 0xf0,
|
||||||
"CALL": 0xf1,
|
"CALL": 0xf1,
|
||||||
"RETURN": 0xf2,
|
"RETURN": 0xf2,
|
||||||
|
"POST": 0xf3,
|
||||||
|
|
||||||
// 0x70 range - other
|
// 0x70 range - other
|
||||||
"LOG": 0xfe,
|
"LOG": 0xfe,
|
||||||
|
277
ethvm/vm.go
277
ethvm/vm.go
@ -1,6 +1,7 @@
|
|||||||
package ethvm
|
package ethvm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -18,11 +19,6 @@ type Debugger interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
// Stack for processing contracts
|
|
||||||
stack *Stack
|
|
||||||
// non-persistent key/value memory storage
|
|
||||||
mem map[string]*big.Int
|
|
||||||
|
|
||||||
env Environment
|
env Environment
|
||||||
|
|
||||||
Verbose bool
|
Verbose bool
|
||||||
@ -40,6 +36,8 @@ type Vm struct {
|
|||||||
Fn string
|
Fn string
|
||||||
|
|
||||||
Recoverable bool
|
Recoverable bool
|
||||||
|
|
||||||
|
queue *list.List
|
||||||
}
|
}
|
||||||
|
|
||||||
type Environment interface {
|
type Environment interface {
|
||||||
@ -66,7 +64,7 @@ func New(env Environment) *Vm {
|
|||||||
lt = LogTyDiff
|
lt = LogTyDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Vm{env: env, logTy: lt, Recoverable: true}
|
return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
@ -215,6 +213,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64()
|
newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BUG This will break on overflows. https://github.com/ethereum/eth-go/issues/47
|
||||||
newMemSize = (newMemSize + 31) / 32 * 32
|
newMemSize = (newMemSize + 31) / 32 * 32
|
||||||
if newMemSize > uint64(mem.Len()) {
|
if newMemSize > uint64(mem.Len()) {
|
||||||
m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
|
m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
|
||||||
@ -711,6 +710,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
err error
|
err error
|
||||||
value = stack.Pop()
|
value = stack.Pop()
|
||||||
size, offset = stack.Popn()
|
size, offset = stack.Popn()
|
||||||
|
input = mem.Get(offset.Int64(), size.Int64())
|
||||||
|
gas = new(big.Int).Set(closure.Gas)
|
||||||
|
|
||||||
// Snapshot the current stack so we are able to
|
// Snapshot the current stack so we are able to
|
||||||
// revert back to it later.
|
// revert back to it later.
|
||||||
@ -726,37 +727,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
|
|
||||||
self.Printf(" (*) %x", addr).Endl()
|
self.Printf(" (*) %x", addr).Endl()
|
||||||
|
|
||||||
msg := self.env.State().Manifest().AddMessage(ðstate.Message{
|
closure.UseGas(closure.Gas)
|
||||||
To: addr, From: closure.Address(),
|
|
||||||
Origin: self.env.Origin(),
|
|
||||||
Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
|
|
||||||
Value: value,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create a new contract
|
|
||||||
contract := self.env.State().NewStateObject(addr)
|
|
||||||
if contract.Balance.Cmp(value) >= 0 {
|
|
||||||
closure.object.SubAmount(value)
|
|
||||||
contract.AddAmount(value)
|
|
||||||
|
|
||||||
// Set the init script
|
|
||||||
initCode := mem.Get(offset.Int64(), size.Int64())
|
|
||||||
msg.Input = initCode
|
|
||||||
|
|
||||||
// Transfer all remaining gas to the new
|
|
||||||
// contract so it may run the init script
|
|
||||||
gas := new(big.Int).Set(closure.Gas)
|
|
||||||
closure.UseGas(closure.Gas)
|
|
||||||
|
|
||||||
// Create the closure
|
|
||||||
c := NewClosure(msg, closure, contract, initCode, gas, closure.Price)
|
|
||||||
// Call the closure and set the return value as
|
|
||||||
// main script.
|
|
||||||
contract.Code, _, err = c.Call(self, nil)
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
msg := NewMessage(self, addr, input, gas, closure.Price, value)
|
||||||
|
ret, err := msg.Exec(closure)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
|
|
||||||
@ -765,10 +739,55 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
|
|
||||||
self.Printf("CREATE err %v", err)
|
self.Printf("CREATE err %v", err)
|
||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigD(addr))
|
msg.object.Code = ret
|
||||||
|
|
||||||
msg.Output = contract.Code
|
stack.Push(ethutil.BigD(addr))
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
msg := self.env.State().Manifest().AddMessage(ðstate.Message{
|
||||||
|
To: addr, From: closure.Address(),
|
||||||
|
Origin: self.env.Origin(),
|
||||||
|
Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a new contract
|
||||||
|
contract := self.env.State().NewStateObject(addr)
|
||||||
|
if contract.Balance.Cmp(value) >= 0 {
|
||||||
|
closure.object.SubAmount(value)
|
||||||
|
contract.AddAmount(value)
|
||||||
|
|
||||||
|
// Set the init script
|
||||||
|
initCode := mem.Get(offset.Int64(), size.Int64())
|
||||||
|
msg.Input = initCode
|
||||||
|
|
||||||
|
// Transfer all remaining gas to the new
|
||||||
|
// contract so it may run the init script
|
||||||
|
gas := new(big.Int).Set(closure.Gas)
|
||||||
|
closure.UseGas(closure.Gas)
|
||||||
|
|
||||||
|
// Create the closure
|
||||||
|
c := NewClosure(msg, closure, contract, initCode, gas, closure.Price)
|
||||||
|
// Call the closure and set the return value as
|
||||||
|
// main script.
|
||||||
|
contract.Code, _, err = c.Call(self, nil)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
stack.Push(ethutil.BigFalse)
|
||||||
|
|
||||||
|
// Revert the state as it was before.
|
||||||
|
self.env.State().Set(snapshot)
|
||||||
|
|
||||||
|
self.Printf("CREATE err %v", err)
|
||||||
|
} else {
|
||||||
|
stack.Push(ethutil.BigD(addr))
|
||||||
|
|
||||||
|
msg.Output = contract.Code
|
||||||
|
}
|
||||||
|
*/
|
||||||
self.Endl()
|
self.Endl()
|
||||||
|
|
||||||
// Debug hook
|
// Debug hook
|
||||||
@ -791,51 +810,88 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
// 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())
|
||||||
|
|
||||||
msg := self.env.State().Manifest().AddMessage(ðstate.Message{
|
snapshot := self.env.State().Copy()
|
||||||
To: addr.Bytes(), From: closure.Address(),
|
|
||||||
Input: args,
|
|
||||||
Origin: self.env.Origin(),
|
|
||||||
Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
|
|
||||||
Value: value,
|
|
||||||
})
|
|
||||||
|
|
||||||
if closure.object.Balance.Cmp(value) < 0 {
|
|
||||||
vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
|
|
||||||
|
|
||||||
closure.ReturnGas(gas, nil)
|
|
||||||
|
|
||||||
|
msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value)
|
||||||
|
ret, err := msg.Exec(closure)
|
||||||
|
if err != nil {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
|
|
||||||
|
self.env.State().Set(snapshot)
|
||||||
} else {
|
} else {
|
||||||
snapshot := self.env.State().Copy()
|
stack.Push(ethutil.BigTrue)
|
||||||
|
|
||||||
stateObject := self.env.State().GetOrNewStateObject(addr.Bytes())
|
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
||||||
|
|
||||||
closure.object.SubAmount(value)
|
|
||||||
stateObject.AddAmount(value)
|
|
||||||
|
|
||||||
// Create a new callable closure
|
|
||||||
c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price)
|
|
||||||
// Executer the closure and get the return value (if any)
|
|
||||||
ret, _, err := c.Call(self, args)
|
|
||||||
if err != nil {
|
|
||||||
stack.Push(ethutil.BigFalse)
|
|
||||||
|
|
||||||
vmlogger.Debugf("Closure execution failed. %v\n", err)
|
|
||||||
|
|
||||||
self.env.State().Set(snapshot)
|
|
||||||
} else {
|
|
||||||
stack.Push(ethutil.BigTrue)
|
|
||||||
|
|
||||||
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Output = ret
|
|
||||||
|
|
||||||
// Debug hook
|
|
||||||
if self.Dbg != nil {
|
|
||||||
self.Dbg.SetCode(closure.Code)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug hook
|
||||||
|
if self.Dbg != nil {
|
||||||
|
self.Dbg.SetCode(closure.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
msg := self.env.State().Manifest().AddMessage(ðstate.Message{
|
||||||
|
To: addr.Bytes(), From: closure.Address(),
|
||||||
|
Input: args,
|
||||||
|
Origin: self.env.Origin(),
|
||||||
|
Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
|
||||||
|
if closure.object.Balance.Cmp(value) < 0 {
|
||||||
|
vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
|
||||||
|
|
||||||
|
closure.ReturnGas(gas, nil)
|
||||||
|
|
||||||
|
stack.Push(ethutil.BigFalse)
|
||||||
|
} else {
|
||||||
|
snapshot := self.env.State().Copy()
|
||||||
|
|
||||||
|
stateObject := self.env.State().GetOrNewStateObject(addr.Bytes())
|
||||||
|
|
||||||
|
closure.object.SubAmount(value)
|
||||||
|
stateObject.AddAmount(value)
|
||||||
|
|
||||||
|
// Create a new callable closure
|
||||||
|
c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price)
|
||||||
|
// Executer the closure and get the return value (if any)
|
||||||
|
ret, _, err := c.Call(self, args)
|
||||||
|
if err != nil {
|
||||||
|
stack.Push(ethutil.BigFalse)
|
||||||
|
|
||||||
|
vmlogger.Debugf("Closure execution failed. %v\n", err)
|
||||||
|
|
||||||
|
self.env.State().Set(snapshot)
|
||||||
|
} else {
|
||||||
|
stack.Push(ethutil.BigTrue)
|
||||||
|
|
||||||
|
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Output = ret
|
||||||
|
|
||||||
|
// Debug hook
|
||||||
|
if self.Dbg != nil {
|
||||||
|
self.Dbg.SetCode(closure.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
case POST:
|
||||||
|
require(6)
|
||||||
|
|
||||||
|
self.Endl()
|
||||||
|
|
||||||
|
gas := stack.Pop()
|
||||||
|
// Pop gas and value of the stack.
|
||||||
|
value, addr := stack.Popn()
|
||||||
|
// Pop input size and offset
|
||||||
|
inSize, inOffset := stack.Popn()
|
||||||
|
// Get the arguments from the memory
|
||||||
|
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
||||||
|
|
||||||
|
msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value)
|
||||||
|
|
||||||
|
msg.Postpone()
|
||||||
case RETURN:
|
case RETURN:
|
||||||
require(2)
|
require(2)
|
||||||
size, offset := stack.Popn()
|
size, offset := stack.Popn()
|
||||||
@ -887,6 +943,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Vm) Queue() *list.List {
|
||||||
|
return self.queue
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
|
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
|
||||||
if self.Verbose && self.logTy == LogTyPretty {
|
if self.Verbose && self.logTy == LogTyPretty {
|
||||||
self.logStr += fmt.Sprintf(format, v...)
|
self.logStr += fmt.Sprintf(format, v...)
|
||||||
@ -918,3 +978,64 @@ func ensure256(x *big.Int) {
|
|||||||
x.SetInt64(0)
|
x.SetInt64(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
vm *Vm
|
||||||
|
closure *Closure
|
||||||
|
address, input []byte
|
||||||
|
gas, price, value *big.Int
|
||||||
|
object *ethstate.StateObject
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMessage(vm *Vm, address, input []byte, gas, gasPrice, value *big.Int) *Message {
|
||||||
|
return &Message{vm: vm, address: address, input: input, gas: gas, price: gasPrice, value: value}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Message) Postpone() {
|
||||||
|
self.vm.queue.PushBack(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Message) Exec(caller ClosureRef) (ret []byte, err error) {
|
||||||
|
queue := self.vm.queue
|
||||||
|
self.vm.queue = list.New()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
queue.PushBackList(self.vm.queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.vm.queue = queue
|
||||||
|
}()
|
||||||
|
|
||||||
|
msg := self.vm.env.State().Manifest().AddMessage(ðstate.Message{
|
||||||
|
To: self.address, From: caller.Address(),
|
||||||
|
Input: self.input,
|
||||||
|
Origin: self.vm.env.Origin(),
|
||||||
|
Block: self.vm.env.BlockHash(), Timestamp: self.vm.env.Time(), Coinbase: self.vm.env.Coinbase(), Number: self.vm.env.BlockNumber(),
|
||||||
|
Value: self.value,
|
||||||
|
})
|
||||||
|
|
||||||
|
object := caller.Object()
|
||||||
|
if object.Balance.Cmp(self.value) < 0 {
|
||||||
|
caller.ReturnGas(self.gas, self.price)
|
||||||
|
|
||||||
|
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance)
|
||||||
|
} else {
|
||||||
|
stateObject := self.vm.env.State().GetOrNewStateObject(self.address)
|
||||||
|
self.object = stateObject
|
||||||
|
|
||||||
|
caller.Object().SubAmount(self.value)
|
||||||
|
stateObject.AddAmount(self.value)
|
||||||
|
|
||||||
|
// Create a new callable closure
|
||||||
|
c := NewClosure(msg, caller, object, object.Code, self.gas, self.price)
|
||||||
|
// Executer the closure and get the return value (if any)
|
||||||
|
ret, _, err = c.Call(self.vm, self.input)
|
||||||
|
|
||||||
|
msg.Output = ret
|
||||||
|
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user