diff --git a/ethchain/closure.go b/ethchain/closure.go index 9453ce22cb..0eef866d0b 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -15,6 +15,7 @@ type ClosureBody interface { Callee ethutil.RlpEncodable GetMem(int64) *ethutil.Value + Address() []byte } // Basic inline closure object which implement the 'closure' interface diff --git a/ethchain/contract.go b/ethchain/contract.go index 10c5e2df67..93d2b68ba3 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -9,26 +9,22 @@ type Contract struct { Amount *big.Int Nonce uint64 //state *ethutil.Trie - state *State + state *State + address []byte } -func NewContract(Amount *big.Int, root []byte) *Contract { - contract := &Contract{Amount: Amount, Nonce: 0} +func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { + contract := &Contract{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) return contract } -func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) -} - -func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) +func NewContractFromBytes(address, data []byte) *Contract { + contract := &Contract{address: address} + contract.RlpDecode(data) - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + return contract } func (c *Contract) Addr(addr []byte) *ethutil.Value { @@ -54,13 +50,29 @@ func (c *Contract) ReturnGas(val *big.Int, state *State) { c.Amount.Add(c.Amount, val) } +func (c *Contract) Address() []byte { + return c.address +} + +func (c *Contract) RlpEncode() []byte { + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) +} + +func (c *Contract) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) +} + func MakeContract(tx *Transaction, state *State) *Contract { // Create contract if there's no recipient if tx.IsContract() { addr := tx.Hash()[12:] value := tx.Value - contract := NewContract(value, []byte("")) + contract := NewContract(addr, value, []byte("")) state.trie.Update(string(addr), string(contract.RlpEncode())) for i, val := range tx.Data { if len(val) > 0 { diff --git a/ethchain/state.go b/ethchain/state.go index b6750d62d2..c9b35da21e 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -63,8 +63,7 @@ func (s *State) GetContract(addr []byte) *Contract { } // build contract - contract := &Contract{} - contract.RlpDecode([]byte(data)) + contract := NewContractFromBytes(addr, []byte(data)) // Check if there's a cached state for this contract cachedState := s.states[string(addr)] @@ -78,7 +77,9 @@ func (s *State) GetContract(addr []byte) *Contract { return contract } -func (s *State) UpdateContract(addr []byte, contract *Contract) { +func (s *State) UpdateContract(contract *Contract) { + addr := contract.Address() + s.states[string(addr)] = contract.state s.trie.Update(string(addr), string(contract.RlpEncode())) } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3d85e2c09c..ba19231cc0 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -23,14 +23,12 @@ type Vm struct { } type RuntimeVars struct { - address []byte + origin []byte blockNumber uint64 - sender []byte prevHash []byte coinbase []byte time int64 diff *big.Int - txValue *big.Int txData []string } @@ -108,6 +106,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, nil) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: size, offset := stack.Popn() @@ -501,7 +500,7 @@ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, tx := NewTransaction(addr, value, dataItems) if tx.IsContract() { contract := MakeContract(tx, state) - state.UpdateContract(tx.Hash()[12:], contract) + state.UpdateContract(contract) } else { account := state.GetAccount(tx.Recipient) account.Amount.Add(account.Amount, tx.Value) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 30c8a110e3..1dca5cfb7c 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -130,7 +130,7 @@ func TestRun3(t *testing.T) { addr := tx.Hash()[12:] fmt.Printf("addr contract %x\n", addr) contract := MakeContract(tx, state) - state.UpdateContract(addr, contract) + state.UpdateContract(contract) callerScript := Compile([]string{ "PUSH", "62", // ret size @@ -143,21 +143,20 @@ func TestRun3(t *testing.T) { "CALL", }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) - callerAddr := callerTx.Hash()[12:] + // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - address: callerAddr, + origin: account.Address, blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), time: 1, diff: big.NewInt(256), - txValue: big.NewInt(10000), - txData: nil, + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, }) callerClosure.Call(vm, nil) }