forked from cerc-io/plugeth
added a transfer method to vm env
This commit is contained in:
parent
27cb0750c1
commit
b5beb1aac1
@ -28,7 +28,7 @@ func (self *State) Dump() []byte {
|
|||||||
self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) {
|
self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) {
|
||||||
stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes())
|
stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes())
|
||||||
|
|
||||||
account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)}
|
account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)}
|
||||||
account.Storage = make(map[string]string)
|
account.Storage = make(map[string]string)
|
||||||
|
|
||||||
stateObject.EachStorage(func(key string, value *ethutil.Value) {
|
stateObject.EachStorage(func(key string, value *ethutil.Value) {
|
||||||
|
@ -33,7 +33,7 @@ func New(trie *ethtrie.Trie) *State {
|
|||||||
func (self *State) GetBalance(addr []byte) *big.Int {
|
func (self *State) GetBalance(addr []byte) *big.Int {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.GetStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Balance
|
return stateObject.balance
|
||||||
}
|
}
|
||||||
|
|
||||||
return ethutil.Big0
|
return ethutil.Big0
|
||||||
|
@ -31,7 +31,7 @@ type StateObject struct {
|
|||||||
// Address of the object
|
// Address of the object
|
||||||
address []byte
|
address []byte
|
||||||
// Shared attributes
|
// Shared attributes
|
||||||
Balance *big.Int
|
balance *big.Int
|
||||||
codeHash []byte
|
codeHash []byte
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
// Contract related attributes
|
// Contract related attributes
|
||||||
@ -61,7 +61,7 @@ func NewStateObject(addr []byte) *StateObject {
|
|||||||
// This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter.
|
// This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter.
|
||||||
address := ethutil.Address(addr)
|
address := ethutil.Address(addr)
|
||||||
|
|
||||||
object := &StateObject{address: address, Balance: new(big.Int), gasPool: new(big.Int)}
|
object := &StateObject{address: address, balance: new(big.Int), gasPool: new(big.Int)}
|
||||||
object.State = New(ethtrie.New(ethutil.Config.Db, ""))
|
object.State = New(ethtrie.New(ethutil.Config.Db, ""))
|
||||||
object.storage = make(Storage)
|
object.storage = make(Storage)
|
||||||
object.gasPool = new(big.Int)
|
object.gasPool = new(big.Int)
|
||||||
@ -71,7 +71,7 @@ func NewStateObject(addr []byte) *StateObject {
|
|||||||
|
|
||||||
func NewContract(address []byte, balance *big.Int, root []byte) *StateObject {
|
func NewContract(address []byte, balance *big.Int, root []byte) *StateObject {
|
||||||
contract := NewStateObject(address)
|
contract := NewStateObject(address)
|
||||||
contract.Balance = balance
|
contract.balance = balance
|
||||||
contract.State = New(ethtrie.New(ethutil.Config.Db, string(root)))
|
contract.State = New(ethtrie.New(ethutil.Config.Db, string(root)))
|
||||||
|
|
||||||
return contract
|
return contract
|
||||||
@ -86,7 +86,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject {
|
|||||||
|
|
||||||
func (self *StateObject) MarkForDeletion() {
|
func (self *StateObject) MarkForDeletion() {
|
||||||
self.remove = true
|
self.remove = true
|
||||||
statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Balance)
|
statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
|
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
|
||||||
@ -174,22 +174,26 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
|
|||||||
return ethutil.NewValueFromBytes([]byte{c.Code[pc.Int64()]})
|
return ethutil.NewValueFromBytes([]byte{c.Code[pc.Int64()]})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) AddAmount(amount *big.Int) {
|
func (c *StateObject) AddBalance(amount *big.Int) {
|
||||||
c.SetBalance(new(big.Int).Add(c.Balance, amount))
|
c.SetBalance(new(big.Int).Add(c.balance, amount))
|
||||||
|
|
||||||
statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Balance, amount)
|
statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.balance, amount)
|
||||||
}
|
}
|
||||||
|
func (c *StateObject) AddAmount(amount *big.Int) { c.AddBalance(amount) }
|
||||||
|
|
||||||
func (c *StateObject) SubAmount(amount *big.Int) {
|
func (c *StateObject) SubBalance(amount *big.Int) {
|
||||||
c.SetBalance(new(big.Int).Sub(c.Balance, amount))
|
c.SetBalance(new(big.Int).Sub(c.balance, amount))
|
||||||
|
|
||||||
statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Balance, amount)
|
statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.balance, amount)
|
||||||
}
|
}
|
||||||
|
func (c *StateObject) SubAmount(amount *big.Int) { c.SubBalance(amount) }
|
||||||
|
|
||||||
func (c *StateObject) SetBalance(amount *big.Int) {
|
func (c *StateObject) SetBalance(amount *big.Int) {
|
||||||
c.Balance = amount
|
c.balance = amount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StateObject) Balance() *big.Int { return self.balance }
|
||||||
|
|
||||||
//
|
//
|
||||||
// Gas setters and getters
|
// Gas setters and getters
|
||||||
//
|
//
|
||||||
@ -198,8 +202,8 @@ func (c *StateObject) SetBalance(amount *big.Int) {
|
|||||||
func (c *StateObject) ReturnGas(gas, price *big.Int) {}
|
func (c *StateObject) ReturnGas(gas, price *big.Int) {}
|
||||||
func (c *StateObject) ConvertGas(gas, price *big.Int) error {
|
func (c *StateObject) ConvertGas(gas, price *big.Int) error {
|
||||||
total := new(big.Int).Mul(gas, price)
|
total := new(big.Int).Mul(gas, price)
|
||||||
if total.Cmp(c.Balance) > 0 {
|
if total.Cmp(c.balance) > 0 {
|
||||||
return fmt.Errorf("insufficient amount: %v, %v", c.Balance, total)
|
return fmt.Errorf("insufficient amount: %v, %v", c.balance, total)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SubAmount(total)
|
c.SubAmount(total)
|
||||||
@ -232,12 +236,12 @@ func (self *StateObject) RefundGas(gas, price *big.Int) {
|
|||||||
rGas := new(big.Int).Set(gas)
|
rGas := new(big.Int).Set(gas)
|
||||||
rGas.Mul(rGas, price)
|
rGas.Mul(rGas, price)
|
||||||
|
|
||||||
self.Balance.Sub(self.Balance, rGas)
|
self.balance.Sub(self.balance, rGas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) Copy() *StateObject {
|
func (self *StateObject) Copy() *StateObject {
|
||||||
stateObject := NewStateObject(self.Address())
|
stateObject := NewStateObject(self.Address())
|
||||||
stateObject.Balance.Set(self.Balance)
|
stateObject.balance.Set(self.balance)
|
||||||
stateObject.codeHash = ethutil.CopyBytes(self.codeHash)
|
stateObject.codeHash = ethutil.CopyBytes(self.codeHash)
|
||||||
stateObject.Nonce = self.Nonce
|
stateObject.Nonce = self.Nonce
|
||||||
if self.State != nil {
|
if self.State != nil {
|
||||||
@ -281,7 +285,7 @@ func (self *StateObject) Object() *StateObject {
|
|||||||
|
|
||||||
// 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)
|
||||||
self.EachStorage(func(addr string, value *ethutil.Value) {
|
self.EachStorage(func(addr string, value *ethutil.Value) {
|
||||||
fmt.Printf("%x %x\n", addr, value.Bytes())
|
fmt.Printf("%x %x\n", addr, value.Bytes())
|
||||||
})
|
})
|
||||||
@ -300,7 +304,7 @@ func (c *StateObject) RlpEncode() []byte {
|
|||||||
root = ""
|
root = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, c.CodeHash()})
|
return ethutil.Encode([]interface{}{c.Nonce, c.balance, root, c.CodeHash()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) CodeHash() ethutil.Bytes {
|
func (c *StateObject) CodeHash() ethutil.Bytes {
|
||||||
@ -316,7 +320,7 @@ func (c *StateObject) RlpDecode(data []byte) {
|
|||||||
decoder := ethutil.NewValueFromBytes(data)
|
decoder := ethutil.NewValueFromBytes(data)
|
||||||
|
|
||||||
c.Nonce = decoder.Get(0).Uint()
|
c.Nonce = decoder.Get(0).Uint()
|
||||||
c.Balance = decoder.Get(1).BigInt()
|
c.balance = decoder.Get(1).BigInt()
|
||||||
c.State = New(ethtrie.New(ethutil.Config.Db, decoder.Get(2).Interface()))
|
c.State = New(ethtrie.New(ethutil.Config.Db, decoder.Get(2).Interface()))
|
||||||
c.storage = make(map[string]*ethutil.Value)
|
c.storage = make(map[string]*ethutil.Value)
|
||||||
c.gasPool = new(big.Int)
|
c.gasPool = new(big.Int)
|
||||||
|
2
peer.go
2
peer.go
@ -674,7 +674,7 @@ func (p *Peer) pushPeers() {
|
|||||||
|
|
||||||
func (self *Peer) pushStatus() {
|
func (self *Peer) pushStatus() {
|
||||||
msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{
|
msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{
|
||||||
//uint32(ProtocolVersion),
|
uint32(ProtocolVersion),
|
||||||
uint32(NetVersion),
|
uint32(NetVersion),
|
||||||
self.ethereum.ChainManager().TD,
|
self.ethereum.ChainManager().TD,
|
||||||
self.ethereum.ChainManager().CurrentBlock.Hash(),
|
self.ethereum.ChainManager().CurrentBlock.Hash(),
|
||||||
|
@ -50,11 +50,14 @@ func (self *Env) Difficulty() *big.Int { return self.difficulty }
|
|||||||
func (self *Env) BlockHash() []byte { return nil }
|
func (self *Env) BlockHash() []byte { return nil }
|
||||||
func (self *Env) State() *ethstate.State { return self.state }
|
func (self *Env) State() *ethstate.State { return self.state }
|
||||||
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
|
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
|
||||||
|
func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func RunVm(state *ethstate.State, env, exec map[string]string) ([]byte, *big.Int, error) {
|
func RunVm(state *ethstate.State, env, exec map[string]string) ([]byte, *big.Int, error) {
|
||||||
address := FromHex(exec["address"])
|
address := FromHex(exec["address"])
|
||||||
caller := state.GetOrNewStateObject(FromHex(exec["caller"]))
|
caller := state.GetOrNewStateObject(FromHex(exec["caller"]))
|
||||||
caller.Balance = ethutil.Big(exec["value"])
|
caller.SetBalance(ethutil.Big(exec["value"]))
|
||||||
|
|
||||||
evm := vm.New(NewEnvFromMap(state, env, exec), vm.DebugVmTy)
|
evm := vm.New(NewEnvFromMap(state, env, exec), vm.DebugVmTy)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ type Account struct {
|
|||||||
|
|
||||||
func StateObjectFromAccount(addr string, account Account) *ethstate.StateObject {
|
func StateObjectFromAccount(addr string, account Account) *ethstate.StateObject {
|
||||||
obj := ethstate.NewStateObject(ethutil.Hex2Bytes(addr))
|
obj := ethstate.NewStateObject(ethutil.Hex2Bytes(addr))
|
||||||
obj.Balance = ethutil.Big(account.Balance)
|
obj.SetBalance(ethutil.Big(account.Balance))
|
||||||
|
|
||||||
if ethutil.IsHex(account.Code) {
|
if ethutil.IsHex(account.Code) {
|
||||||
account.Code = account.Code[2:]
|
account.Code = account.Code[2:]
|
||||||
@ -44,9 +44,6 @@ func RunVmTest(p string, t *testing.T) {
|
|||||||
helper.CreateFileTests(t, p, &tests)
|
helper.CreateFileTests(t, p, &tests)
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
if name != "CallRecursiveBomb" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
state := ethstate.New(helper.NewTrie())
|
state := ethstate.New(helper.NewTrie())
|
||||||
for addr, account := range test.Pre {
|
for addr, account := range test.Pre {
|
||||||
obj := StateObjectFromAccount(addr, account)
|
obj := StateObjectFromAccount(addr, account)
|
||||||
@ -92,7 +89,6 @@ func TestVMArithmetic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVMSystemOperation(t *testing.T) {
|
func TestVMSystemOperation(t *testing.T) {
|
||||||
helper.Logger.SetLogLevel(5)
|
|
||||||
const fn = "../files/vmtests/vmSystemOperationsTest.json"
|
const fn = "../files/vmtests/vmSystemOperationsTest.json"
|
||||||
RunVmTest(fn, t)
|
RunVmTest(fn, t)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/eth-go/ethstate"
|
"github.com/ethereum/eth-go/ethstate"
|
||||||
@ -18,9 +19,28 @@ type Environment interface {
|
|||||||
Difficulty() *big.Int
|
Difficulty() *big.Int
|
||||||
BlockHash() []byte
|
BlockHash() []byte
|
||||||
GasLimit() *big.Int
|
GasLimit() *big.Int
|
||||||
|
Transfer(from, to Account, amount *big.Int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Object interface {
|
type Object interface {
|
||||||
GetStorage(key *big.Int) *ethutil.Value
|
GetStorage(key *big.Int) *ethutil.Value
|
||||||
SetStorage(key *big.Int, value *ethutil.Value)
|
SetStorage(key *big.Int, value *ethutil.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Account interface {
|
||||||
|
SubBalance(amount *big.Int)
|
||||||
|
AddBalance(amount *big.Int)
|
||||||
|
Balance() *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// generic transfer method
|
||||||
|
func Transfer(from, to Account, amount *big.Int) error {
|
||||||
|
if from.Balance().Cmp(amount) < 0 {
|
||||||
|
return errors.New("Insufficient balance in account")
|
||||||
|
}
|
||||||
|
|
||||||
|
from.SubBalance(amount)
|
||||||
|
to.AddBalance(amount)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -48,17 +48,17 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte,
|
|||||||
Value: self.value,
|
Value: self.value,
|
||||||
})
|
})
|
||||||
|
|
||||||
object := caller.Object()
|
from, to := caller.Object(), env.State().GetOrNewStateObject(self.address)
|
||||||
if object.Balance.Cmp(self.value) < 0 {
|
err = env.Transfer(from, to, self.value)
|
||||||
|
if err != nil {
|
||||||
caller.ReturnGas(self.Gas, self.price)
|
caller.ReturnGas(self.Gas, self.price)
|
||||||
|
|
||||||
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance)
|
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance)
|
||||||
} else {
|
} else {
|
||||||
stateObject := env.State().GetOrNewStateObject(self.address)
|
self.object = to
|
||||||
self.object = stateObject
|
|
||||||
|
|
||||||
caller.Object().SubAmount(self.value)
|
//caller.Object().SubAmount(self.value)
|
||||||
stateObject.AddAmount(self.value)
|
//stateObject.AddAmount(self.value)
|
||||||
|
|
||||||
// Pre-compiled contracts (address.go) 1, 2 & 3.
|
// Pre-compiled contracts (address.go) 1, 2 & 3.
|
||||||
naddr := ethutil.BigD(caddr).Uint64()
|
naddr := ethutil.BigD(caddr).Uint64()
|
||||||
@ -69,7 +69,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create a new callable closure
|
// Create a new callable closure
|
||||||
c := NewClosure(msg, caller, stateObject, code, self.Gas, self.price)
|
c := NewClosure(msg, caller, to, code, self.Gas, self.price)
|
||||||
c.exe = self
|
c.exe = self
|
||||||
|
|
||||||
if self.vm.Depth() == MaxCallDepth {
|
if self.vm.Depth() == MaxCallDepth {
|
||||||
|
2
vm/vm.go
2
vm/vm.go
@ -692,7 +692,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
|||||||
|
|
||||||
receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes())
|
receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes())
|
||||||
|
|
||||||
receiver.AddAmount(closure.object.Balance)
|
receiver.AddAmount(closure.object.Balance())
|
||||||
|
|
||||||
closure.object.MarkForDeletion()
|
closure.object.MarkForDeletion()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user