From fd19142c0db3d2b6651989f5389944f3e211d84f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 11:19:07 +0200 Subject: No longer store script directly in the state tree --- ethchain/block.go | 2 +- ethchain/block_chain.go | 2 +- ethchain/state.go | 49 +++++++++++++------------------------------ ethchain/state_manager.go | 5 +++-- ethchain/state_object.go | 21 +++++++++++-------- ethchain/state_object_test.go | 25 ++++++++++++++++++++++ ethchain/transaction.go | 2 +- ethchain/vm.go | 2 +- 8 files changed, 59 insertions(+), 49 deletions(-) create mode 100644 ethchain/state_object_test.go (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index aac50ccb1..ca84dc19c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -122,7 +122,7 @@ func (block *Block) Transactions() []*Transaction { } func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.state.GetContract(addr) + contract := block.state.GetStateObject(addr) // If we can't pay the fee return if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { fmt.Println("Contract has insufficient funds", contract.Amount, fee) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6c3b15a6a..99e17727c 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/state.go b/ethchain/state.go index d02584d67..63c4a32a6 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -49,28 +49,6 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -// XXX Deprecated -func (s *State) GetContract(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - // build contract - contract := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedState := s.states[string(addr)] - if cachedState != nil { - contract.state = cachedState - } else { - // If it isn't cached, cache the state - s.states[string(addr)] = contract.state - } - - return contract -} - func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -91,6 +69,21 @@ func (s *State) GetStateObject(addr []byte) *StateObject { return stateObject } +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil { + s.states[string(addr)] = object.state + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) + + s.trie.Update(string(addr), string(object.RlpEncode())) + + s.manifest.AddObjectChange(object) +} + func (s *State) SetStateObject(stateObject *StateObject) { s.states[string(stateObject.address)] = stateObject.state @@ -116,18 +109,6 @@ func (s *State) Copy() *State { return NewState(s.trie.Copy()) } -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil { - s.states[string(addr)] = object.state - } - - s.trie.Update(string(addr), string(object.RlpEncode())) - s.manifest.AddObjectChange(object) -} - func (s *State) Put(key, object []byte) { s.trie.Update(string(key), string(object)) } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 28570775b..098263e8a 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -87,7 +87,7 @@ func (sm *StateManager) BlockChain() *BlockChain { func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) if contract != nil { - state.states[string(tx.Hash()[12:])] = contract.state + state.states[string(tx.CreationAddress())] = contract.state return contract } @@ -117,7 +117,8 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetContract(tx.Recipient) + contract := state.GetStateObject(tx.Recipient) + ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) if err == nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7a11a1152..cb6211ea6 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -10,8 +10,9 @@ type StateObject struct { // Address of the object address []byte // Shared attributes - Amount *big.Int - Nonce uint64 + Amount *big.Int + ScriptHash []byte + Nonce uint64 // Contract related attributes state *State script []byte @@ -22,12 +23,10 @@ type StateObject struct { func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient if tx.IsContract() { - // FIXME - addr := tx.Hash()[12:] + addr := tx.CreationAddress() value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.UpdateStateObject(contract) + contract := NewContract(addr, value, ZeroHash256) contract.script = tx.Data contract.initScript = tx.Init @@ -146,9 +145,10 @@ func (c *StateObject) RlpEncode() []byte { if c.state != nil { root = c.state.trie.Root } else { - root = nil + root = ZeroHash256 } - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script}) + + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { @@ -157,7 +157,10 @@ func (c *StateObject) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.script = decoder.Get(3).Bytes() + + c.ScriptHash = decoder.Get(3).Bytes() + + c.script, _ = ethutil.Config.Db.Get(c.ScriptHash) } // Storage change object. Used by the manifest for notifying changes to diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go new file mode 100644 index 000000000..1db01a537 --- /dev/null +++ b/ethchain/state_object_test.go @@ -0,0 +1,25 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "testing" +) + +func TestSync(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd) + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + + contract.script = []byte{42} + + state.UpdateStateObject(contract) + state.Sync() + + object := state.GetStateObject([]byte("aa")) + fmt.Printf("%x\n", object.Script()) +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e93e610be..8ea4704cb 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -60,7 +60,7 @@ func (tx *Transaction) IsContract() bool { } func (tx *Transaction) CreationAddress() []byte { - return tx.Hash()[12:] + return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } func (tx *Transaction) Signature(key []byte) []byte { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6579830ec..e732d22a4 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -471,7 +471,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro args := mem.Get(inOffset.Int64(), inSize.Int64()) // Fetch the contract which will serve as the closure body - contract := vm.state.GetContract(addr.Bytes()) + contract := vm.state.GetStateObject(addr.Bytes()) if contract != nil { // Prepay for the gas -- cgit