From 655e94259765b02454df93205a30a271103de5a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 13:14:21 +0100 Subject: Added GetBlock GetUncle with OOB guard --- core/block_processor.go | 6 +++++- core/block_processor_test.go | 34 ++++++++++++++++++++++++++++++++++ core/chain_manager.go | 16 ++++++++-------- core/types/block.go | 12 ++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 core/block_processor_test.go (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index 893c586dd..b4449100f 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -250,7 +250,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error { } if block.Time() > time.Now().Unix() { - return fmt.Errorf("block time is in the future") + return BlockFutureErr + } + + if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 { + return BlockNumberErr } // Verify the nonce of the block. Return an error if it's not valid diff --git a/core/block_processor_test.go b/core/block_processor_test.go new file mode 100644 index 000000000..35aeaa714 --- /dev/null +++ b/core/block_processor_test.go @@ -0,0 +1,34 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" +) + +func proc() (*BlockProcessor, *ChainManager) { + db, _ := ethdb.NewMemDatabase() + var mux event.TypeMux + + chainMan := NewChainManager(db, &mux) + return NewBlockProcessor(db, nil, chainMan, &mux), chainMan +} + +func TestNumber(t *testing.T) { + bp, chain := proc() + block1 := chain.NewBlock(nil) + block1.Header().Number = big.NewInt(3) + + err := bp.ValidateBlock(block1, chain.Genesis()) + if err != BlockNumberErr { + t.Errorf("expected block number error") + } + + block1 = chain.NewBlock(nil) + err = bp.ValidateBlock(block1, chain.Genesis()) + if err == BlockNumberErr { + t.Errorf("didn't expect block number error") + } +} diff --git a/core/chain_manager.go b/core/chain_manager.go index 22d54be03..286282064 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -87,6 +87,14 @@ type ChainManager struct { transState *state.StateDB } +func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { + bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} + bc.setLastBlock() + bc.transState = bc.State().Copy() + + return bc +} + func (self *ChainManager) Td() *big.Int { self.mu.RLock() defer self.mu.RUnlock() @@ -108,14 +116,6 @@ func (self *ChainManager) CurrentBlock() *types.Block { return self.currentBlock } -func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { - bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} - bc.setLastBlock() - bc.transState = bc.State().Copy() - - return bc -} - func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) { self.mu.RLock() defer self.mu.RUnlock() diff --git a/core/types/block.go b/core/types/block.go index fa28f5cc7..d57de1311 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -185,6 +185,18 @@ func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } func (self *Block) Root() []byte { return self.header.Root } func (self *Block) SetRoot(root []byte) { self.header.Root = root } func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) } +func (self *Block) GetTransaction(i int) *Transaction { + if len(self.transactions) > i { + return self.transactions[i] + } + return nil +} +func (self *Block) GetUncle(i int) *Header { + if len(self.uncles) > i { + return self.uncles[i] + } + return nil +} // Implement pow.Block func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } -- cgit v1.2.3 From ee9df32dba5091069cbdad8d00dc15738d676d5b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Feb 2015 16:08:51 +0100 Subject: Added errors --- core/error.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'core') diff --git a/core/error.go b/core/error.go index 11d8c1653..6af48ac2d 100644 --- a/core/error.go +++ b/core/error.go @@ -1,10 +1,16 @@ package core import ( + "errors" "fmt" "math/big" ) +var ( + BlockNumberErr = errors.New("block number invalid") + BlockFutureErr = errors.New("block time is in the future") +) + // Parent error. In case a parent is unknown this error will be thrown // by the block manager type ParentErr struct { -- cgit v1.2.3 From fa4cbad315609e41d88c59ecbce7c6c6169fc57a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 22:33:22 +0100 Subject: Optimisations and fixed a couple of DDOS issues in the miner --- core/block_processor.go | 25 ++++++++++++++----------- core/chain_manager.go | 25 ++++++++++++++++++++----- core/error.go | 17 ----------------- core/events.go | 3 +++ core/state_transition.go | 3 ++- core/transaction_pool.go | 33 ++++++++++++++++++++++++--------- 6 files changed, 63 insertions(+), 43 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index b4449100f..a9795385f 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -73,24 +73,27 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block return receipts, nil } -func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, state *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { +func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { // If we are mining this block and validating we want to set the logs back to 0 - state.EmptyLogs() + statedb.EmptyLogs() txGas := new(big.Int).Set(tx.Gas()) - cb := state.GetStateObject(coinbase.Address()) - st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb) + cb := statedb.GetStateObject(coinbase.Address()) + st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb) _, err := st.TransitionState() + if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err)) { + return nil, nil, err + } txGas.Sub(txGas, st.gas) // Update the state with pending changes - state.Update(txGas) + statedb.Update(txGas) cumulative := new(big.Int).Set(usedGas.Add(usedGas, txGas)) - receipt := types.NewReceipt(state.Root(), cumulative) - receipt.SetLogs(state.Logs()) + receipt := types.NewReceipt(statedb.Root(), cumulative) + receipt.SetLogs(statedb.Logs()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) chainlogger.Debugln(receipt) @@ -99,12 +102,12 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, state go self.eventMux.Post(TxPostEvent{tx}) } - go self.eventMux.Post(state.Logs()) + go self.eventMux.Post(statedb.Logs()) return receipt, txGas, err } -func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) { +func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) { var ( receipts types.Receipts handled, unhandled types.Transactions @@ -115,12 +118,12 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state ) for _, tx := range txs { - receipt, txGas, err := self.ApplyTransaction(coinbase, state, block, tx, totalUsedGas, transientProcess) + receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess) if err != nil { switch { case IsNonceErr(err): return nil, nil, nil, nil, err - case IsGasLimitErr(err): + case state.IsGasLimitErr(err): return nil, nil, nil, nil, err default: statelogger.Infoln(err) diff --git a/core/chain_manager.go b/core/chain_manager.go index 286282064..003781791 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -134,14 +134,11 @@ func (self *ChainManager) State() *state.StateDB { func (self *ChainManager) TransState() *state.StateDB { self.tsmu.RLock() defer self.tsmu.RUnlock() - //tmp := self.transState return self.transState } func (self *ChainManager) setTransState(statedb *state.StateDB) { - self.tsmu.Lock() - defer self.tsmu.Unlock() self.transState = statedb } @@ -361,6 +358,9 @@ func (bc *ChainManager) Stop() { } func (self *ChainManager) InsertChain(chain types.Blocks) error { + self.tsmu.Lock() + defer self.tsmu.Unlock() + for _, block := range chain { td, err := self.processor.Process(block) if err != nil { @@ -376,6 +376,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } block.Td = td + var chain, split bool self.mu.Lock() { self.write(block) @@ -383,16 +384,26 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { 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) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td) + split = true } self.setTotalDifficulty(td) self.insert(block) - self.setTransState(state.New(cblock.Root(), self.db)) - self.eventMux.Post(ChainEvent{block, td}) + chain = true } } self.mu.Unlock() + + if chain { + //self.setTransState(state.New(block.Root(), self.db)) + self.eventMux.Post(ChainEvent{block, td}) + } + + if split { + self.setTransState(state.New(block.Root(), self.db)) + self.eventMux.Post(ChainSplitEvent{block}) + } } return nil @@ -402,3 +413,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { func (self *ChainManager) GetAccount(addr []byte) *state.StateObject { return self.State().GetAccount(addr) } + +func (self *ChainManager) TransMut() *sync.RWMutex { + return &self.tsmu +} diff --git a/core/error.go b/core/error.go index 6af48ac2d..e86bacb2d 100644 --- a/core/error.go +++ b/core/error.go @@ -68,23 +68,6 @@ func IsValidationErr(err error) bool { return ok } -type GasLimitErr struct { - Message string - Is, Max *big.Int -} - -func IsGasLimitErr(err error) bool { - _, ok := err.(*GasLimitErr) - - return ok -} -func (err *GasLimitErr) Error() string { - return err.Message -} -func GasLimitError(is, max *big.Int) *GasLimitErr { - return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} -} - type NonceErr struct { Message string Is, Exp uint64 diff --git a/core/events.go b/core/events.go index fe106da49..4cbbc609c 100644 --- a/core/events.go +++ b/core/events.go @@ -13,3 +13,6 @@ type NewBlockEvent struct{ Block *types.Block } // NewMinedBlockEvent is posted when a block has been imported. type NewMinedBlockEvent struct{ Block *types.Block } + +// ChainSplit is posted when a new head is detected +type ChainSplitEvent struct{ Block *types.Block } diff --git a/core/state_transition.go b/core/state_transition.go index 33dd45f02..e82be647d 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -166,7 +166,8 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { defer self.RefundGas() // Increment the nonce for the next transaction - sender.Nonce += 1 + self.state.SetNonce(sender.Address(), sender.Nonce+1) + //sender.Nonce += 1 // Transaction gas if err = self.UseGas(vm.GasTx); err != nil { diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 7a901fcae..894b6c440 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "sync" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethutil" @@ -35,6 +36,7 @@ type TxProcessor interface { // guarantee a non blocking pool we use a queue channel which can be // independently read without needing access to the actual pool. type TxPool struct { + mu sync.RWMutex // Queueing channel for reading and writing incoming // transactions to queueChan chan *types.Transaction @@ -97,7 +99,7 @@ func (self *TxPool) addTx(tx *types.Transaction) { self.txs[string(tx.Hash())] = tx } -func (self *TxPool) Add(tx *types.Transaction) error { +func (self *TxPool) add(tx *types.Transaction) error { if self.txs[string(tx.Hash())] != nil { return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4]) } @@ -128,17 +130,28 @@ func (self *TxPool) Size() int { return len(self.txs) } +func (self *TxPool) Add(tx *types.Transaction) error { + self.mu.Lock() + defer self.mu.Unlock() + return self.add(tx) +} func (self *TxPool) AddTransactions(txs []*types.Transaction) { + self.mu.Lock() + defer self.mu.Unlock() + for _, tx := range txs { - if err := self.Add(tx); err != nil { - txplogger.Infoln(err) + if err := self.add(tx); err != nil { + txplogger.Debugln(err) } else { - txplogger.Infof("tx %x\n", tx.Hash()[0:4]) + txplogger.Debugf("tx %x\n", tx.Hash()[0:4]) } } } func (self *TxPool) GetTransactions() (txs types.Transactions) { + self.mu.RLock() + defer self.mu.RUnlock() + txs = make(types.Transactions, self.Size()) i := 0 for _, tx := range self.txs { @@ -150,30 +163,32 @@ func (self *TxPool) GetTransactions() (txs types.Transactions) { } func (pool *TxPool) RemoveInvalid(query StateQuery) { + pool.mu.Lock() + var removedTxs types.Transactions for _, tx := range pool.txs { sender := query.GetAccount(tx.From()) err := pool.ValidateTransaction(tx) - fmt.Println(err, sender.Nonce, tx.Nonce()) if err != nil || sender.Nonce >= tx.Nonce() { removedTxs = append(removedTxs, tx) } } + pool.mu.Unlock() pool.RemoveSet(removedTxs) } func (self *TxPool) RemoveSet(txs types.Transactions) { + self.mu.Lock() + defer self.mu.Unlock() + for _, tx := range txs { delete(self.txs, string(tx.Hash())) } } -func (pool *TxPool) Flush() []*types.Transaction { - txList := pool.GetTransactions() +func (pool *TxPool) Flush() { pool.txs = make(map[string]*types.Transaction) - - return txList } func (pool *TxPool) Start() { -- cgit v1.2.3 From d8ac267f4128117c3fb9736a40f3dbc327582e32 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 14:01:30 +0100 Subject: dirty tracking for state objects fixed --- core/block_processor.go | 7 ++----- core/chain_manager.go | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index a9795385f..bfd9d4560 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -296,16 +296,13 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren r := new(big.Int) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) - uncleAccount := statedb.GetAccount(uncle.Coinbase) - uncleAccount.AddAmount(r) + statedb.AddBalance(uncle.Coinbase, r) reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) } // Get the account associated with the coinbase - account := statedb.GetAccount(block.Header().Coinbase) - // Reward amount of ether to the coinbase address - account.AddAmount(reward) + statedb.AddBalance(block.Header().Coinbase, reward) return nil } diff --git a/core/chain_manager.go b/core/chain_manager.go index 003781791..dd0dd3cbe 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -397,7 +397,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { if chain { //self.setTransState(state.New(block.Root(), self.db)) - self.eventMux.Post(ChainEvent{block, td}) + //self.eventMux.Post(ChainEvent{block, td}) } if split { -- cgit v1.2.3 From ea9a549bbdc8377bca73f1417f2dc4a18396a382 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 14:19:34 +0100 Subject: Removed exported fields from state object and added proper set/getters --- core/state_transition.go | 8 ++++---- core/transaction_pool.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'core') diff --git a/core/state_transition.go b/core/state_transition.go index e82be647d..36ffa23d9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -138,8 +138,8 @@ func (self *StateTransition) preCheck() (err error) { ) // Make sure this transaction's nonce is correct - if sender.Nonce != msg.Nonce() { - return NonceError(msg.Nonce(), sender.Nonce) + if sender.Nonce() != msg.Nonce() { + return NonceError(msg.Nonce(), sender.Nonce()) } // Pre-pay gas / Buy gas of the coinbase account @@ -166,7 +166,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { defer self.RefundGas() // Increment the nonce for the next transaction - self.state.SetNonce(sender.Address(), sender.Nonce+1) + self.state.SetNonce(sender.Address(), sender.Nonce()+1) //sender.Nonce += 1 // Transaction gas @@ -242,7 +242,7 @@ func MakeContract(msg Message, state *state.StateDB) *state.StateObject { addr := AddressFromMessage(msg) contract := state.GetOrNewStateObject(addr) - contract.InitCode = msg.Data() + contract.SetInitCode(msg.Data()) return contract } diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 894b6c440..050cff3d8 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -169,7 +169,7 @@ func (pool *TxPool) RemoveInvalid(query StateQuery) { for _, tx := range pool.txs { sender := query.GetAccount(tx.From()) err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce >= tx.Nonce() { + if err != nil || sender.Nonce() >= tx.Nonce() { removedTxs = append(removedTxs, tx) } } -- cgit v1.2.3 From 66d5559866f37a79a7b5aeccd03dfe1b4401542b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 16:59:08 +0100 Subject: Fixed chain event issue --- core/chain_manager.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'core') diff --git a/core/chain_manager.go b/core/chain_manager.go index 47cad825d..600dc3db5 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -396,9 +396,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.mu.Unlock() if chain { - fmt.Println("POST START") - self.eventMux.Post(ChainEvent{block, td}) - fmt.Println("POST END") + go self.eventMux.Post(ChainEvent{block, td}) } if split { -- cgit v1.2.3 From cc43ab9a810125239636143a91609389b19b49c7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 18:05:46 +0100 Subject: Minor updates for release --- core/chain_manager.go | 3 ++- core/genesis.go | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 14 deletions(-) (limited to 'core') diff --git a/core/chain_manager.go b/core/chain_manager.go index 600dc3db5..9ef091c3c 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -268,6 +268,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain break } } + fmt.Printf("get hash %x (%d)\n", hash, len(chain)) return } @@ -396,7 +397,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.mu.Unlock() if chain { - go self.eventMux.Post(ChainEvent{block, td}) + self.eventMux.Post(ChainEvent{block, td}) } if split { diff --git a/core/genesis.go b/core/genesis.go index c870ce61e..75b4fc100 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -1,7 +1,10 @@ package core import ( + "encoding/json" + "fmt" "math/big" + "os" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -31,24 +34,39 @@ func GenesisBlock(db ethutil.Database) *types.Block { genesis.SetTransactions(types.Transactions{}) genesis.SetReceipts(types.Receipts{}) + var accounts map[string]struct{ Balance string } + err := json.Unmarshal(genesisData, &accounts) + if err != nil { + fmt.Println("enable to decode genesis json data:", err) + os.Exit(1) + } + statedb := state.New(genesis.Root(), db) - for _, addr := range []string{ - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", - "e4157b34ea9615cfbde6b4fda419828124b70c78", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - } { + for addr, account := range accounts { codedAddr := ethutil.Hex2Bytes(addr) - account := statedb.GetAccount(codedAddr) - account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) - statedb.UpdateStateObject(account) + accountState := statedb.GetAccount(codedAddr) + accountState.SetBalance(ethutil.Big(account.Balance)) + statedb.UpdateStateObject(accountState) } statedb.Sync() genesis.Header().Root = statedb.Root() + fmt.Printf("+++ genesis +++\nRoot: %x\nHash: %x\n", genesis.Header().Root, genesis.Hash()) + return genesis } + +var genesisData = []byte(`{ + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": {"balance": "154162184000000000000000"}, + "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": {"balance": "102774789000000000000000"}, + "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": {"balance": "51387394000000000000000"}, + "b7576e9d314df41ec5506494293afb1bd5d3f65d": {"balance": "69423399000000000000000"} +}`) -- cgit v1.2.3 From 483d96a89d68023360d211ab329400f4b960fe48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:12:01 +0100 Subject: Added eth_logs & fixed issue with manual log filtering * Implemented `eth_logs` * Fixed issue with `filter.Find()` where logs were appended to an incorrect, non-returned slice resulting in no logs found --- core/block_processor.go | 16 ++++++---------- core/filter.go | 5 ++--- 2 files changed, 8 insertions(+), 13 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index bfd9d4560..fd591a29d 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -60,12 +60,12 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM return sm } -func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) { +func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) coinbase.SetGasPool(CalcGasLimit(parent, block)) // Process the transactions on to parent state - receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false) + receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) if err != nil { return nil, err } @@ -100,10 +100,9 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) + go self.eventMux.Post(statedb.Logs()) } - go self.eventMux.Post(statedb.Logs()) - return receipt, txGas, err } @@ -179,7 +178,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big return } - receipts, err := sm.TransitionState(state, parent, block) + receipts, err := sm.TransitionState(state, parent, block, false) if err != nil { return } @@ -316,13 +315,10 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro var ( parent = sm.bc.GetBlock(block.Header().ParentHash) - //state = state.New(parent.Trie().Copy()) - state = state.New(parent.Root(), sm.db) + state = state.New(parent.Root(), sm.db) ) - defer state.Reset() - - sm.TransitionState(state, parent, block) + sm.TransitionState(state, parent, block, true) sm.AccumulateRewards(state, block, parent) return state.Logs(), nil diff --git a/core/filter.go b/core/filter.go index 88f12a67c..cdf7b282d 100644 --- a/core/filter.go +++ b/core/filter.go @@ -111,14 +111,14 @@ func (self *Filter) Find() state.Logs { // current parameters if self.bloomFilter(block) { // Get the logs of the block - logs, err := self.eth.BlockProcessor().GetLogs(block) + unfiltered, err := self.eth.BlockProcessor().GetLogs(block) if err != nil { chainlogger.Warnln("err: filter get logs ", err) break } - logs = append(logs, self.FilterLogs(logs)...) + logs = append(logs, self.FilterLogs(unfiltered)...) } block = self.eth.ChainManager().GetBlock(block.ParentHash()) @@ -146,7 +146,6 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs { Logs: for _, log := range logs { if !includes(self.address, log.Address()) { - //if !bytes.Equal(self.address, log.Address()) { continue } -- cgit v1.2.3 From b2a225a52e45315f3ec90e11707fefa6059d13f5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 15:43:41 +0100 Subject: Properly uninstall filters. Mining issue fixed #closes #365 * Added an additional tx state which is used to get the current nonce * Refresh transient state each time a new canonical block is found * Properly uninstall filters. Fixes a possible crash in RPC --- core/chain_manager.go | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'core') diff --git a/core/chain_manager.go b/core/chain_manager.go index 9ef091c3c..4c7db6e2e 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -85,12 +85,14 @@ type ChainManager struct { lastBlockHash []byte transState *state.StateDB + txState *state.StateDB } func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux} bc.setLastBlock() bc.transState = bc.State().Copy() + bc.txState = bc.State().Copy() return bc } @@ -138,6 +140,19 @@ func (self *ChainManager) TransState() *state.StateDB { return self.transState } +func (self *ChainManager) TxState() *state.StateDB { + self.tsmu.RLock() + defer self.tsmu.RUnlock() + + return self.txState +} + +func (self *ChainManager) setTxState(state *state.StateDB) { + self.tsmu.Lock() + defer self.tsmu.Unlock() + self.txState = state +} + func (self *ChainManager) setTransState(statedb *state.StateDB) { self.transState = statedb } @@ -363,6 +378,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { defer self.tsmu.Unlock() for _, block := range chain { + // Call in to the block processor and check for errors. It's likely that if one block fails + // all others will fail too (unless a known block is returned). td, err := self.processor.Process(block) if err != nil { if IsKnownBlockErr(err) { @@ -377,11 +394,15 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } block.Td = td - var chain, split bool + var canonical, split bool self.mu.Lock() { + // Write block to database. Eventually we'll have to improve on this and throw away blocks that are + // not in the canonical chain. self.write(block) cblock := self.currentBlock + // Compare the TD of the last known block in the canonical chain to make sure it's greater. + // At this point it's possible that a different chain (fork) becomes the new canonical chain. 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) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td) @@ -391,17 +412,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.setTotalDifficulty(td) self.insert(block) - chain = true + canonical = true } } self.mu.Unlock() - if chain { + if canonical { + self.setTransState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainEvent{block, td}) } if split { - self.setTransState(state.New(block.Root(), self.db)) + self.setTxState(state.New(block.Root(), self.db)) self.eventMux.Post(ChainSplitEvent{block}) } } -- cgit v1.2.3 From 0b57bad2de08f382c1b36045db4c66b84d207d3b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Feb 2015 19:25:41 +0100 Subject: removed log --- core/chain_manager.go | 1 - 1 file changed, 1 deletion(-) (limited to 'core') diff --git a/core/chain_manager.go b/core/chain_manager.go index 9ef091c3c..38d1d64b4 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -268,7 +268,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain break } } - fmt.Printf("get hash %x (%d)\n", hash, len(chain)) return } -- cgit v1.2.3 From 260ab739694b554c3cdec8531b98e0334753fbe1 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 25 Feb 2015 20:00:32 +0100 Subject: Validate block header gas limit * Add block header gas limit validation in ValidateBlock function, see eq 39 and 45 in yellow paper. Before it was calculated _for_ the block instead of validated. * Use the block header gas limit when setting the gas pool instead of calculating the value for the block. --- core/block_processor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index fd591a29d..f66d158b2 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -62,7 +62,7 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase) - coinbase.SetGasPool(CalcGasLimit(parent, block)) + coinbase.SetGasPool(block.Header().GasLimit) // Process the transactions on to parent state receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess) @@ -247,6 +247,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd) } + expl := CalcGasLimit(parent, block) + if expl.Cmp(block.Header().GasLimit) != 0 { + return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl) + } + if block.Time() < parent.Time() { return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time) } -- cgit v1.2.3 From e235b57234a68a8a39cfe7691a1825d8c6bb3443 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 18:39:05 +0100 Subject: Fixed consensus issue for refunding * Refund should _always_ go to the origin --- core/block_processor.go | 8 ++++---- core/state_transition.go | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'core') diff --git a/core/block_processor.go b/core/block_processor.go index f66d158b2..7eaeb5be0 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -48,9 +48,8 @@ type BlockProcessor struct { func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor { sm := &BlockProcessor{ - db: db, - mem: make(map[string]*big.Int), - //Pow: ðash.Ethash{}, + db: db, + mem: make(map[string]*big.Int), Pow: ezp.New(), bc: chainManager, eventMux: eventMux, @@ -100,7 +99,8 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) - go self.eventMux.Post(statedb.Logs()) + logs := statedb.Logs() + go self.eventMux.Post(logs) } return receipt, txGas, err diff --git a/core/state_transition.go b/core/state_transition.go index 36ffa23d9..a065c4f6b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -126,7 +126,7 @@ func (self *StateTransition) BuyGas() error { self.AddGas(self.msg.Gas()) self.initialGas.Set(self.msg.Gas()) - sender.SubAmount(MessageGasValue(self.msg)) + sender.SubBalance(MessageGasValue(self.msg)) return nil } @@ -251,13 +251,16 @@ 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) + fmt.Println("REFUND:", remaining) + sender.AddBalance(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())) + addToIt := refund.Mul(refund, self.msg.GasPrice()) + fmt.Println("ADD TO IT", addToIt) + self.state.AddBalance([]byte(addr), addToIt) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) -- cgit v1.2.3 From 3ab05ddd25aa805510ac304c1fd8f7c5c620dff4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Feb 2015 20:26:37 +0100 Subject: Bump --- core/state_transition.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'core') diff --git a/core/state_transition.go b/core/state_transition.go index a065c4f6b..7331fdd4a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -251,16 +251,13 @@ func (self *StateTransition) RefundGas() { coinbase, sender := self.Coinbase(), self.From() // Return remaining gas remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) - fmt.Println("REFUND:", remaining) sender.AddBalance(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) - addToIt := refund.Mul(refund, self.msg.GasPrice()) - fmt.Println("ADD TO IT", addToIt) - self.state.AddBalance([]byte(addr), addToIt) + self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice())) } coinbase.RefundGas(self.gas, self.msg.GasPrice()) -- cgit v1.2.3