From b5beb1aac11af92bfe0f3ed7560b9eb08495ed09 Mon Sep 17 00:00:00 2001 From: obscuren 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()