From b5beb1aac11af92bfe0f3ed7560b9eb08495ed09 Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Wed, 22 Oct 2014 15:22:21 +0200
Subject: [PATCH] added a transfer method to vm env

---
 ethstate/dump.go         |  2 +-
 ethstate/state.go        |  2 +-
 ethstate/state_object.go | 40 ++++++++++++++++++++++------------------
 peer.go                  |  2 +-
 tests/helper/vm.go       |  5 ++++-
 tests/vm/gh_test.go      |  6 +-----
 vm/environment.go        | 20 ++++++++++++++++++++
 vm/execution.go          | 16 ++++++++--------
 vm/vm.go                 |  2 +-
 9 files changed, 59 insertions(+), 36 deletions(-)

diff --git a/ethstate/dump.go b/ethstate/dump.go
index cdd4228b8..e7cbde48b 100644
--- a/ethstate/dump.go
+++ b/ethstate/dump.go
@@ -28,7 +28,7 @@ func (self *State) Dump() []byte {
 	self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) {
 		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)
 
 		stateObject.EachStorage(func(key string, value *ethutil.Value) {
diff --git a/ethstate/state.go b/ethstate/state.go
index 2efe2a311..59d2265a9 100644
--- a/ethstate/state.go
+++ b/ethstate/state.go
@@ -33,7 +33,7 @@ func New(trie *ethtrie.Trie) *State {
 func (self *State) GetBalance(addr []byte) *big.Int {
 	stateObject := self.GetStateObject(addr)
 	if stateObject != nil {
-		return stateObject.Balance
+		return stateObject.balance
 	}
 
 	return ethutil.Big0
diff --git a/ethstate/state_object.go b/ethstate/state_object.go
index a5b7c65e9..1ba005439 100644
--- a/ethstate/state_object.go
+++ b/ethstate/state_object.go
@@ -31,7 +31,7 @@ type StateObject struct {
 	// Address of the object
 	address []byte
 	// Shared attributes
-	Balance  *big.Int
+	balance  *big.Int
 	codeHash []byte
 	Nonce    uint64
 	// 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.
 	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.storage = make(Storage)
 	object.gasPool = new(big.Int)
@@ -71,7 +71,7 @@ func NewStateObject(addr []byte) *StateObject {
 
 func NewContract(address []byte, balance *big.Int, root []byte) *StateObject {
 	contract := NewStateObject(address)
-	contract.Balance = balance
+	contract.balance = balance
 	contract.State = New(ethtrie.New(ethutil.Config.Db, string(root)))
 
 	return contract
@@ -86,7 +86,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject {
 
 func (self *StateObject) MarkForDeletion() {
 	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 {
@@ -174,22 +174,26 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
 	return ethutil.NewValueFromBytes([]byte{c.Code[pc.Int64()]})
 }
 
-func (c *StateObject) AddAmount(amount *big.Int) {
-	c.SetBalance(new(big.Int).Add(c.Balance, amount))
+func (c *StateObject) AddBalance(amount *big.Int) {
+	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) {
-	c.SetBalance(new(big.Int).Sub(c.Balance, amount))
+func (c *StateObject) SubBalance(amount *big.Int) {
+	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) {
-	c.Balance = amount
+	c.balance = amount
 }
 
+func (self *StateObject) Balance() *big.Int { return self.balance }
+
 //
 // 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) ConvertGas(gas, price *big.Int) error {
 	total := new(big.Int).Mul(gas, price)
-	if total.Cmp(c.Balance) > 0 {
-		return fmt.Errorf("insufficient amount: %v, %v", c.Balance, total)
+	if total.Cmp(c.balance) > 0 {
+		return fmt.Errorf("insufficient amount: %v, %v", c.balance, total)
 	}
 
 	c.SubAmount(total)
@@ -232,12 +236,12 @@ func (self *StateObject) RefundGas(gas, price *big.Int) {
 	rGas := new(big.Int).Set(gas)
 	rGas.Mul(rGas, price)
 
-	self.Balance.Sub(self.Balance, rGas)
+	self.balance.Sub(self.balance, rGas)
 }
 
 func (self *StateObject) Copy() *StateObject {
 	stateObject := NewStateObject(self.Address())
-	stateObject.Balance.Set(self.Balance)
+	stateObject.balance.Set(self.balance)
 	stateObject.codeHash = ethutil.CopyBytes(self.codeHash)
 	stateObject.Nonce = self.Nonce
 	if self.State != nil {
@@ -281,7 +285,7 @@ func (self *StateObject) Object() *StateObject {
 
 // Debug stuff
 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) {
 		fmt.Printf("%x %x\n", addr, value.Bytes())
 	})
@@ -300,7 +304,7 @@ func (c *StateObject) RlpEncode() []byte {
 		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 {
@@ -316,7 +320,7 @@ func (c *StateObject) RlpDecode(data []byte) {
 	decoder := ethutil.NewValueFromBytes(data)
 
 	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.storage = make(map[string]*ethutil.Value)
 	c.gasPool = new(big.Int)
diff --git a/peer.go b/peer.go
index 04ff4af39..557c436f6 100644
--- a/peer.go
+++ b/peer.go
@@ -674,7 +674,7 @@ func (p *Peer) pushPeers() {
 
 func (self *Peer) pushStatus() {
 	msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{
-		//uint32(ProtocolVersion),
+		uint32(ProtocolVersion),
 		uint32(NetVersion),
 		self.ethereum.ChainManager().TD,
 		self.ethereum.ChainManager().CurrentBlock.Hash(),
diff --git a/tests/helper/vm.go b/tests/helper/vm.go
index a3d54de23..06c3d4eca 100644
--- a/tests/helper/vm.go
+++ b/tests/helper/vm.go
@@ -50,11 +50,14 @@ func (self *Env) Difficulty() *big.Int   { return self.difficulty }
 func (self *Env) BlockHash() []byte      { return nil }
 func (self *Env) State() *ethstate.State { return self.state }
 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) {
 	address := FromHex(exec["address"])
 	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)
 
diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go
index f27cc7af3..64f279d8d 100644
--- a/tests/vm/gh_test.go
+++ b/tests/vm/gh_test.go
@@ -18,7 +18,7 @@ type Account struct {
 
 func StateObjectFromAccount(addr string, account Account) *ethstate.StateObject {
 	obj := ethstate.NewStateObject(ethutil.Hex2Bytes(addr))
-	obj.Balance = ethutil.Big(account.Balance)
+	obj.SetBalance(ethutil.Big(account.Balance))
 
 	if ethutil.IsHex(account.Code) {
 		account.Code = account.Code[2:]
@@ -44,9 +44,6 @@ func RunVmTest(p string, t *testing.T) {
 	helper.CreateFileTests(t, p, &tests)
 
 	for name, test := range tests {
-		if name != "CallRecursiveBomb" {
-			continue
-		}
 		state := ethstate.New(helper.NewTrie())
 		for addr, account := range test.Pre {
 			obj := StateObjectFromAccount(addr, account)
@@ -92,7 +89,6 @@ func TestVMArithmetic(t *testing.T) {
 }
 
 func TestVMSystemOperation(t *testing.T) {
-	helper.Logger.SetLogLevel(5)
 	const fn = "../files/vmtests/vmSystemOperationsTest.json"
 	RunVmTest(fn, t)
 }
diff --git a/vm/environment.go b/vm/environment.go
index 2d933b65c..23b46c5df 100644
--- a/vm/environment.go
+++ b/vm/environment.go
@@ -1,6 +1,7 @@
 package vm
 
 import (
+	"errors"
 	"math/big"
 
 	"github.com/ethereum/eth-go/ethstate"
@@ -18,9 +19,28 @@ type Environment interface {
 	Difficulty() *big.Int
 	BlockHash() []byte
 	GasLimit() *big.Int
+	Transfer(from, to Account, amount *big.Int) error
 }
 
 type Object interface {
 	GetStorage(key *big.Int) *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
+}
diff --git a/vm/execution.go b/vm/execution.go
index 6bed43026..4c4bd1e3c 100644
--- a/vm/execution.go
+++ b/vm/execution.go
@@ -48,17 +48,17 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte,
 		Value: self.value,
 	})
 
-	object := caller.Object()
-	if object.Balance.Cmp(self.value) < 0 {
+	from, to := caller.Object(), env.State().GetOrNewStateObject(self.address)
+	err = env.Transfer(from, to, self.value)
+	if err != nil {
 		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 {
-		stateObject := env.State().GetOrNewStateObject(self.address)
-		self.object = stateObject
+		self.object = to
 
-		caller.Object().SubAmount(self.value)
-		stateObject.AddAmount(self.value)
+		//caller.Object().SubAmount(self.value)
+		//stateObject.AddAmount(self.value)
 
 		// Pre-compiled contracts (address.go) 1, 2 & 3.
 		naddr := ethutil.BigD(caddr).Uint64()
@@ -69,7 +69,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte,
 			}
 		} else {
 			// 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
 
 			if self.vm.Depth() == MaxCallDepth {
diff --git a/vm/vm.go b/vm/vm.go
index 72d4f7131..b5c7c0e21 100644
--- a/vm/vm.go
+++ b/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.AddAmount(closure.object.Balance)
+			receiver.AddAmount(closure.object.Balance())
 
 			closure.object.MarkForDeletion()
 
-- 
GitLab