diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/block_manager.go | 125 | ||||
-rw-r--r-- | core/chain_manager.go | 234 | ||||
-rw-r--r-- | core/chain_manager_test.go | 126 | ||||
-rw-r--r-- | core/events.go | 3 | ||||
-rw-r--r-- | core/execution.go | 45 | ||||
-rw-r--r-- | core/filter.go | 13 | ||||
-rw-r--r-- | core/filter_test.go | 6 | ||||
-rw-r--r-- | core/genesis.go | 65 | ||||
-rw-r--r-- | core/helper_test.go | 6 | ||||
-rw-r--r-- | core/state_transition.go | 157 | ||||
-rw-r--r-- | core/transaction_pool.go | 75 | ||||
-rw-r--r-- | core/types/block.go | 499 | ||||
-rw-r--r-- | core/types/block_test.go | 23 | ||||
-rw-r--r-- | core/types/derive_sha.go | 8 | ||||
-rw-r--r-- | core/types/transaction.go | 160 | ||||
-rw-r--r-- | core/vm_env.go | 26 |
16 files changed, 832 insertions, 739 deletions
diff --git a/core/block_manager.go b/core/block_manager.go index f6c73bc2c..8a5455306 100644 --- a/core/block_manager.go +++ b/core/block_manager.go @@ -2,7 +2,6 @@ package core import ( "bytes" - "container/list" "errors" "fmt" "math/big" @@ -14,10 +13,11 @@ import ( "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow/ezp" "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/wire" + "gopkg.in/fatih/set.v0" ) var statelogger = logger.NewLogger("BLOCK") @@ -38,13 +38,12 @@ type EthManager interface { BlockManager() *BlockManager ChainManager() *ChainManager TxPool() *TxPool - Broadcast(msgType wire.MsgType, data []interface{}) PeerCount() int IsMining() bool IsListening() bool - Peers() *list.List + Peers() []*p2p.Peer KeyManager() *crypto.KeyManager - ClientIdentity() wire.ClientIdentity + ClientIdentity() p2p.ClientIdentity Db() ethutil.Database EventMux() *event.TypeMux } @@ -58,8 +57,8 @@ type BlockManager struct { mem map[string]*big.Int // Proof of work used for validating Pow pow.PoW - // The ethereum manager interface - eth EthManager + + txpool *TxPool // The last attempted block is mainly used for debugging purposes // This does not have to be a valid block and will be set during @@ -71,21 +70,21 @@ type BlockManager struct { eventMux *event.TypeMux } -func NewBlockManager(ethereum EthManager) *BlockManager { +func NewBlockManager(txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockManager { sm := &BlockManager{ mem: make(map[string]*big.Int), Pow: ezp.New(), - eth: ethereum, - bc: ethereum.ChainManager(), - eventMux: ethereum.EventMux(), + bc: chainManager, + eventMux: eventMux, + txpool: txpool, } return sm } func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) { - coinbase := statedb.GetOrNewStateObject(block.Coinbase) - coinbase.SetGasPool(block.CalcGasLimit(parent)) + coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) + coinbase.SetGasPool(CalcGasLimit(parent, block)) // Process the transactions on to current block receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false) @@ -111,11 +110,11 @@ done: // If we are mining this block and validating we want to set the logs back to 0 state.EmptyLogs() - txGas := new(big.Int).Set(tx.Gas) + txGas := new(big.Int).Set(tx.Gas()) cb := state.GetStateObject(coinbase.Address()) st := NewStateTransition(cb, tx, state, block) - err = st.TransitionState() + _, err = st.TransitionState() if err != nil { switch { case IsNonceErr(err): @@ -129,12 +128,11 @@ done: statelogger.Infoln(err) erroneous = append(erroneous, tx) err = nil - continue } } txGas.Sub(txGas, st.gas) - cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice)) + cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice())) // Update the state with pending changes state.Update(txGas) @@ -143,6 +141,7 @@ done: receipt := types.NewReceipt(state.Root(), cumulative) receipt.SetLogs(state.Logs()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + chainlogger.Debugln(receipt) // Notify all subscribers if !transientProcess { @@ -158,7 +157,7 @@ done: } block.Reward = cumulativeSum - block.GasUsed = totalUsedGas + block.Header().GasUsed = totalUsedGas return receipts, handled, unhandled, erroneous, err } @@ -168,14 +167,15 @@ func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Mes sm.mutex.Lock() defer sm.mutex.Unlock() - if sm.bc.HasBlock(block.Hash()) { - return nil, nil, &KnownBlockError{block.Number, block.Hash()} + header := block.Header() + if sm.bc.HasBlock(header.Hash()) { + return nil, nil, &KnownBlockError{header.Number, header.Hash()} } - if !sm.bc.HasBlock(block.PrevHash) { - return nil, nil, ParentError(block.PrevHash) + if !sm.bc.HasBlock(header.ParentHash) { + return nil, nil, ParentError(header.ParentHash) } - parent := sm.bc.GetBlock(block.PrevHash) + parent := sm.bc.GetBlock(header.ParentHash) return sm.ProcessWithParent(block, parent) } @@ -183,13 +183,7 @@ func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Mes func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) { sm.lastAttemptedBlock = block - state := parent.State().Copy() - - // Defer the Undo on the Trie. If the block processing happened - // 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 state.Reset() + state := state.New(parent.Trie().Copy()) // Block validation if err = sm.ValidateBlock(block, parent); err != nil { @@ -201,21 +195,24 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I return } + header := block.Header() + rbloom := types.CreateBloom(receipts) - if bytes.Compare(rbloom, block.LogsBloom) != 0 { + if bytes.Compare(rbloom, header.Bloom) != 0 { err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return } txSha := types.DeriveSha(block.Transactions()) - if bytes.Compare(txSha, block.TxSha) != 0 { - err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha) + if bytes.Compare(txSha, header.TxHash) != 0 { + err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha) return } receiptSha := types.DeriveSha(receipts) - if bytes.Compare(receiptSha, block.ReceiptSha) != 0 { - err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha) + if bytes.Compare(receiptSha, header.ReceiptHash) != 0 { + fmt.Println("receipts", receipts) + err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha) return } @@ -225,8 +222,8 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I state.Update(ethutil.Big0) - if !block.State().Cmp(state) { - err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root()) + if !bytes.Equal(header.Root, state.Root()) { + err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root()) return } @@ -238,9 +235,9 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I messages := state.Manifest().Messages state.Manifest().Reset() - chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4]) + chainlogger.Infof("Processed block #%d (%x...)\n", header.Number, block.Hash()[0:4]) - sm.eth.TxPool().RemoveSet(block.Transactions()) + sm.txpool.RemoveSet(block.Transactions()) return td, messages, nil } else { @@ -250,18 +247,18 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) { uncleDiff := new(big.Int) - for _, uncle := range block.Uncles { + for _, uncle := range block.Uncles() { uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) } // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty td := new(big.Int) - td = td.Add(sm.bc.TD, uncleDiff) - td = td.Add(td, block.Difficulty) + td = td.Add(sm.bc.Td(), uncleDiff) + td = td.Add(td, block.Header().Difficulty) // The new TD will only be accepted if the new difficulty is // is greater than the previous. - if td.Cmp(sm.bc.TD) > 0 { + if td.Cmp(sm.bc.Td()) > 0 { return td, true } @@ -273,13 +270,13 @@ func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) { // Validation validates easy over difficult (dagger takes longer time = difficult) func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error { expd := CalcDifficulty(block, parent) - if expd.Cmp(block.Difficulty) < 0 { - return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) + if expd.Cmp(block.Header().Difficulty) < 0 { + return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd) } - diff := block.Time - parent.Time + diff := block.Header().Time - parent.Header().Time if diff < 0 { - return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time) + return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time) } /* XXX @@ -291,7 +288,7 @@ func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error { // Verify the nonce of the block. Return an error if it's not valid if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) { - return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce)) + return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce)) } return nil @@ -300,24 +297,28 @@ func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error { func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error { reward := new(big.Int).Set(BlockReward) - knownUncles := ethutil.Set(parent.Uncles) - nonces := ethutil.NewSet(block.Nonce) - for _, uncle := range block.Uncles { + knownUncles := set.New() + for _, uncle := range parent.Uncles() { + knownUncles.Add(string(uncle.Hash())) + } + + nonces := ethutil.NewSet(block.Header().Nonce) + for _, uncle := range block.Uncles() { if nonces.Include(uncle.Nonce) { // Error not unique return UncleError("Uncle not unique") } - uncleParent := sm.bc.GetBlock(uncle.PrevHash) + uncleParent := sm.bc.GetBlock(uncle.ParentHash) if uncleParent == nil { - return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.PrevHash[0:4])) + return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) } - if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 { + if uncleParent.Header().Number.Cmp(new(big.Int).Sub(parent.Header().Number, big.NewInt(6))) < 0 { return UncleError("Uncle too old") } - if knownUncles.Include(uncle.Hash()) { + if knownUncles.Has(string(uncle.Hash())) { return UncleError("Uncle in chain") } @@ -333,15 +334,15 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent } // Get the account associated with the coinbase - account := statedb.GetAccount(block.Coinbase) + account := statedb.GetAccount(block.Header().Coinbase) // Reward amount of ether to the coinbase address account.AddAmount(reward) statedb.Manifest().AddMessage(&state.Message{ - To: block.Coinbase, + To: block.Header().Coinbase, Input: nil, Origin: nil, - Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number, + Block: block.Hash(), Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number, Value: new(big.Int).Add(reward, block.Reward), }) @@ -349,15 +350,15 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent } func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error) { - if !sm.bc.HasBlock(block.PrevHash) { - return nil, ParentError(block.PrevHash) + if !sm.bc.HasBlock(block.Header().ParentHash) { + return nil, ParentError(block.Header().ParentHash) } sm.lastAttemptedBlock = block var ( - parent = sm.bc.GetBlock(block.PrevHash) - state = parent.State().Copy() + parent = sm.bc.GetBlock(block.Header().ParentHash) + state = state.New(parent.Trie().Copy()) ) defer state.Reset() diff --git a/core/chain_manager.go b/core/chain_manager.go index 3e48579b9..485c195d5 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -1,18 +1,22 @@ package core import ( + "bytes" "fmt" "math/big" + "sync" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" ) var chainlogger = logger.NewLogger("CHAIN") +/* func AddTestNetFunds(block *types.Block) { for _, addr := range []string{ "51ba59315b3a95761d0863b05ccc7a7f54703d99", @@ -30,39 +34,87 @@ func AddTestNetFunds(block *types.Block) { block.State().UpdateStateObject(account) } } +*/ func CalcDifficulty(block, parent *types.Block) *big.Int { diff := new(big.Int) - adjust := new(big.Int).Rsh(parent.Difficulty, 10) - if block.Time >= parent.Time+5 { - diff.Sub(parent.Difficulty, adjust) + bh, ph := block.Header(), parent.Header() + adjust := new(big.Int).Rsh(ph.Difficulty, 10) + if bh.Time >= ph.Time+5 { + diff.Sub(ph.Difficulty, adjust) } else { - diff.Add(parent.Difficulty, adjust) + diff.Add(ph.Difficulty, adjust) } return diff } +func CalcGasLimit(parent, block *types.Block) *big.Int { + if block.Number().Cmp(big.NewInt(0)) == 0 { + return ethutil.BigPow(10, 6) + } + + // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 + + previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit()) + current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5)) + curInt := new(big.Int).Div(current.Num(), current.Denom()) + + result := new(big.Int).Add(previous, curInt) + result.Div(result, big.NewInt(1024)) + + min := big.NewInt(125000) + + return ethutil.BigMax(min, result) +} + type ChainManager struct { //eth EthManager processor types.BlockProcessor eventMux *event.TypeMux genesisBlock *types.Block // Last known total difficulty - TD *big.Int + mu sync.RWMutex + td *big.Int + lastBlockNumber uint64 + currentBlock *types.Block + lastBlockHash []byte + + transState *state.StateDB +} - LastBlockNumber uint64 +func (self *ChainManager) Td() *big.Int { + self.mu.RLock() + defer self.mu.RUnlock() - CurrentBlock *types.Block - LastBlockHash []byte + return self.td +} - transState *state.StateDB +func (self *ChainManager) LastBlockNumber() uint64 { + self.mu.RLock() + defer self.mu.RUnlock() + + return self.lastBlockNumber +} + +func (self *ChainManager) LastBlockHash() []byte { + self.mu.RLock() + defer self.mu.RUnlock() + + return self.lastBlockHash +} + +func (self *ChainManager) CurrentBlock() *types.Block { + self.mu.RLock() + defer self.mu.RUnlock() + + return self.currentBlock } func NewChainManager(mux *event.TypeMux) *ChainManager { bc := &ChainManager{} - bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis)) + bc.genesisBlock = GenesisBlock() bc.eventMux = mux bc.setLastBlock() @@ -72,12 +124,19 @@ func NewChainManager(mux *event.TypeMux) *ChainManager { return bc } +func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { + self.mu.RLock() + defer self.mu.RUnlock() + + return self.td, self.currentBlock.Hash(), self.Genesis().Hash() +} + func (self *ChainManager) SetProcessor(proc types.BlockProcessor) { self.processor = proc } func (self *ChainManager) State() *state.StateDB { - return self.CurrentBlock.State() + return state.New(self.CurrentBlock().Trie()) } func (self *ChainManager) TransState() *state.StateDB { @@ -87,46 +146,48 @@ func (self *ChainManager) TransState() *state.StateDB { func (bc *ChainManager) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { - // Prep genesis - AddTestNetFunds(bc.genesisBlock) - - block := types.NewBlockFromBytes(data) - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = block.Number.Uint64() + var block types.Block + rlp.Decode(bytes.NewReader(data), &block) + bc.currentBlock = &block + bc.lastBlockHash = block.Hash() + bc.lastBlockNumber = block.Header().Number.Uint64() // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + bc.td = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) } else { bc.Reset() } - chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) + chainlogger.Infof("Last block (#%d) %x\n", bc.lastBlockNumber, bc.currentBlock.Hash()) } // Block creation & chain handling func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { - var root interface{} - hash := ZeroHash256 + bc.mu.RLock() + defer bc.mu.RUnlock() + + var root []byte + parentHash := ZeroHash256 if bc.CurrentBlock != nil { - root = bc.CurrentBlock.Root() - hash = bc.LastBlockHash + root = bc.currentBlock.Header().Root + parentHash = bc.lastBlockHash } - block := types.CreateBlock( - root, - hash, + block := types.NewBlock( + parentHash, coinbase, + root, ethutil.BigPow(2, 32), nil, "") - parent := bc.CurrentBlock + parent := bc.currentBlock if parent != nil { - block.Difficulty = CalcDifficulty(block, parent) - block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) + header := block.Header() + header.Difficulty = CalcDifficulty(block, parent) + header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1) + header.GasLimit = CalcGasLimit(parent, block) } @@ -134,41 +195,46 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { } func (bc *ChainManager) Reset() { - AddTestNetFunds(bc.genesisBlock) + bc.mu.Lock() + defer bc.mu.Unlock() + + for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) { + ethutil.Config.Db.Delete(block.Hash()) + } - bc.genesisBlock.Trie().Sync() // Prepare the genesis block bc.write(bc.genesisBlock) bc.insert(bc.genesisBlock) - bc.CurrentBlock = bc.genesisBlock - - bc.SetTotalDifficulty(ethutil.Big("0")) + bc.currentBlock = bc.genesisBlock - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + bc.setTotalDifficulty(ethutil.Big("0")) } func (self *ChainManager) Export() []byte { - chainlogger.Infoln("exporting", self.CurrentBlock.Number, "blocks") + self.mu.RLock() + defer self.mu.RUnlock() - blocks := make(types.Blocks, int(self.CurrentBlock.Number.Int64())+1) - for block := self.CurrentBlock; block != nil; block = self.GetBlock(block.PrevHash) { - blocks[block.Number.Int64()] = block + chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number) + + blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1) + for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) { + blocks[block.NumberU64()] = block } + return ethutil.Encode(blocks) } func (bc *ChainManager) insert(block *types.Block) { - encodedBlock := block.RlpEncode() + encodedBlock := ethutil.Encode(block) ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() + bc.currentBlock = block + bc.lastBlockHash = block.Hash() } func (bc *ChainManager) write(block *types.Block) { bc.writeBlockInfo(block) - encodedBlock := block.RlpEncode() + encodedBlock := ethutil.Encode(block) ethutil.Config.Db.Put(block.Hash(), encodedBlock) } @@ -183,7 +249,7 @@ func (bc *ChainManager) HasBlock(hash []byte) bool { return len(data) != 0 } -func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { +func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) { block := self.GetBlock(hash) if block == nil { return @@ -193,11 +259,11 @@ func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain for i := uint64(0); i < max; i++ { chain = append(chain, block.Hash()) - if block.Number.Cmp(ethutil.Big0) <= 0 { + if block.Header().Number.Cmp(ethutil.Big0) <= 0 { break } - block = self.GetBlock(block.PrevHash) + block = self.GetBlock(block.Header().ParentHash) } return @@ -208,65 +274,61 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block { if len(data) == 0 { return nil } + var block types.Block + if err := rlp.Decode(bytes.NewReader(data), &block); err != nil { + fmt.Println(err) + return nil + } - return types.NewBlockFromBytes(data) + return &block } func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { - block := self.CurrentBlock - for ; block != nil; block = self.GetBlock(block.PrevHash) { - if block.Number.Uint64() == num { + self.mu.RLock() + defer self.mu.RUnlock() + + block := self.currentBlock + for ; block != nil; block = self.GetBlock(block.Header().ParentHash) { + if block.Header().Number.Uint64() == num { break } } - if block != nil && block.Number.Uint64() == 0 && num != 0 { + if block != nil && block.Header().Number.Uint64() == 0 && num != 0 { return nil } return block } -func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { +func (bc *ChainManager) setTotalDifficulty(td *big.Int) { ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) - bc.TD = td + bc.td = td } func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) { - parent := self.GetBlock(block.PrevHash) + parent := self.GetBlock(block.Header().ParentHash) if parent == nil { - return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) + return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash) } - parentTd := parent.BlockInfo().TD + parentTd := parent.Td uncleDiff := new(big.Int) - for _, uncle := range block.Uncles { + for _, uncle := range block.Uncles() { uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) } td := new(big.Int) td = td.Add(parentTd, uncleDiff) - td = td.Add(td, block.Difficulty) + td = td.Add(td, block.Header().Difficulty) return td, nil } -func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo { - bi := types.BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) - bi.RlpDecode(data) - - return bi -} - // Unexported method for writing extra non-essential block info to the db func (bc *ChainManager) writeBlockInfo(block *types.Block) { - bc.LastBlockNumber++ - bi := types.BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} - - // For now we use the block hash with the words "info" appended as key - ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode()) + bc.lastBlockNumber++ } func (bc *ChainManager) Stop() { @@ -283,23 +345,29 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { continue } - chainlogger.Infof("block #%v process failed (%x)\n", block.Number, block.Hash()[:4]) + h := block.Header() + chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4]) chainlogger.Infoln(block) chainlogger.Infoln(err) return err } - self.write(block) - if td.Cmp(self.TD) > 0 { - if block.Number.Cmp(new(big.Int).Add(self.CurrentBlock.Number, ethutil.Big1)) < 0 { - chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Number, block.Hash()[:4], self.CurrentBlock.Number, self.CurrentBlock.Hash()[:4]) + self.mu.Lock() + { + self.write(block) + cblock := self.currentBlock + if td.Cmp(self.td) > 0 { + if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 { + chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Header().Number, block.Hash()[:4], cblock.Header().Number, cblock.Hash()[:4]) + } + + self.setTotalDifficulty(td) + self.insert(block) + self.transState = state.New(cblock.Trie().Copy()) } - self.SetTotalDifficulty(td) - self.insert(block) - self.transState = self.State().Copy() - //sm.eth.TxPool().RemoveSet(block.Transactions()) } + self.mu.Unlock() self.eventMux.Post(NewBlockEvent{block}) self.eventMux.Post(messages) diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index a84e3ff3b..108718901 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -2,18 +2,138 @@ package core import ( "fmt" + "os" "path" + "reflect" + "runtime" + "strconv" "testing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/rlp" ) +//var Logger logpkg.LogSystem + +//var Log = logpkg.NewLogger("TEST") + +func init() { + runtime.GOMAXPROCS(runtime.NumCPU()) + //Logger = logpkg.NewStdLogSystem(os.Stdout, log.LstdFlags, logpkg.DebugLevel) + //logpkg.AddLogSystem(Logger) + + ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH") + + db, err := ethdb.NewMemDatabase() + if err != nil { + panic("Could not create mem-db, failing") + } + ethutil.Config.Db = db +} + +func loadChain(fn string, t *testing.T) (types.Blocks, error) { + fh, err := os.OpenFile(path.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm) + if err != nil { + return nil, err + } + defer fh.Close() + + var chain types.Blocks + if err := rlp.Decode(fh, &chain); err != nil { + return nil, err + } + + return chain, nil +} + +func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) { + err := chainMan.InsertChain(chain) + done <- true + if err != nil { + fmt.Println(err) + t.FailNow() + } +} + func TestChainInsertions(t *testing.T) { - c1, err := ethutil.ReadAllFile(path.Join("..", "_data", "chain1")) + chain1, err := loadChain("valid1", t) + if err != nil { + fmt.Println(err) + t.FailNow() + } + fmt.Println(len(chain1)) + + chain2, err := loadChain("valid2", t) if err != nil { fmt.Println(err) t.FailNow() } - data1, _ := ethutil.Decode([]byte(c1), 0) - fmt.Println(data1) + + var eventMux event.TypeMux + chainMan := NewChainManager(&eventMux) + txPool := NewTxPool(chainMan, &eventMux) + blockMan := NewBlockManager(txPool, chainMan, &eventMux) + chainMan.SetProcessor(blockMan) + + const max = 2 + done := make(chan bool, max) + + go insertChain(done, chainMan, chain1, t) + go insertChain(done, chainMan, chain2, t) + + for i := 0; i < max; i++ { + <-done + } + + if reflect.DeepEqual(chain2[len(chain2)-1], chainMan.CurrentBlock()) { + t.Error("chain2 is canonical and shouldn't be") + } + + if !reflect.DeepEqual(chain1[len(chain1)-1], chainMan.CurrentBlock()) { + t.Error("chain1 isn't canonical and should be") + } +} + +func TestChainMultipleInsertions(t *testing.T) { + const max = 4 + chains := make([]types.Blocks, max) + var longest int + for i := 0; i < max; i++ { + var err error + name := "valid" + strconv.Itoa(i+1) + chains[i], err = loadChain(name, t) + if len(chains[i]) >= len(chains[longest]) { + longest = i + } + fmt.Println("loaded", name, "with a length of", len(chains[i])) + if err != nil { + fmt.Println(err) + t.FailNow() + } + } + + var eventMux event.TypeMux + chainMan := NewChainManager(&eventMux) + txPool := NewTxPool(chainMan, &eventMux) + blockMan := NewBlockManager(txPool, chainMan, &eventMux) + chainMan.SetProcessor(blockMan) + done := make(chan bool, max) + for i, chain := range chains { + var i int = i + go func() { + insertChain(done, chainMan, chain, t) + fmt.Println(i, "done") + }() + } + + for i := 0; i < max; i++ { + <-done + } + + if !reflect.DeepEqual(chains[longest][len(chains[longest])-1], chainMan.CurrentBlock()) { + t.Error("Invalid canonical chain") + } } diff --git a/core/events.go b/core/events.go index deeba3e98..fe106da49 100644 --- a/core/events.go +++ b/core/events.go @@ -10,3 +10,6 @@ type TxPostEvent struct{ Tx *types.Transaction } // NewBlockEvent is posted when a block has been imported. type NewBlockEvent struct{ Block *types.Block } + +// NewMinedBlockEvent is posted when a block has been imported. +type NewMinedBlockEvent struct{ Block *types.Block } diff --git a/core/execution.go b/core/execution.go index 58d46c509..b7eead0dd 100644 --- a/core/execution.go +++ b/core/execution.go @@ -3,22 +3,21 @@ package core import ( "fmt" "math/big" + "time" - "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) type Execution struct { - vm vm.VirtualMachine + env vm.Environment address, input []byte Gas, price, value *big.Int - object *state.StateObject SkipTransfer bool } -func NewExecution(vm vm.VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { - return &Execution{vm: vm, address: address, input: input, Gas: gas, price: gasPrice, value: value} +func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution { + return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value} } func (self *Execution) Addr() []byte { @@ -27,14 +26,19 @@ func (self *Execution) Addr() []byte { func (self *Execution) Call(codeAddr []byte, caller vm.ClosureRef) ([]byte, error) { // Retrieve the executing code - code := self.vm.Env().State().GetCode(codeAddr) + code := self.env.State().GetCode(codeAddr) return self.exec(code, codeAddr, caller) } func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret []byte, err error) { - env := self.vm.Env() - chainlogger.Debugf("pre state %x\n", env.State().Root()) + env := self.env + evm := vm.New(env, vm.DebugVmTy) + + if env.Depth() == vm.MaxCallDepth { + // Consume all gas (by not returning it) and return a depth error + return nil, vm.DepthError{} + } from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address) // Skipping transfer is used on testing for the initial call @@ -49,32 +53,19 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret } snapshot := env.State().Copy() - defer func() { - if vm.IsDepthErr(err) || vm.IsOOGErr(err) { - env.State().Set(snapshot) - } - chainlogger.Debugf("post state %x\n", env.State().Root()) - }() - - self.object = to - // Pre-compiled contracts (address.go) 1, 2 & 3. - naddr := ethutil.BigD(contextAddr).Uint64() - if p := vm.Precompiled[naddr]; p != nil { - if self.Gas.Cmp(p.Gas(len(self.input))) >= 0 { - ret = p.Call(self.input) - self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret) - self.vm.Endl() - } - } else { - ret, err = self.vm.Run(to, caller, code, self.value, self.Gas, self.price, self.input) + start := time.Now() + ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input) + if err != nil { + env.State().Set(snapshot) } + chainlogger.Debugf("vm took %v\n", time.Since(start)) return } func (self *Execution) Create(caller vm.ClosureRef) (ret []byte, err error, account *state.StateObject) { ret, err = self.exec(self.input, nil, caller) - account = self.vm.Env().State().GetStateObject(self.address) + account = self.env.State().GetStateObject(self.address) return } diff --git a/core/filter.go b/core/filter.go index fe3665bf3..7c34748df 100644 --- a/core/filter.go +++ b/core/filter.go @@ -76,13 +76,14 @@ func (self *Filter) SetSkip(skip int) { // Run filters messages with the current parameters set func (self *Filter) Find() []*state.Message { + earliestBlock := self.eth.ChainManager().CurrentBlock() var earliestBlockNo uint64 = uint64(self.earliest) if self.earliest == -1 { - earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() + earliestBlockNo = earliestBlock.NumberU64() } var latestBlockNo uint64 = uint64(self.latest) if self.latest == -1 { - latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64() + latestBlockNo = earliestBlock.NumberU64() } var ( @@ -93,7 +94,7 @@ func (self *Filter) Find() []*state.Message { for i := 0; !quit && block != nil; i++ { // Quit on latest switch { - case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0: + case block.NumberU64() == earliestBlockNo, block.NumberU64() == 0: quit = true case self.max <= len(messages): break @@ -113,7 +114,7 @@ func (self *Filter) Find() []*state.Message { messages = append(messages, self.FilterMessages(msgs)...) } - block = self.eth.ChainManager().GetBlock(block.PrevHash) + block = self.eth.ChainManager().GetBlock(block.ParentHash()) } skip := int(math.Min(float64(len(messages)), float64(self.skip))) @@ -176,7 +177,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool { var fromIncluded, toIncluded bool if len(self.from) > 0 { for _, from := range self.from { - if types.BloomLookup(block.LogsBloom, from) || bytes.Equal(block.Coinbase, from) { + if types.BloomLookup(block.Bloom(), from) || bytes.Equal(block.Coinbase(), from) { fromIncluded = true break } @@ -187,7 +188,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool { if len(self.to) > 0 { for _, to := range self.to { - if types.BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase, to) { + if types.BloomLookup(block.Bloom(), ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase(), to) { toIncluded = true break } diff --git a/core/filter_test.go b/core/filter_test.go index d53b835b7..9a8bc9592 100644 --- a/core/filter_test.go +++ b/core/filter_test.go @@ -1,7 +1 @@ package core - -// import "testing" - -// func TestFilter(t *testing.T) { -// NewFilter(NewTestManager()) -// } diff --git a/core/genesis.go b/core/genesis.go index 707154759..10b40516f 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -3,8 +3,10 @@ package core import ( "math/big" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) /* @@ -17,36 +19,35 @@ var ZeroHash512 = make([]byte, 64) var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{})) var EmptyListRoot = crypto.Sha3(ethutil.Encode("")) -var GenesisHeader = []interface{}{ - // Previous hash (none) - ZeroHash256, - // Empty uncles - EmptyShaList, - // Coinbase - ZeroHash160, - // Root state - EmptyShaList, - // tx root - EmptyListRoot, - // receipt root - EmptyListRoot, - // bloom - ZeroHash512, - // Difficulty - //ethutil.BigPow(2, 22), - big.NewInt(131072), - // Number - ethutil.Big0, - // Block upper gas bound - big.NewInt(1000000), - // Block gas used - ethutil.Big0, - // Time - ethutil.Big0, - // Extra - nil, - // Nonce - crypto.Sha3(big.NewInt(42).Bytes()), -} +func GenesisBlock() *types.Block { + genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, big.NewInt(131072), crypto.Sha3(big.NewInt(42).Bytes()), "") + genesis.Header().Number = ethutil.Big0 + genesis.Header().GasLimit = big.NewInt(1000000) + genesis.Header().GasUsed = ethutil.Big0 + genesis.Header().Time = 0 + + genesis.SetUncles([]*types.Header{}) + genesis.SetTransactions(types.Transactions{}) + genesis.SetReceipts(types.Receipts{}) -var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} + statedb := state.New(genesis.Trie()) + for _, addr := range []string{ + "51ba59315b3a95761d0863b05ccc7a7f54703d99", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", + } { + codedAddr := ethutil.Hex2Bytes(addr) + account := statedb.GetAccount(codedAddr) + account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) + statedb.UpdateStateObject(account) + } + statedb.Sync() + genesis.Header().Root = statedb.Root() + + return genesis +} diff --git a/core/helper_test.go b/core/helper_test.go index b340144fd..b8bf254d7 100644 --- a/core/helper_test.go +++ b/core/helper_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/wire" + "github.com/ethereum/go-ethereum/p2p" ) // Implement our EthTest Manager @@ -54,11 +54,11 @@ func (tm *TestManager) TxPool() *TxPool { func (tm *TestManager) EventMux() *event.TypeMux { return tm.eventMux } -func (tm *TestManager) Broadcast(msgType wire.MsgType, data []interface{}) { +func (tm *TestManager) Broadcast(msgType p2p.Msg, data []interface{}) { fmt.Println("Broadcast not implemented") } -func (tm *TestManager) ClientIdentity() wire.ClientIdentity { +func (tm *TestManager) ClientIdentity() p2p.ClientIdentity { return nil } func (tm *TestManager) KeyManager() *crypto.KeyManager { diff --git a/core/state_transition.go b/core/state_transition.go index 820ba66e6..7b7026c29 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -5,6 +5,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -27,48 +29,69 @@ import ( */ type StateTransition struct { coinbase, receiver []byte - tx *types.Transaction + msg Message gas, gasPrice *big.Int + initialGas *big.Int value *big.Int data []byte state *state.StateDB block *types.Block cb, rec, sen *state.StateObject + + Env vm.Environment } -func NewStateTransition(coinbase *state.StateObject, tx *types.Transaction, state *state.StateDB, block *types.Block) *StateTransition { - return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} +type Message interface { + Hash() []byte + + From() []byte + To() []byte + + GasPrice() *big.Int + Gas() *big.Int + Value() *big.Int + + Nonce() uint64 + Data() []byte } -func (self *StateTransition) Coinbase() *state.StateObject { - if self.cb != nil { - return self.cb - } +func AddressFromMessage(msg Message) []byte { + // Generate a new address + return crypto.Sha3(ethutil.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:] +} - self.cb = self.state.GetOrNewStateObject(self.coinbase) - return self.cb +func MessageCreatesContract(msg Message) bool { + return len(msg.To()) == 0 } -func (self *StateTransition) Sender() *state.StateObject { - if self.sen != nil { - return self.sen - } - self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) +func MessageGasValue(msg Message) *big.Int { + return new(big.Int).Mul(msg.Gas(), msg.GasPrice()) +} - return self.sen +func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition { + return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), new(big.Int), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil} } -func (self *StateTransition) Receiver() *state.StateObject { - if self.tx != nil && self.tx.CreatesContract() { - return nil - } - if self.rec != nil { - return self.rec +func (self *StateTransition) VmEnv() vm.Environment { + if self.Env == nil { + self.Env = NewEnv(self.state, self.msg, self.block) } - self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) - return self.rec + return self.Env +} + +func (self *StateTransition) Coinbase() *state.StateObject { + return self.state.GetOrNewStateObject(self.coinbase) +} +func (self *StateTransition) From() *state.StateObject { + return self.state.GetOrNewStateObject(self.msg.From()) +} +func (self *StateTransition) To() *state.StateObject { + if self.msg != nil && MessageCreatesContract(self.msg) { + return nil + } + return self.state.GetOrNewStateObject(self.msg.To()) } func (self *StateTransition) UseGas(amount *big.Int) error { @@ -87,41 +110,33 @@ func (self *StateTransition) AddGas(amount *big.Int) { func (self *StateTransition) BuyGas() error { var err error - sender := self.Sender() - if sender.Balance().Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance()) + sender := self.From() + if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 { + return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance()) } coinbase := self.Coinbase() - err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + err = coinbase.BuyGas(self.msg.Gas(), self.msg.GasPrice()) if err != nil { return err } - self.AddGas(self.tx.Gas) - sender.SubAmount(self.tx.GasValue()) + self.AddGas(self.msg.Gas()) + self.initialGas.Set(self.msg.Gas()) + sender.SubAmount(MessageGasValue(self.msg)) return nil } -func (self *StateTransition) RefundGas() { - coinbase, sender := self.Coinbase(), self.Sender() - coinbase.RefundGas(self.gas, self.tx.GasPrice) - - // Return remaining gas - remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) - sender.AddAmount(remaining) -} - func (self *StateTransition) preCheck() (err error) { var ( - tx = self.tx - sender = self.Sender() + msg = self.msg + sender = self.From() ) // Make sure this transaction's nonce is correct - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) + if sender.Nonce != msg.Nonce() { + return NonceError(msg.Nonce(), sender.Nonce) } // Pre-pay gas / Buy gas of the coinbase account @@ -132,8 +147,8 @@ func (self *StateTransition) preCheck() (err error) { return nil } -func (self *StateTransition) TransitionState() (err error) { - statelogger.Debugf("(~) %x\n", self.tx.Hash()) +func (self *StateTransition) TransitionState() (ret []byte, err error) { + statelogger.Debugf("(~) %x\n", self.msg.Hash()) // XXX Transactions after this point are considered valid. if err = self.preCheck(); err != nil { @@ -141,8 +156,8 @@ func (self *StateTransition) TransitionState() (err error) { } var ( - tx = self.tx - sender = self.Sender() + msg = self.msg + sender = self.From() ) defer self.RefundGas() @@ -168,30 +183,56 @@ func (self *StateTransition) TransitionState() (err error) { return } - var ret []byte - vmenv := NewEnv(self.state, self.tx, self.block) + vmenv := self.VmEnv() var ref vm.ClosureRef - if tx.CreatesContract() { - self.rec = MakeContract(tx, self.state) - - ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.tx.Data, self.gas, self.gasPrice, self.value) - ref.SetCode(ret) + if MessageCreatesContract(msg) { + contract := MakeContract(msg, self.state) + ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) + if err == nil { + dataGas := big.NewInt(int64(len(ret))) + dataGas.Mul(dataGas, vm.GasCreateByte) + if err = self.UseGas(dataGas); err == nil { + //self.state.SetCode(ref.Address(), ret) + ref.SetCode(ret) + } + } } else { - ret, err = vmenv.Call(self.Sender(), self.Receiver().Address(), self.tx.Data, self.gas, self.gasPrice, self.value) + ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) } + if err != nil { - statelogger.Debugln(err) + self.UseGas(self.gas) } return } // Converts an transaction in to a state object -func MakeContract(tx *types.Transaction, state *state.StateDB) *state.StateObject { - addr := tx.CreationAddress(state) +func MakeContract(msg Message, state *state.StateDB) *state.StateObject { + addr := AddressFromMessage(msg) contract := state.GetOrNewStateObject(addr) - contract.InitCode = tx.Data + contract.InitCode = msg.Data() return contract } + +func (self *StateTransition) RefundGas() { + coinbase, sender := self.Coinbase(), self.From() + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) + sender.AddAmount(remaining) + + uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2) + for addr, ref := range self.state.Refunds() { + refund := ethutil.BigMin(uhalf, ref) + self.gas.Add(self.gas, refund) + self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) + } + + coinbase.RefundGas(self.gas, self.msg.GasPrice()) +} + +func (self *StateTransition) GasUsed() *big.Int { + return new(big.Int).Sub(self.initialGas, self.gas) +} diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 7166d35e8..1149d4cfb 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -8,9 +8,9 @@ import ( "sync" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/wire" ) var txplogger = logger.NewLogger("TXP") @@ -18,7 +18,9 @@ var txplogger = logger.NewLogger("TXP") const txPoolQueueSize = 50 type TxPoolHook chan *types.Transaction -type TxMsgTy byte +type TxMsg struct { + Tx *types.Transaction +} const ( minGasPrice = 1000000 @@ -26,11 +28,6 @@ const ( var MinGasPrice = big.NewInt(10000000000000) -type TxMsg struct { - Tx *types.Transaction - Type TxMsgTy -} - func EachTx(pool *list.List, it func(*types.Transaction, *list.Element) bool) { for e := pool.Front(); e != nil; e = e.Next() { if it(e.Value.(*types.Transaction), e) { @@ -61,7 +58,6 @@ type TxProcessor interface { // pool is being drained or synced for whatever reason the transactions // will simple queue up and handled when the mutex is freed. type TxPool struct { - Ethereum EthManager // The mutex for accessing the Tx pool. mutex sync.Mutex // Queueing channel for reading and writing incoming @@ -75,14 +71,18 @@ type TxPool struct { SecondaryProcessor TxProcessor subscribers []chan TxMsg + + chainManager *ChainManager + eventMux *event.TypeMux } -func NewTxPool(ethereum EthManager) *TxPool { +func NewTxPool(chainManager *ChainManager, eventMux *event.TypeMux) *TxPool { return &TxPool{ - pool: list.New(), - queueChan: make(chan *types.Transaction, txPoolQueueSize), - quit: make(chan bool), - Ethereum: ethereum, + pool: list.New(), + queueChan: make(chan *types.Transaction, txPoolQueueSize), + quit: make(chan bool), + chainManager: chainManager, + eventMux: eventMux, } } @@ -94,20 +94,20 @@ func (pool *TxPool) addTransaction(tx *types.Transaction) { pool.pool.PushBack(tx) // Broadcast the transaction to the rest of the peers - pool.Ethereum.Broadcast(wire.MsgTxTy, []interface{}{tx.RlpData()}) + pool.eventMux.Post(TxPreEvent{tx}) } func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { // Get the last block so we can retrieve the sender and receiver from // the merkle trie - block := pool.Ethereum.ChainManager().CurrentBlock + block := pool.chainManager.CurrentBlock // Something has gone horribly wrong if this happens if block == nil { return fmt.Errorf("No last block on the block chain") } - if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { - return fmt.Errorf("Invalid recipient. len = %d", len(tx.Recipient)) + if len(tx.To()) != 0 && len(tx.To()) != 20 { + return fmt.Errorf("Invalid recipient. len = %d", len(tx.To())) } v, _, _ := tx.Curve() @@ -116,19 +116,17 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { } // Get the sender - sender := pool.Ethereum.ChainManager().State().GetAccount(tx.Sender()) + senderAddr := tx.From() + if senderAddr == nil { + return fmt.Errorf("invalid sender") + } + sender := pool.chainManager.State().GetAccount(senderAddr) - totAmount := new(big.Int).Set(tx.Value) + totAmount := new(big.Int).Set(tx.Value()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. if sender.Balance().Cmp(totAmount) < 0 { - return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) - } - - if tx.IsContract() { - if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { - return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) - } + return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From()) } // Increment the nonce making each tx valid only once to prevent replay @@ -154,13 +152,10 @@ func (self *TxPool) Add(tx *types.Transaction) error { self.addTransaction(tx) - tmp := make([]byte, 4) - copy(tmp, tx.Recipient) - - txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.From()[:4], tx.To()[:4], tx.Value, tx.Hash()) // Notify the subscribers - go self.Ethereum.EventMux().Post(TxPreEvent{tx}) + go self.eventMux.Post(TxPreEvent{tx}) return nil } @@ -169,7 +164,17 @@ func (self *TxPool) Size() int { return self.pool.Len() } -func (pool *TxPool) CurrentTransactions() []*types.Transaction { +func (self *TxPool) AddTransactions(txs []*types.Transaction) { + for _, tx := range txs { + if err := self.Add(tx); err != nil { + txplogger.Infoln(err) + } else { + txplogger.Infof("tx %x\n", tx.Hash()[0:4]) + } + } +} + +func (pool *TxPool) GetTransactions() []*types.Transaction { pool.mutex.Lock() defer pool.mutex.Unlock() @@ -192,9 +197,9 @@ func (pool *TxPool) RemoveInvalid(state *state.StateDB) { for e := pool.pool.Front(); e != nil; e = e.Next() { tx := e.Value.(*types.Transaction) - sender := state.GetAccount(tx.Sender()) + sender := state.GetAccount(tx.From()) err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce >= tx.Nonce { + if err != nil || sender.Nonce >= tx.Nonce() { pool.pool.Remove(e) } } @@ -216,7 +221,7 @@ func (self *TxPool) RemoveSet(txs types.Transactions) { } func (pool *TxPool) Flush() []*types.Transaction { - txList := pool.CurrentTransactions() + txList := pool.GetTransactions() // Recreate a new list all together // XXX Is this the fastest way? diff --git a/core/types/block.go b/core/types/block.go index 0108bd586..7b4695f73 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -9,408 +9,259 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/ptrie" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/trie" ) -type BlockInfo struct { - Number uint64 - Hash []byte - Parent []byte - TD *big.Int -} - -func (bi *BlockInfo) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - bi.Number = decoder.Get(0).Uint() - bi.Hash = decoder.Get(1).Bytes() - bi.Parent = decoder.Get(2).Bytes() - bi.TD = decoder.Get(3).BigInt() -} - -func (bi *BlockInfo) RlpEncode() []byte { - return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD}) -} - -type Blocks []*Block - -func (self Blocks) AsSet() ethutil.UniqueSet { - set := make(ethutil.UniqueSet) - for _, block := range self { - set.Insert(block.Hash()) - } - - return set -} - -type BlockBy func(b1, b2 *Block) bool - -func (self BlockBy) Sort(blocks Blocks) { - bs := blockSorter{ - blocks: blocks, - by: self, - } - sort.Sort(bs) -} - -type blockSorter struct { - blocks Blocks - by func(b1, b2 *Block) bool -} - -func (self blockSorter) Len() int { return len(self.blocks) } -func (self blockSorter) Swap(i, j int) { - self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] -} -func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } - -func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } - -type Block struct { +type Header struct { // Hash to the previous block - PrevHash ethutil.Bytes + ParentHash ethutil.Bytes // Uncles of this block - Uncles Blocks - UncleSha []byte + UncleHash []byte // The coin base address Coinbase []byte // Block Trie state - //state *ethutil.Trie - state *state.StateDB + Root []byte + // Tx sha + TxHash []byte + // Receipt sha + ReceiptHash []byte + // Bloom + Bloom []byte // Difficulty for the current block Difficulty *big.Int - // Creation time - Time int64 // The block number Number *big.Int // Gas limit GasLimit *big.Int // Gas used GasUsed *big.Int + // Creation time + Time uint64 // Extra data Extra string // Block Nonce for verification Nonce ethutil.Bytes - // List of transactions and/or contracts - transactions Transactions - receipts Receipts - TxSha, ReceiptSha []byte - LogsBloom []byte - - Reward *big.Int } -func NewBlockFromBytes(raw []byte) *Block { - block := &Block{} - block.RlpDecode(raw) +func (self *Header) rlpData(withNonce bool) []interface{} { + fields := []interface{}{self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra} + if withNonce { + fields = append(fields, self.Nonce) + } - return block + return fields } -// New block takes a raw encoded string -func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { - block := &Block{} - block.RlpValueDecode(rlpValue) +func (self *Header) RlpData() interface{} { + return self.rlpData(true) +} - return block +func (self *Header) Hash() []byte { + return crypto.Sha3(ethutil.Encode(self.rlpData(true))) } -func CreateBlock(root interface{}, - prevHash []byte, - base []byte, - Difficulty *big.Int, - Nonce []byte, - extra string) *Block { - - block := &Block{ - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), +func (self *Header) HashNoNonce() []byte { + return crypto.Sha3(ethutil.Encode(self.rlpData(false))) +} + +type Block struct { + header *Header + uncles []*Header + transactions Transactions + Td *big.Int + + receipts Receipts + Reward *big.Int +} + +func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce []byte, extra string) *Block { + header := &Header{ + Root: root, + ParentHash: parentHash, + Coinbase: coinbase, + Difficulty: difficulty, + Nonce: nonce, + Time: uint64(time.Now().Unix()), Extra: extra, - UncleSha: nil, GasUsed: new(big.Int), GasLimit: new(big.Int), } - block.SetUncles([]*Block{}) - block.state = state.New(trie.New(ethutil.Config.Db, root)) + block := &Block{header: header, Reward: new(big.Int)} return block } -// Returns a hash of the block -func (block *Block) Hash() ethutil.Bytes { - return crypto.Sha3(ethutil.NewValue(block.header()).Encode()) - //return crypto.Sha3(block.Value().Encode()) -} - -func (block *Block) HashNoNonce() []byte { - return crypto.Sha3(ethutil.Encode(block.miningHeader())) -} - -func (block *Block) State() *state.StateDB { - return block.state +func NewBlockWithHeader(header *Header) *Block { + return &Block{header: header} } -func (block *Block) Transactions() Transactions { - return block.transactions -} - -func (block *Block) CalcGasLimit(parent *Block) *big.Int { - if block.Number.Cmp(big.NewInt(0)) == 0 { - return ethutil.BigPow(10, 6) +func (self *Block) DecodeRLP(s *rlp.Stream) error { + if _, err := s.List(); err != nil { + return err } - // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 - - previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) - current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed), big.NewRat(6, 5)) - curInt := new(big.Int).Div(current.Num(), current.Denom()) - - result := new(big.Int).Add(previous, curInt) - result.Div(result, big.NewInt(1024)) - - min := big.NewInt(125000) - - return ethutil.BigMax(min, result) -} - -func (block *Block) BlockInfo() BlockInfo { - bi := BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) - bi.RlpDecode(data) - - return bi -} - -func (self *Block) GetTransaction(hash []byte) *Transaction { - for _, tx := range self.transactions { - if bytes.Compare(tx.Hash(), hash) == 0 { - return tx - } + var header Header + if err := s.Decode(&header); err != nil { + return err } - return nil -} - -// Sync the block's state and contract respectively -func (block *Block) Sync() { - block.state.Sync() -} - -func (block *Block) Undo() { - // Sync the block state itself - block.state.Reset() -} - -/////// Block Encoding -func (block *Block) rlpReceipts() interface{} { - // Marshal the transactions of this block - encR := make([]interface{}, len(block.receipts)) - for i, r := range block.receipts { - // Cast it to a string (safe) - encR[i] = r.RlpData() + var transactions []*Transaction + if err := s.Decode(&transactions); err != nil { + return err } - return encR -} + var uncleHeaders []*Header + if err := s.Decode(&uncleHeaders); err != nil { + return err + } -func (block *Block) rlpUncles() interface{} { - // Marshal the transactions of this block - uncles := make([]interface{}, len(block.Uncles)) - for i, uncle := range block.Uncles { - // Cast it to a string (safe) - uncles[i] = uncle.header() + var tdBytes []byte + if err := s.Decode(&tdBytes); err != nil { + // If this block comes from the network that's fine. If loaded from disk it should be there + // Blocks don't store their Td when propagated over the network + } else { + self.Td = ethutil.BigD(tdBytes) } - return uncles -} + if err := s.ListEnd(); err != nil { + return err + } -func (block *Block) SetUncles(uncles []*Block) { - block.Uncles = uncles - block.UncleSha = crypto.Sha3(ethutil.Encode(block.rlpUncles())) -} + self.header = &header + self.uncles = uncleHeaders + self.transactions = transactions -func (self *Block) SetReceipts(receipts Receipts) { - self.receipts = receipts - self.ReceiptSha = DeriveSha(receipts) - self.LogsBloom = CreateBloom(receipts) + return nil } -func (self *Block) SetTransactions(txs Transactions) { - self.transactions = txs - self.TxSha = DeriveSha(txs) +func (self *Block) Header() *Header { + return self.header } -func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()}) +func (self *Block) Uncles() []*Header { + return self.uncles } -func (block *Block) RlpEncode() []byte { - // Encode a slice interface which contains the header and the list of - // transactions. - return block.Value().Encode() +func (self *Block) SetUncles(uncleHeaders []*Header) { + self.uncles = uncleHeaders + self.header.UncleHash = crypto.Sha3(ethutil.Encode(uncleHeaders)) } -func (block *Block) RlpDecode(data []byte) { - rlpValue := ethutil.NewValueFromBytes(data) - block.RlpValueDecode(rlpValue) +func (self *Block) Transactions() Transactions { + return self.transactions } -func (block *Block) RlpValueDecode(decoder *ethutil.Value) { - block.setHeader(decoder.Get(0)) - - // Tx list might be empty if this is an uncle. Uncles only have their - // header set. - if decoder.Get(1).IsNil() == false { // Yes explicitness - //receipts := decoder.Get(1) - //block.receipts = make([]*Receipt, receipts.Len()) - txs := decoder.Get(1) - block.transactions = make(Transactions, txs.Len()) - for i := 0; i < txs.Len(); i++ { - block.transactions[i] = NewTransactionFromValue(txs.Get(i)) - //receipt := NewRecieptFromValue(receipts.Get(i)) - //block.transactions[i] = receipt.Tx - //block.receipts[i] = receipt - } - - } - - if decoder.Get(2).IsNil() == false { // Yes explicitness - uncles := decoder.Get(2) - block.Uncles = make([]*Block, uncles.Len()) - for i := 0; i < uncles.Len(); i++ { - block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) +func (self *Block) Transaction(hash []byte) *Transaction { + for _, transaction := range self.transactions { + if bytes.Equal(hash, transaction.Hash()) { + return transaction } } - + return nil } -func (self *Block) setHeader(header *ethutil.Value) { - self.PrevHash = header.Get(0).Bytes() - self.UncleSha = header.Get(1).Bytes() - self.Coinbase = header.Get(2).Bytes() - self.state = state.New(trie.New(ethutil.Config.Db, header.Get(3).Val)) - self.TxSha = header.Get(4).Bytes() - self.ReceiptSha = header.Get(5).Bytes() - self.LogsBloom = header.Get(6).Bytes() - self.Difficulty = header.Get(7).BigInt() - self.Number = header.Get(8).BigInt() - self.GasLimit = header.Get(9).BigInt() - self.GasUsed = header.Get(10).BigInt() - self.Time = int64(header.Get(11).BigInt().Uint64()) - self.Extra = header.Get(12).Str() - self.Nonce = header.Get(13).Bytes() +func (self *Block) SetTransactions(transactions Transactions) { + self.transactions = transactions + self.header.TxHash = DeriveSha(transactions) } -func NewUncleBlockFromValue(header *ethutil.Value) *Block { - block := &Block{} - block.setHeader(header) - - return block +func (self *Block) Receipts() Receipts { + return self.receipts } -func (block *Block) Trie() *trie.Trie { - return block.state.Trie +func (self *Block) SetReceipts(receipts Receipts) { + self.receipts = receipts + self.header.ReceiptHash = DeriveSha(receipts) + self.header.Bloom = CreateBloom(receipts) } -func (block *Block) Root() interface{} { - return block.state.Root() +func (self *Block) RlpData() interface{} { + return []interface{}{self.header, self.transactions, self.uncles} +} + +func (self *Block) RlpDataForStorage() interface{} { + return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */} +} + +// Header accessors (add as you need them) +func (self *Block) Number() *big.Int { return self.header.Number } +func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } +func (self *Block) ParentHash() []byte { return self.header.ParentHash } +func (self *Block) Bloom() []byte { return self.header.Bloom } +func (self *Block) Coinbase() []byte { return self.header.Coinbase } +func (self *Block) Time() int64 { return int64(self.header.Time) } +func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } +func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } +func (self *Block) Hash() []byte { return self.header.Hash() } +func (self *Block) Trie() *ptrie.Trie { return ptrie.New(self.header.Root, ethutil.Config.Db) } +func (self *Block) State() *state.StateDB { return state.New(self.Trie()) } +func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) } +func (self *Block) SetRoot(root []byte) { self.header.Root = root } + +// Implement block.Pow +func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } +func (self *Block) N() []byte { return self.header.Nonce } +func (self *Block) HashNoNonce() []byte { + return crypto.Sha3(ethutil.Encode(self.header.rlpData(false))) +} + +func (self *Block) String() string { + return fmt.Sprintf(`BLOCK(%x): Size: %v { +Header: +[ +%v +] +Transactions: +%v +Uncles: +%v +} +`, self.header.Hash(), self.Size(), self.header, self.transactions, self.uncles) +} + +func (self *Header) String() string { + return fmt.Sprintf(` + ParentHash: %x + UncleHash: %x + Coinbase: %x + Root: %x + TxSha %x + ReceiptSha: %x + Bloom: %x + Difficulty: %v + Number: %v + GasLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x +`, self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.Nonce) } -func (block *Block) Diff() *big.Int { - return block.Difficulty -} +type Blocks []*Block -func (self *Block) Receipts() []*Receipt { - return self.receipts -} +type BlockBy func(b1, b2 *Block) bool -func (block *Block) miningHeader() []interface{} { - return []interface{}{ - // Sha of the previous block - block.PrevHash, - // Sha of uncles - block.UncleSha, - // Coinbase address - block.Coinbase, - // root state - block.Root(), - // tx root - block.TxSha, - // Sha of tx - block.ReceiptSha, - // Bloom - block.LogsBloom, - // Current block Difficulty - block.Difficulty, - // The block number - block.Number, - // Block upper gas bound - block.GasLimit, - // Block gas used - block.GasUsed, - // Time the block was found? - block.Time, - // Extra data - block.Extra, +func (self BlockBy) Sort(blocks Blocks) { + bs := blockSorter{ + blocks: blocks, + by: self, } + sort.Sort(bs) } -func (block *Block) header() []interface{} { - return append(block.miningHeader(), block.Nonce) -} - -func (block *Block) String() string { - return fmt.Sprintf(` - BLOCK(%x): Size: %v - PrevHash: %x - UncleSha: %x - Coinbase: %x - Root: %x - TxSha %x - ReceiptSha: %x - Bloom: %x - Difficulty: %v - Number: %v - MaxLimit: %v - GasUsed: %v - Time: %v - Extra: %v - Nonce: %x - NumTx: %v -`, - block.Hash(), - block.Size(), - block.PrevHash, - block.UncleSha, - block.Coinbase, - block.Root(), - block.TxSha, - block.ReceiptSha, - block.LogsBloom, - block.Difficulty, - block.Number, - block.GasLimit, - block.GasUsed, - block.Time, - block.Extra, - block.Nonce, - len(block.transactions), - ) -} - -func (self *Block) Size() ethutil.StorageSize { - return ethutil.StorageSize(len(self.RlpEncode())) +type blockSorter struct { + blocks Blocks + by func(b1, b2 *Block) bool } -// Implement RlpEncodable -func (self *Block) RlpData() interface{} { - return self.Value().Val +func (self blockSorter) Len() int { return len(self.blocks) } +func (self blockSorter) Swap(i, j int) { + self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] } +func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } -// Implement pow.Block -func (self *Block) N() []byte { return self.Nonce } +func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 } diff --git a/core/types/block_test.go b/core/types/block_test.go new file mode 100644 index 000000000..c85708975 --- /dev/null +++ b/core/types/block_test.go @@ -0,0 +1,23 @@ +package types + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/rlp" +) + +func init() { + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + ethutil.Config.Db, _ = ethdb.NewMemDatabase() +} + +func TestNewBlock(t *testing.T) { + block := GenesisBlock() + data := ethutil.Encode(block) + + var genesis Block + err := rlp.Decode(bytes.NewReader(data), &genesis) +} diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go index 1897ff198..0beb19670 100644 --- a/core/types/derive_sha.go +++ b/core/types/derive_sha.go @@ -2,7 +2,7 @@ package types import ( "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/ptrie" ) type DerivableList interface { @@ -11,10 +11,10 @@ type DerivableList interface { } func DeriveSha(list DerivableList) []byte { - trie := trie.New(ethutil.Config.Db, "") + trie := ptrie.New(nil, ethutil.Config.Db) for i := 0; i < list.Len(); i++ { - trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i))) + trie.Update(ethutil.Encode(i), list.GetRlp(i)) } - return trie.GetRoot() + return trie.Root() } diff --git a/core/types/transaction.go b/core/types/transaction.go index 63edef756..59244adc3 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -1,42 +1,37 @@ package types import ( + "bytes" "fmt" "math/big" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/rlp" "github.com/obscuren/secp256k1-go" ) -var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - func IsContractAddr(addr []byte) bool { return len(addr) == 0 - //return bytes.Compare(addr, ContractAddr) == 0 } type Transaction struct { - Nonce uint64 - Recipient []byte - Value *big.Int - Gas *big.Int - GasPrice *big.Int - Data []byte - v byte - r, s []byte - - // Indicates whether this tx is a contract creation transaction - contractCreation bool + AccountNonce uint64 + Price *big.Int + GasLimit *big.Int + Recipient []byte + Amount *big.Int + Payload []byte + V uint64 + R, S []byte } -func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} +func NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction { + return NewTransactionMessage(nil, Amount, gasAmount, price, data) } -func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)} +func NewTransactionMessage(to []byte, Amount, gasAmount, price *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -46,46 +41,55 @@ func NewTransactionFromBytes(data []byte) *Transaction { return tx } -func NewTransactionFromValue(val *ethutil.Value) *Transaction { +func NewTransactionFromAmount(val *ethutil.Value) *Transaction { tx := &Transaction{} tx.RlpValueDecode(val) return tx } -func (self *Transaction) GasValue() *big.Int { - return new(big.Int).Mul(self.Gas, self.GasPrice) +func (tx *Transaction) Hash() []byte { + data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} + + return crypto.Sha3(ethutil.Encode(data)) +} + +func (self *Transaction) Data() []byte { + return self.Payload } -func (self *Transaction) TotalValue() *big.Int { - v := self.GasValue() - return v.Add(v, self.Value) +func (self *Transaction) Gas() *big.Int { + return self.GasLimit } -func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} +func (self *Transaction) GasPrice() *big.Int { + return self.Price +} - return crypto.Sha3(ethutil.NewValue(data).Encode()) +func (self *Transaction) Value() *big.Int { + return self.Amount } -func (tx *Transaction) CreatesContract() bool { - return tx.contractCreation +func (self *Transaction) Nonce() uint64 { + return self.AccountNonce } -/* Deprecated */ -func (tx *Transaction) IsContract() bool { - return tx.CreatesContract() +func (self *Transaction) SetNonce(AccountNonce uint64) { + self.AccountNonce = AccountNonce } -func (tx *Transaction) CreationAddress(state *state.StateDB) []byte { - // Generate a new address - return crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] +func (self *Transaction) From() []byte { + return self.sender() +} + +func (self *Transaction) To() []byte { + return self.Recipient } func (tx *Transaction) Curve() (v byte, r []byte, s []byte) { - v = tx.v - r = ethutil.LeftPadBytes(tx.r, 32) - s = ethutil.LeftPadBytes(tx.s, 32) + v = byte(tx.V) + r = ethutil.LeftPadBytes(tx.R, 32) + s = ethutil.LeftPadBytes(tx.S, 32) return } @@ -106,18 +110,18 @@ func (tx *Transaction) PublicKey() []byte { sig := append(r, s...) sig = append(sig, v-27) - pubkey := crypto.Ecrecover(append(hash, sig...)) - //pubkey, _ := secp256k1.RecoverPubkey(hash, sig) + //pubkey := crypto.Ecrecover(append(hash, sig...)) + pubkey, _ := secp256k1.RecoverPubkey(hash, sig) return pubkey } -func (tx *Transaction) Sender() []byte { +func (tx *Transaction) sender() []byte { pubkey := tx.PublicKey() // Validate the returned key. // Return nil if public key isn't in full format - if len(pubkey) != 0 && pubkey[0] != 4 { + if len(pubkey) == 0 || pubkey[0] != 4 { return nil } @@ -128,48 +132,37 @@ func (tx *Transaction) Sign(privk []byte) error { sig := tx.Signature(privk) - tx.r = sig[:32] - tx.s = sig[32:64] - tx.v = sig[64] + 27 + tx.R = sig[:32] + tx.S = sig[32:64] + tx.V = uint64(sig[64] + 27) return nil } func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - - // TODO Remove prefixing zero's - - return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) -} + data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload} -func (tx *Transaction) RlpValue() *ethutil.Value { - return ethutil.NewValue(tx.RlpData()) + return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes()) } func (tx *Transaction) RlpEncode() []byte { - return tx.RlpValue().Encode() + return ethutil.Encode(tx) } func (tx *Transaction) RlpDecode(data []byte) { - tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) + rlp.Decode(bytes.NewReader(data), tx) } func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { - tx.Nonce = decoder.Get(0).Uint() - tx.GasPrice = decoder.Get(1).BigInt() - tx.Gas = decoder.Get(2).BigInt() + tx.AccountNonce = decoder.Get(0).Uint() + tx.Price = decoder.Get(1).BigInt() + tx.GasLimit = decoder.Get(2).BigInt() tx.Recipient = decoder.Get(3).Bytes() - tx.Value = decoder.Get(4).BigInt() - tx.Data = decoder.Get(5).Bytes() - tx.v = byte(decoder.Get(6).Uint()) - - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - - if IsContractAddr(tx.Recipient) { - tx.contractCreation = true - } + tx.Amount = decoder.Get(4).BigInt() + tx.Payload = decoder.Get(5).Bytes() + tx.V = decoder.Get(6).Uint() + tx.R = decoder.Get(7).Bytes() + tx.S = decoder.Get(8).Bytes() } func (tx *Transaction) String() string { @@ -180,25 +173,28 @@ func (tx *Transaction) String() string { To: %x Nonce: %v GasPrice: %v - Gas: %v + GasLimit %v Value: %v Data: 0x%x V: 0x%x R: 0x%x S: 0x%x - `, + Hex: %x +`, tx.Hash(), len(tx.Recipient) == 0, - tx.Sender(), - tx.Recipient, - tx.Nonce, - tx.GasPrice, - tx.Gas, - tx.Value, - tx.Data, - tx.v, - tx.r, - tx.s) + tx.From(), + tx.To(), + tx.AccountNonce, + tx.Price, + tx.GasLimit, + tx.Amount, + tx.Payload, + tx.V, + tx.R, + tx.S, + ethutil.Encode(tx), + ) } // Transaction slice type for basic sorting @@ -221,5 +217,5 @@ func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) } type TxByNonce struct{ Transactions } func (s TxByNonce) Less(i, j int) bool { - return s.Transactions[i].Nonce < s.Transactions[j].Nonce + return s.Transactions[i].AccountNonce < s.Transactions[j].AccountNonce } diff --git a/core/vm_env.go b/core/vm_env.go index 9e1815188..209115eab 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -11,28 +11,28 @@ import ( type VMEnv struct { state *state.StateDB block *types.Block - tx *types.Transaction + msg Message depth int } -func NewEnv(state *state.StateDB, tx *types.Transaction, block *types.Block) *VMEnv { +func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv { return &VMEnv{ state: state, block: block, - tx: tx, + msg: msg, } } -func (self *VMEnv) Origin() []byte { return self.tx.Sender() } -func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } -func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } -func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } -func (self *VMEnv) Time() int64 { return self.block.Time } -func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) Origin() []byte { return self.msg.From() } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() } +func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() } +func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() } +func (self *VMEnv) Time() int64 { return self.block.Time() } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() } func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } -func (self *VMEnv) Value() *big.Int { return self.tx.Value } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() } +func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) State() *state.StateDB { return self.state } -func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } func (self *VMEnv) Depth() int { return self.depth } func (self *VMEnv) SetDepth(i int) { self.depth = i } func (self *VMEnv) AddLog(log state.Log) { @@ -43,9 +43,7 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { } func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution { - evm := vm.New(self, vm.DebugVmTy) - - return NewExecution(evm, addr, data, gas, price, value) + return NewExecution(self, addr, data, gas, price, value) } func (self *VMEnv) Call(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { |