diff options
author | obscuren <geffobscura@gmail.com> | 2014-05-20 23:09:44 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2014-05-20 23:09:44 +0800 |
commit | 4b13f93a3e0f2901a8e1aa38dfef115e24c63ef0 (patch) | |
tree | d4622ae52bcc4c158aa26cf171a306979307bfc9 /ethchain | |
parent | 6efdd21633c1d21f36080754a89ad82c0c244128 (diff) | |
parent | c37b3cef7dc465832761b1da6761eeaa47e368d1 (diff) | |
download | dexon-4b13f93a3e0f2901a8e1aa38dfef115e24c63ef0.tar.gz dexon-4b13f93a3e0f2901a8e1aa38dfef115e24c63ef0.tar.zst dexon-4b13f93a3e0f2901a8e1aa38dfef115e24c63ef0.zip |
Merge branch 'release/poc5-rc7'
Diffstat (limited to 'ethchain')
-rw-r--r-- | ethchain/block.go | 83 | ||||
-rw-r--r-- | ethchain/block_chain.go | 25 | ||||
-rw-r--r-- | ethchain/block_chain_test.go | 17 | ||||
-rw-r--r-- | ethchain/dagger.go | 4 | ||||
-rw-r--r-- | ethchain/genesis.go | 18 | ||||
-rw-r--r-- | ethchain/state.go | 49 | ||||
-rw-r--r-- | ethchain/state_manager.go | 111 | ||||
-rw-r--r-- | ethchain/state_object.go | 21 | ||||
-rw-r--r-- | ethchain/state_object_test.go | 25 | ||||
-rw-r--r-- | ethchain/transaction.go | 14 | ||||
-rw-r--r-- | ethchain/transaction_pool.go | 24 | ||||
-rw-r--r-- | ethchain/vm.go | 3 | ||||
-rw-r--r-- | ethchain/vm_test.go | 2 |
13 files changed, 237 insertions, 159 deletions
diff --git a/ethchain/block.go b/ethchain/block.go index aac50ccb1..c6c2c1226 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" + "strconv" "time" ) @@ -40,6 +41,14 @@ type Block struct { Difficulty *big.Int // Creation time Time int64 + // The block number + Number *big.Int + // Minimum Gas Price + MinGasPrice *big.Int + // Gas limit + GasLimit *big.Int + // Gas used + GasUsed *big.Int // Extra data Extra string // Block Nonce for verification @@ -122,7 +131,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) @@ -206,7 +215,12 @@ func (block *Block) SetUncles(uncles []*Block) { func (block *Block) SetTransactions(txs []*Transaction) { block.transactions = txs - block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) + trie := ethutil.NewTrie(ethutil.Config.Db, "") + for i, tx := range txs { + trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) + } + + block.TxSha = trie.Root.([]byte) } func (block *Block) Value() *ethutil.Value { @@ -233,9 +247,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() - block.Time = int64(header.Get(6).BigInt().Uint64()) - block.Extra = header.Get(7).Str() - block.Nonce = header.Get(8).Bytes() + block.Number = header.Get(6).BigInt() + block.MinGasPrice = header.Get(7).BigInt() + block.GasLimit = header.Get(8).BigInt() + block.GasUsed = header.Get(9).BigInt() + block.Time = int64(header.Get(10).BigInt().Uint64()) + block.Extra = header.Get(11).Str() + block.Nonce = header.Get(12).Bytes() block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their @@ -270,21 +288,21 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() - block.Time = int64(header.Get(6).BigInt().Uint64()) - block.Extra = header.Get(7).Str() - block.Nonce = header.Get(8).Bytes() + block.Number = header.Get(6).BigInt() + block.MinGasPrice = header.Get(7).BigInt() + block.GasLimit = header.Get(8).BigInt() + block.GasUsed = header.Get(9).BigInt() + block.Time = int64(header.Get(10).BigInt().Uint64()) + block.Extra = header.Get(11).Str() + block.Nonce = header.Get(12).Bytes() return block } -func (block *Block) String() string { - return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) -} func (block *Block) GetRoot() interface{} { return block.state.trie.Root } -//////////// UNEXPORTED ///////////////// func (block *Block) header() []interface{} { return []interface{}{ // Sha of the previous block @@ -299,6 +317,14 @@ func (block *Block) header() []interface{} { block.TxSha, // Current block Difficulty block.Difficulty, + // The block number + block.Number, + // Block minimum gas price + block.MinGasPrice, + // Block upper gas bound + block.GasLimit, + // Block gas used + block.GasUsed, // Time the block was found? block.Time, // Extra data @@ -307,3 +333,36 @@ func (block *Block) header() []interface{} { block.Nonce, } } + +func (block *Block) String() string { + return fmt.Sprintf(` + BLOCK(%x): + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x +`, + block.Hash(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.state.trie.Root, + block.TxSha, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce) +} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2be4cd92b..2865336fb 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -70,6 +70,22 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { diff.Mul(diff, mul) diff.Add(diff, bc.CurrentBlock.Difficulty) block.Difficulty = diff + + block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) + + // max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024) + base := new(big.Int) + base2 := new(big.Int) + parentGL := bc.CurrentBlock.GasLimit + parentUsed := bc.CurrentBlock.GasUsed + + base.Mul(parentGL, big.NewInt(1024-1)) + base2.Mul(parentUsed, big.NewInt(6)) + base2.Div(base2, big.NewInt(5)) + base.Add(base, base2) + base.Div(base, big.NewInt(1024)) + + block.GasLimit = ethutil.BigMax(big.NewInt(10000), base) } return block @@ -127,7 +143,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } - log.Println("Checking incoming blocks:") chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } @@ -182,6 +197,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { // XXX Why are we resetting? This is the block chain, it has nothing to do with states //bc.Ethereum.StateManager().PrepareDefault(returnTo) + // Manually reset the last sync block err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { return err @@ -261,13 +277,14 @@ func AddTestNetFunds(block *Block) { "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman } { - //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) account.Amount = ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } + log.Printf("%x\n", block.RlpEncode()) } func (bc *BlockChain) setLastBlock() { @@ -279,7 +296,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = info.Number - log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -294,7 +311,7 @@ func (bc *BlockChain) setLastBlock() { // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - log.Printf("Last block: %x\n", bc.CurrentBlock.Hash()) + ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 30eb62266..4e4bb9dd4 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -18,6 +18,18 @@ type TestManager struct { Blocks []*Block } +func (s *TestManager) IsListening() bool { + return false +} + +func (s *TestManager) IsMining() bool { + return false +} + +func (s *TestManager) PeerCount() int { + return 0 +} + func (s *TestManager) BlockChain() *BlockChain { return s.blockChain } @@ -38,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest") + ethutil.ReadConfig(".ethtest", ethutil.LogStd) db, err := ethdb.NewMemDatabase() if err != nil { @@ -62,8 +74,7 @@ func NewTestManager() *TestManager { func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) - tm.StateManager().PrepareDefault(block) - err := tm.StateManager().ProcessBlock(block, false) + err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false) return err } func (tm *TestManager) CreateChain1() error { diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 9d2df4069..18e53d3a8 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - log.Println("[POW] Received reactor event; breaking out.") + ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - log.Println("[POW] Hashing @", int64(hashes), "khash") + ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 935978a69..b8f9f865a 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -15,7 +15,6 @@ var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) - //"", ZeroHash256, // Sha of uncles ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), @@ -23,15 +22,22 @@ var GenesisHeader = []interface{}{ ZeroHash160, // Root state "", - // Sha of transactions - //EmptyShaList, - ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + // tx sha + ZeroHash256, // Difficulty ethutil.BigPow(2, 22), + // Number + ethutil.Big0, + // Block minimum gas price + ethutil.Big0, + // Block upper gas bound + big.NewInt(1000000), + // Block gas used + ethutil.Big0, // Time - int64(0), + ethutil.Big0, // Extra - "", + nil, // Nonce ethutil.Sha3Bin(big.NewInt(42).Bytes()), } 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 57d56469b..c7c6857d8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -39,20 +39,13 @@ type StateManager struct { // The ethereum manager interface Ethereum EthManager // The managed states - // Processor state. Anything processed will be applied to this - // state - procState *State - // Comparative state it used for comparing and validating end - // results - compState *State // Transiently state. The trans state isn't ever saved, validated and // it could be used for setting account nonces without effecting // the main states. transState *State - // Manifest for keeping changes regarding state objects. See `notify` - // XXX Should we move the manifest to the State object. Benefit: - // * All states can keep their own local changes - //manifest *Manifest + // Mining state. The mining state is used purely and solely by the mining + // operation. + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -62,30 +55,39 @@ func NewStateManager(ethereum EthManager) *StateManager { Pow: &EasyPow{}, Ethereum: ethereum, bc: ethereum.BlockChain(), - //manifest: NewManifest(), } - sm.procState = ethereum.BlockChain().CurrentBlock.State() - sm.transState = sm.procState.Copy() + sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy() + sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy() return sm } -func (sm *StateManager) ProcState() *State { - return sm.procState +func (sm *StateManager) CurrentState() *State { + return sm.Ethereum.BlockChain().CurrentBlock.State() } func (sm *StateManager) TransState() *State { return sm.transState } +func (sm *StateManager) MiningState() *State { + return sm.miningState +} + +func (sm *StateManager) NewMiningState() *State { + sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy() + + return sm.miningState +} + func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { - contract := MakeContract(tx, sm.procState) +func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) if contract != nil { - sm.procState.states[string(tx.Hash()[12:])] = contract.state + state.states[string(tx.CreationAddress())] = contract.state return contract } @@ -95,7 +97,7 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { +func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract @@ -104,9 +106,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { if tx.IsContract() { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) if err == nil { - contract := sm.MakeContract(tx) + contract := sm.MakeContract(state, tx) if contract != nil { - sm.EvalScript(contract.Init(), contract, tx, block) + sm.EvalScript(state, contract.Init(), contract, tx, block) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -115,9 +117,10 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := sm.procState.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(contract.Script(), contract, tx, block) + sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { ethutil.Config.Log.Infoln("[STATE] process:", err) } @@ -125,20 +128,8 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } -// The prepare function, prepares the state manager for the next -// "ProcessBlock" action. -func (sm *StateManager) Prepare(processor *State, comparative *State) { - sm.compState = comparative - sm.procState = processor -} - -// Default prepare function -func (sm *StateManager) PrepareDefault(block *Block) { - sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) -} - // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -153,7 +144,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. - defer sm.bc.CurrentBlock.Undo() + defer state.Reset() // Check if we have the parent hash, if it isn't known we discard it // Reasons might be catching up or simply an invalid block @@ -162,7 +153,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } // Process the transactions on to current block - sm.ApplyTransactions(sm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -172,35 +163,35 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(block); err != nil { + if err := sm.AccumelateRewards(state, block); err != nil { fmt.Println("[SM] Error accumulating reward", err) return err } - if !sm.compState.Cmp(sm.procState) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) + //if !sm.compState.Cmp(state) { + if !block.State().Cmp(state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - sm.procState.Sync() + state.Sync() // Add the block to the chain sm.bc.Add(block) + sm.notifyChanges(state) ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) - sm.notifyChanges() - - sm.procState.manifest.Reset() + state.manifest.Reset() } sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - sm.Ethereum.TxPool().RemoveInvalid(sm.procState) + sm.Ethereum.TxPool().RemoveInvalid(state) } else { fmt.Println("total diff failed") } @@ -276,21 +267,21 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (sm *StateManager) AccumelateRewards(block *Block) error { +func (sm *StateManager) AccumelateRewards(state *State, block *Block) error { // Get the account associated with the coinbase - account := sm.procState.GetAccount(block.Coinbase) + account := state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) addr := make([]byte, len(block.Coinbase)) copy(addr, block.Coinbase) - sm.procState.UpdateStateObject(account) + state.UpdateStateObject(account) for _, uncle := range block.Uncles { - uncleAccount := sm.procState.GetAccount(uncle.Coinbase) + uncleAccount := state.GetAccount(uncle.Coinbase) uncleAccount.AddAmount(CalculateUncleReward(uncle)) - sm.procState.UpdateStateObject(uncleAccount) + state.UpdateStateObject(uncleAccount) } return nil @@ -300,8 +291,8 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { - account := sm.procState.GetAccount(tx.Sender()) +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) { + account := state.GetAccount(tx.Sender()) err := account.ConvertGas(tx.Gas, tx.GasPrice) if err != nil { @@ -309,8 +300,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans return } - closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) - vm := NewVm(sm.procState, sm, RuntimeVars{ + closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) + vm := NewVm(state, sm, RuntimeVars{ Origin: account.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, @@ -323,16 +314,16 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans closure.Call(vm, tx.Data, nil) // Update the account (refunds) - sm.procState.UpdateStateObject(account) - sm.procState.UpdateStateObject(object) + state.UpdateStateObject(account) + state.UpdateStateObject(object) } -func (sm *StateManager) notifyChanges() { - for addr, stateObject := range sm.procState.manifest.objectChanges { +func (sm *StateManager) notifyChanges(state *State) { + for addr, stateObject := range state.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range state.manifest.storageChanges { for addr, value := range mappedObjects { sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } 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..bd7a0e424 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 { @@ -109,10 +109,8 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] -// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -135,10 +133,10 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() - tx.Value = decoder.Get(1).BigInt() - tx.GasPrice = decoder.Get(2).BigInt() - tx.Gas = decoder.Get(3).BigInt() - tx.Recipient = decoder.Get(4).Bytes() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() // If the list is of length 10 it's a contract creation tx diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6c0282dc6..796ec7c9a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -131,9 +131,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract block.state.UpdateStateObject(sender) - log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - pool.notifySubscribers(TxPost, tx) + // Notify all subscribers + pool.Ethereum.Reactor().Post("newTx:post", tx) return } @@ -148,7 +149,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient @@ -188,10 +190,7 @@ out: pool.addTransaction(tx) // Notify the subscribers - pool.Ethereum.Reactor().Post("newTx", tx) - - // Notify the subscribers - pool.notifySubscribers(TxPre, tx) + pool.Ethereum.Reactor().Post("newTx:pre", tx) } case <-pool.quit: break out @@ -252,14 +251,3 @@ func (pool *TxPool) Stop() { log.Println("[TXP] Stopped") } - -func (pool *TxPool) Subscribe(channel chan TxMsg) { - pool.subscribers = append(pool.subscribers, channel) -} - -func (pool *TxPool) notifySubscribers(ty TxMsgTy, tx *Transaction) { - msg := TxMsg{Type: ty, Tx: tx} - for _, subscriber := range pool.subscribers { - subscriber <- msg - } -} diff --git a/ethchain/vm.go b/ethchain/vm.go index 584c66611..e732d22a4 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } - fmt.Println(closure.Script) for { // The base for all big integer arithmetic @@ -472,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 diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index b919b496f..5d03ccf0c 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -12,7 +12,7 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("") + ethutil.ReadConfig("", ethutil.LogStd) db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) |