// makeCurrent creates a new environment for the current cycle. func (self *worker) makeCurrent(parent *types.Block, header *types.Header) { state := state.New(parent.Root(), self.eth.ChainDb()) work := &Work{ state: state, ancestors: set.New(), family: set.New(), uncles: set.New(), header: header, coinbase: state.GetOrNewStateObject(self.coinbase), createdAt: time.Now(), } // when 08 is processed ancestors contain 07 (quick block) for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) { for _, uncle := range ancestor.Uncles() { work.family.Add(uncle.Hash()) } work.family.Add(ancestor.Hash()) work.ancestors.Add(ancestor.Hash()) } accounts, _ := self.eth.AccountManager().Accounts() // Keep track of transactions which return errors so they can be removed work.remove = set.New() work.tcount = 0 work.ignoredTransactors = set.New() work.lowGasTransactors = set.New() work.ownedAccounts = accountAddressesSet(accounts) if self.current != nil { work.localMinedBlocks = self.current.localMinedBlocks } self.current = work }
func (self *Filter) bloomFilter(block *types.Block) bool { if len(self.address) > 0 { var included bool for _, addr := range self.address { if types.BloomLookup(block.Bloom(), addr) { included = true break } } if !included { return false } } for _, sub := range self.topics { var included bool for _, topic := range sub { if (topic == common.Hash{}) || types.BloomLookup(block.Bloom(), topic) { included = true break } } if !included { return false } } return true }
// SendNewBlock propagates an entire block to a remote peer. func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { propBlockOutPacketsMeter.Mark(1) propBlockOutTrafficMeter.Mark(block.Size().Int64()) p.knownBlocks.Add(block.Hash()) return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) }
func (self *SQLDB) DeleteBlock(block *types.Block) { query := `DELETE FROM blocks WHERE number = ?` _, err := self.db.Exec(query, block.Number().Uint64()) if err != nil { glog.V(logger.Error).Infoln("Error creating SQL tables", err, query) } }
func blockRecovery(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) arg := ctx.Args().First() if len(ctx.Args()) < 1 && len(arg) > 0 { glog.Fatal("recover requires block number or hash") } cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) utils.CheckLegalese(cfg.DataDir) blockDb, err := ethdb.NewLDBDatabase(filepath.Join(cfg.DataDir, "blockchain"), cfg.DatabaseCache) if err != nil { glog.Fatalln("could not open db:", err) } var block *types.Block if arg[0] == '#' { block = core.GetBlockByNumber(blockDb, common.String2Big(arg[1:]).Uint64()) } else { block = core.GetBlockByHash(blockDb, common.HexToHash(arg)) } if block == nil { glog.Fatalln("block not found. Recovery failed") } err = core.WriteHead(blockDb, block) if err != nil { glog.Fatalln("block write err", err) } glog.Infof("Recovery succesful. New HEAD %x\n", block.Hash()) }
func (bc *ChainManager) removeBlock(block *types.Block) { if bc.sqlDB != nil { bc.sqlDB.DeleteBlock(block) } bc.chainDb.Delete(append(blockHashPre, block.Hash().Bytes()...)) }
// enqueue schedules a new future import operation, if the block to be imported // has not yet been seen. func (f *Fetcher) enqueue(peer string, block *types.Block) { hash := block.Hash() // Ensure the peer isn't DOSing us count := f.queues[peer] + 1 if count > blockLimit { glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x], exceeded allowance (%d)", peer, block.NumberU64(), hash.Bytes()[:4], blockLimit) return } // Discard any past or too distant blocks if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist { glog.V(logger.Debug).Infof("Peer %s: discarded block #%d [%x], distance %d", peer, block.NumberU64(), hash.Bytes()[:4], dist) discardMeter.Mark(1) return } // Schedule the block for future importing if _, ok := f.queued[hash]; !ok { op := &inject{ origin: peer, block: block, } f.queues[peer] = count f.queued[hash] = op f.queue.Push(op, -float32(block.NumberU64())) if glog.V(logger.Debug) { glog.Infof("Peer %s: queued block #%d [%x], total %v", peer, block.NumberU64(), hash.Bytes()[:4], f.queue.Size()) } } }
// WriteCanonNumber writes the canonical hash for the given block func WriteCanonNumber(db common.Database, block *types.Block) error { key := append(blockNumPre, block.Number().Bytes()...) err := db.Put(key, block.Hash().Bytes()) if err != nil { return err } return nil }
// CalcTD computes the total difficulty of block. func CalcTD(block, parent *types.Block) *big.Int { if parent == nil { return block.Difficulty() } d := block.Difficulty() d.Add(d, parent.Td) return d }
// GetLogs returns the logs of the given block. This method is using a two step approach // where it tries to get it from the (updated) method which gets them from the receipts or // the depricated way by re-processing the block. func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) { receipts := GetBlockReceipts(sm.chainDb, block.Hash()) // coalesce logs for _, receipt := range receipts { logs = append(logs, receipt.Logs()...) } return logs, nil }
func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) { for i := 0; block != nil && i < length; i++ { uncles = append(uncles, block.Uncles()...) block = self.GetBlock(block.ParentHash()) } return }
// WriteHead force writes the current head func WriteHead(db common.Database, block *types.Block) error { err := WriteCanonNumber(db, block) if err != nil { return err } err = db.Put([]byte("LastBlock"), block.Hash().Bytes()) if err != nil { return err } return nil }
// BroadcastBlock will either propagate a block to a subset of it's peers, or // will only announce it's availability (depending what's requested). func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) { hash := block.Hash() peers := pm.peers.PeersWithoutBlock(hash) // If propagation is requested, send to a subset of the peer if propagate { // Calculate the TD of the block (it's not imported yet, so block.Td is not valid) var td *big.Int if parent := pm.chainman.GetBlock(block.ParentHash()); parent != nil { td = new(big.Int).Add(parent.Td, block.Difficulty()) } else { glog.V(logger.Error).Infof("propagating dangling block #%d [%x]", block.NumberU64(), hash[:4]) return } // Send the block to a subset of our peers transfer := peers[:int(math.Sqrt(float64(len(peers))))] for _, peer := range transfer { peer.SendNewBlock(block, td) } glog.V(logger.Detail).Infof("propagated block %x to %d peers in %v", hash[:4], len(transfer), time.Since(block.ReceivedAt)) } // Otherwise if the block is indeed in out own chain, announce it if pm.chainman.HasBlock(hash) { for _, peer := range peers { peer.SendNewBlockHashes([]common.Hash{hash}) } glog.V(logger.Detail).Infof("announced block %x to %d peers in %v", hash[:4], len(peers), time.Since(block.ReceivedAt)) } }
// CalcGasLimit computes the gas limit of the next block after parent. // The result may be modified by the caller. // This is miner strategy, not consensus protocol. func CalcGasLimit(parent *types.Block) *big.Int { // contrib = (parentGasUsed * 3 / 2) / 1024 contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3)) contrib = contrib.Div(contrib, big.NewInt(2)) contrib = contrib.Div(contrib, params.GasLimitBoundDivisor) // decay = parentGasLimit / 1024 -1 decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor) decay.Sub(decay, big.NewInt(1)) /* strategy: gasLimit of block-to-mine is set based on parent's gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we increase it, otherwise lower it (or leave it unchanged if it's right at that usage) the amount increased/decreased depends on how far away from parentGasLimit * (2/3) parentGasUsed is. */ gl := new(big.Int).Sub(parent.GasLimit(), decay) gl = gl.Add(gl, contrib) gl.Set(common.BigMax(gl, params.MinGasLimit)) // however, if we're now below the target (GenesisGasLimit) we increase the // limit as much as we can (parentGasLimit / 1024 -1) if gl.Cmp(params.GenesisGasLimit) < 0 { gl.Add(parent.GasLimit(), decay) gl.Set(common.BigMin(gl, params.GenesisGasLimit)) } return gl }
// makeChain creates a chain of n blocks starting at but not including // parent. the returned hash chain is ordered head->parent. func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { blocks := core.GenerateChain(parent, testdb, n, func(i int, gen *core.BlockGen) { gen.SetCoinbase(common.Address{seed}) }) hashes := make([]common.Hash, n+1) hashes[len(hashes)-1] = parent.Hash() blockm := make(map[common.Hash]*types.Block, n+1) blockm[parent.Hash()] = parent for i, b := range blocks { hashes[len(hashes)-i-2] = b.Hash() blockm[b.Hash()] = b } return hashes, blockm }
func (self *BlockProcessor) ApplyTransactions(gp GasPool, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) { var ( receipts types.Receipts totalUsedGas = big.NewInt(0) err error cumulativeSum = new(big.Int) header = block.Header() ) for i, tx := range txs { statedb.StartRecord(tx.Hash(), block.Hash(), i) receipt, txGas, err := self.ApplyTransaction(gp, statedb, header, tx, totalUsedGas, transientProcess) if err != nil { return nil, err } if err != nil { glog.V(logger.Core).Infoln("TX err:", err) } receipts = append(receipts, receipt) cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice())) } if block.GasUsed().Cmp(totalUsedGas) != 0 { return nil, ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), totalUsedGas)) } if transientProcess { go self.eventMux.Post(PendingBlockEvent{block, statedb.Logs()}) } return receipts, err }
func (bc *ChainManager) SetHead(head *types.Block) { bc.mu.Lock() defer bc.mu.Unlock() for block := bc.currentBlock; block != nil && block.Hash() != head.Hash(); block = bc.GetBlock(block.ParentHash()) { bc.removeBlock(block) } bc.cache, _ = lru.New(blockCacheLimit) bc.currentBlock = head bc.makeCache() bc.setTotalDifficulty(head.Td) bc.insert(head) bc.setLastState() }
func (self *GasPriceOracle) processBlock(block *types.Block) { i := block.NumberU64() if i > self.lastProcessed { self.lastProcessed = i } lastBase := self.eth.GpoMinGasPrice bpl := self.blocks[i-1] if bpl != nil { lastBase = bpl.baseGasPrice } if lastBase == nil { return } var corr int lp := self.lowestPrice(block) if lp == nil { return } if lastBase.Cmp(lp) < 0 { corr = self.eth.GpobaseStepUp } else { corr = -self.eth.GpobaseStepDown } crand := int64(corr * (900 + rand.Intn(201))) newBase := new(big.Int).Mul(lastBase, big.NewInt(1000000+crand)) newBase.Div(newBase, big.NewInt(1000000)) if newBase.Cmp(self.minBase) < 0 { newBase = self.minBase } bpi := self.blocks[i] if bpi == nil { bpi = &blockPriceInfo{} self.blocks[i] = bpi } bpi.baseGasPrice = newBase self.lastBaseMutex.Lock() self.lastBase = newBase self.lastBaseMutex.Unlock() glog.V(logger.Detail).Infof("Processed block #%v, base price is %v\n", block.NumberU64(), newBase.Int64()) }
func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { var chain []*types.Block for i, difficulty := range d { header := &types.Header{ Coinbase: common.Address{seed}, Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty)), } if i == 0 { header.ParentHash = genesis.Hash() } else { header.ParentHash = chain[i-1].Hash() } block := types.NewBlockWithHeader(header) chain = append(chain, block) } return chain }
// PutBlockReceipts stores the block's transactions associated receipts // and stores them by block hash in a single slice. This is required for // forks and chain reorgs func PutBlockReceipts(db common.Database, block *types.Block, receipts types.Receipts) error { rs := make([]*types.ReceiptForStorage, len(receipts)) for i, receipt := range receipts { rs[i] = (*types.ReceiptForStorage)(receipt) } bytes, err := rlp.EncodeToBytes(rs) if err != nil { return err } hash := block.Hash() err = db.Put(append(blockReceiptsPre, hash[:]...), bytes) if err != nil { return err } return nil }
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { var time *big.Int if parent.Time() == nil { time = big.NewInt(10) } else { time = new(big.Int).Add(parent.Time(), big.NewInt(25)) // block time is fixed at 25 seconds } return &types.Header{ Root: state.Root(), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), Difficulty: CalcDifficulty(time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), GasLimit: CalcGasLimit(parent), GasUsed: new(big.Int), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: time, } }
func (self *SQLDB) InsertBlock(block *types.Block) { tx, err := self.db.Begin() if err != nil { glog.V(logger.Error).Infoln("SQL DB Begin:", err) return } stmtBlock, err := tx.Prepare(`insert or replace into shift_blocks(number, hash) values(?, ?)`) if err != nil { glog.V(logger.Error).Infoln("SQL DB:", err) return } defer stmtBlock.Close() stmtTrans, err := tx.Prepare(`insert or replace into shift_transactions(hash, blocknumber, sender, receiver) values(?, ?, ?, ?)`) if err != nil { glog.V(logger.Error).Infoln("SQL DB:", err) return } defer stmtTrans.Close() // block _, err = stmtBlock.Exec(block.Number().Uint64(), block.Hash().Hex()) if err != nil { glog.V(logger.Error).Infoln("SQL DB:", err) tx.Rollback() return } // transactions for _, trans := range block.Transactions() { sender, err := trans.From() if err != nil { glog.V(logger.Error).Infoln("SQL DB:", err) continue } senderHex := sender.Hex() receiver := trans.To() receiverHex := "" if receiver != nil { receiverHex = receiver.Hex() } _, err = stmtTrans.Exec(trans.Hash().Hex(), block.Number().Uint64(), senderHex, receiverHex) if err != nil { glog.V(logger.Error).Infoln("SQL DB:", err) tx.Rollback() return } } tx.Commit() }
// insert injects a block into the current chain block chain. Note, this function // assumes that the `mu` mutex is held! func (bc *ChainManager) insert(block *types.Block) { err := WriteHead(bc.chainDb, block) if err != nil { glog.Fatal("db write fail:", err) } bc.checkpoint++ if bc.checkpoint > checkpointLimit { err = bc.chainDb.Put([]byte("checkpoint"), block.Hash().Bytes()) if err != nil { glog.Fatal("db write fail:", err) } bc.checkpoint = 0 } bc.currentBlock = block bc.lastBlockHash = block.Hash() }
func dump(ctx *cli.Context) { chain, chainDb := utils.MakeChain(ctx) for _, arg := range ctx.Args() { var block *types.Block if hashish(arg) { block = chain.GetBlock(common.HexToHash(arg)) } else { num, _ := strconv.Atoi(arg) block = chain.GetBlockByNumber(uint64(num)) } if block == nil { fmt.Println("{}") utils.Fatalf("block not found") } else { state := state.New(block.Root(), chainDb) fmt.Printf("%s\n", state.Dump()) } } chainDb.Close() }
func (bc *BlockCache) Push(block *types.Block) { bc.mu.Lock() defer bc.mu.Unlock() if len(bc.hashes) == bc.size { delete(bc.blocks, bc.hashes[0]) // XXX There are a few other options on solving this // 1) use a poller / GC like mechanism to clean up untracked objects // 2) copy as below // re-use the slice and remove the reference to bc.hashes[0] // this will allow the element to be garbage collected. copy(bc.hashes, bc.hashes[1:]) } else { bc.hashes = append(bc.hashes, common.Hash{}) } hash := block.Hash() bc.blocks[hash] = block bc.hashes[len(bc.hashes)-1] = hash }
// returns the lowers possible price with which a tx was or could have been included func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int { gasUsed := big.NewInt(0) receipts := self.eth.BlockProcessor().GetBlockReceipts(block.Hash()) if len(receipts) > 0 { if cgu := receipts[len(receipts)-1].CumulativeGasUsed; cgu != nil { gasUsed = receipts[len(receipts)-1].CumulativeGasUsed } } if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(), big.NewInt(int64(self.eth.GpoFullBlockRatio)))) < 0 { // block is not full, could have posted a tx with MinGasPrice return big.NewInt(0) } txs := block.Transactions() if len(txs) == 0 { return big.NewInt(0) } // block is full, find smallest gasPrice minPrice := txs[0].GasPrice() for i := 1; i < len(txs); i++ { price := txs[i].GasPrice() if price.Cmp(minPrice) < 0 { minPrice = price } } return minPrice }
func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { bc.mu.Lock() defer bc.mu.Unlock() for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.ParentHash()) { bc.removeBlock(block) } // Prepare the genesis block gb.Td = gb.Difficulty() bc.genesisBlock = gb err := WriteBlock(bc.chainDb, bc.genesisBlock) if err != nil { glog.Fatalln("db err:", err) } bc.insert(bc.genesisBlock) bc.currentBlock = bc.genesisBlock bc.makeCache() bc.td = gb.Difficulty() }
// GenerateChain creates a chain of n blocks. The first block's // parent will be the provided parent. db is used to store // intermediate states and should contain the parent's state trie. // // The generator function is called with a new block generator for // every block. Any transactions and uncles added to the generator // become part of the block. If gen is nil, the blocks will be empty // and their coinbase will be the zero address. // // Blocks created by GenerateChain do not contain valid proof of work // values. Inserting them into ChainManager requires use of FakePow or // a similar non-validating proof of work implementation. func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int, *BlockGen)) []*types.Block { statedb := state.New(parent.Root(), db) blocks := make(types.Blocks, n) genblock := func(i int, h *types.Header) *types.Block { b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb} if gen != nil { gen(i, b) } AccumulateRewards(statedb, h, b.uncles) statedb.SyncIntermediate() h.Root = statedb.Root() return types.NewBlock(h, b.txs, b.uncles, b.receipts) } for i := 0; i < n; i++ { header := makeHeader(parent, statedb) block := genblock(i, header) block.Td = CalcTD(block, parent) blocks[i] = block parent = block } return blocks }
// WriteBlock writes the block to the chain (or pending queue) func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status writeStatus, err error) { self.wg.Add(1) defer self.wg.Done() 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 block.Td.Cmp(self.Td()) > 0 { // chain fork if block.ParentHash() != cblock.Hash() { // during split we merge two different chains and create the new canonical chain err := self.merge(cblock, block) if err != nil { return NonStatTy, err } status = SplitStatTy } self.mu.Lock() self.setTotalDifficulty(block.Td) self.insert(block) self.mu.Unlock() status = CanonStatTy } else { status = SideStatTy } err = WriteBlock(self.chainDb, block) if err != nil { glog.Fatalln("db err:", err) } // Delete from future blocks self.futureBlocks.Remove(block.Hash()) return }
// insert spawns a new goroutine to run a block insertion into the chain. If the // block's number is at the same height as the current import phase, if updates // the phase states accordingly. func (f *Fetcher) insert(peer string, block *types.Block) { hash := block.Hash() // Run the import on a new thread glog.V(logger.Debug).Infof("Peer %s: importing block #%d [%x]", peer, block.NumberU64(), hash[:4]) go func() { defer func() { f.done <- hash }() // If the parent's unknown, abort insertion parent := f.getBlock(block.ParentHash()) if parent == nil { return } // Quickly validate the header and propagate the block if it passes switch err := f.validateBlock(block, parent); err { case nil: // All ok, quickly propagate to our peers broadcastTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, true) case core.BlockFutureErr: futureMeter.Mark(1) // Weird future block, don't fail, but neither propagate default: // Something went very wrong, drop the peer glog.V(logger.Debug).Infof("Peer %s: block #%d [%x] verification failed: %v", peer, block.NumberU64(), hash[:4], err) f.dropPeer(peer) return } // Run the actual import and log any issues if _, err := f.insertChain(types.Blocks{block}); err != nil { glog.V(logger.Warn).Infof("Peer %s: block #%d [%x] import failed: %v", peer, block.NumberU64(), hash[:4], err) return } // If import succeeded, broadcast the block announceTimer.UpdateSince(block.ReceivedAt) go f.broadcastBlock(block, false) // Invoke the testing hook if needed if f.importedHook != nil { f.importedHook(block) } }() }