// Creates a new QML Block from a chain block func NewBlock(block *types.Block) *Block { if block == nil { return &Block{} } ptxs := make([]*Transaction, len(block.Transactions())) /* for i, tx := range block.Transactions() { ptxs[i] = NewTx(tx) } */ txlist := common.NewList(ptxs) puncles := make([]*Block, len(block.Uncles())) /* for i, uncle := range block.Uncles() { puncles[i] = NewBlock(types.NewBlockWithHeader(uncle)) } */ ulist := common.NewList(puncles) return &Block{ ref: block, Size: block.Size().String(), Number: int(block.NumberU64()), GasUsed: block.GasUsed().String(), GasLimit: block.GasLimit().String(), Hash: block.Hash().Hex(), Transactions: txlist, Uncles: ulist, Time: block.Time(), Coinbase: block.Coinbase().Hex(), PrevHash: block.ParentHash().Hex(), Bloom: common.ToHex(block.Bloom().Bytes()), Raw: block.String(), } }
// 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 (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() }
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) { gp := statedb.GetOrNewStateObject(block.Coinbase()) gp.SetGasLimit(block.GasLimit()) // Process the transactions on to parent state receipts, err = sm.ApplyTransactions(gp, statedb, block, block.Transactions(), transientProcess) if err != nil { return nil, err } return receipts, nil }
// PutTransactions stores the transactions in the given database func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) { batch := new(leveldb.Batch) _, batchWrite := db.(*ethdb.LDBDatabase) for i, tx := range block.Transactions() { rlpEnc, err := rlp.EncodeToBytes(tx) if err != nil { glog.V(logger.Debug).Infoln("Failed encoding tx", err) return } if batchWrite { batch.Put(tx.Hash().Bytes(), rlpEnc) } else { db.Put(tx.Hash().Bytes(), rlpEnc) } var txExtra struct { BlockHash common.Hash BlockIndex uint64 Index uint64 } txExtra.BlockHash = block.Hash() txExtra.BlockIndex = block.NumberU64() txExtra.Index = uint64(i) rlpMeta, err := rlp.EncodeToBytes(txExtra) if err != nil { glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err) return } if batchWrite { batch.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) } else { db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) } } if db, ok := db.(*ethdb.LDBDatabase); ok { if err := db.LDB().Write(batch, nil); err != nil { glog.V(logger.Error).Infoln("db write err:", err) } } }
func NewBlockRes(block *types.Block, fullTx bool) *BlockRes { if block == nil { return nil } res := new(BlockRes) res.fullTx = fullTx res.BlockNumber = newHexNum(block.Number()) res.BlockHash = newHexData(block.Hash()) res.ParentHash = newHexData(block.ParentHash()) res.Nonce = newHexData(block.Nonce()) res.Sha3Uncles = newHexData(block.UncleHash()) res.LogsBloom = newHexData(block.Bloom()) res.TransactionRoot = newHexData(block.TxHash()) res.StateRoot = newHexData(block.Root()) res.Miner = newHexData(block.Coinbase()) res.Difficulty = newHexNum(block.Difficulty()) res.TotalDifficulty = newHexNum(block.Td) res.Size = newHexNum(block.Size().Int64()) res.ExtraData = newHexData(block.Extra()) res.GasLimit = newHexNum(block.GasLimit()) res.GasUsed = newHexNum(block.GasUsed()) res.UnixTimestamp = newHexNum(block.Time()) txs := block.Transactions() res.Transactions = make([]*TransactionRes, len(txs)) for i, tx := range txs { res.Transactions[i] = NewTransactionRes(tx) res.Transactions[i].BlockHash = res.BlockHash res.Transactions[i].BlockNumber = res.BlockNumber res.Transactions[i].TxIndex = newHexNum(i) } uncles := block.Uncles() res.Uncles = make([]*UncleRes, len(uncles)) for i, uncle := range uncles { res.Uncles[i] = NewUncleRes(uncle) } return res }
// reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // to be part of the new canonical chain and accumulates potential missing transactions and post an // event about them func (self *ChainManager) reorg(oldBlock, newBlock *types.Block) error { self.mu.Lock() defer self.mu.Unlock() var ( newChain types.Blocks commonBlock *types.Block oldStart = oldBlock newStart = newBlock deletedTxs types.Transactions addedTxs types.Transactions ) // first reduce whoever is higher bound if oldBlock.NumberU64() > newBlock.NumberU64() { // reduce old chain for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) { deletedTxs = append(deletedTxs, oldBlock.Transactions()...) } } else { // reduce new chain and append new chain blocks for inserting later on for newBlock = newBlock; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) { newChain = append(newChain, newBlock) } } if oldBlock == nil { return fmt.Errorf("Invalid old chain") } if newBlock == nil { return fmt.Errorf("Invalid new chain") } numSplit := newBlock.Number() for { if oldBlock.Hash() == newBlock.Hash() { commonBlock = oldBlock break } newChain = append(newChain, newBlock) oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) if oldBlock == nil { return fmt.Errorf("Invalid old chain") } if newBlock == nil { return fmt.Errorf("Invalid new chain") } deletedTxs = append(deletedTxs, oldBlock.Transactions()...) } if glog.V(logger.Debug) { commonHash := commonBlock.Hash() glog.Infof("Chain split detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4]) } // insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly for _, block := range newChain { // insert the block in the canonical way, re-writing history self.insert(block) // write canonical receipts and transactions PutTransactions(self.chainDb, block, block.Transactions()) PutReceipts(self.chainDb, GetBlockReceipts(self.chainDb, block.Hash())) addedTxs = append(addedTxs, block.Transactions()...) } var diff types.Transactions diff.Difference(deletedTxs, addedTxs) self.eventMux.Post(RemovedTransactionEvent{diff}) return nil }
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, receipts types.Receipts, err error) { // Create a new state based on the parent's root (e.g., create copy) state := state.New(parent.Root(), sm.chainDb) header := block.Header() uncles := block.Uncles() txs := block.Transactions() // Block validation if err = ValidateHeader(sm.Pow, header, parent, false, false); err != nil { return } // There can be at most two uncles if len(uncles) > 2 { return nil, nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(uncles)) } receipts, err = sm.TransitionState(state, parent, block, false) if err != nil { return } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. rbloom := types.CreateBloom(receipts) if rbloom != header.Bloom { err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return } // The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]])) // can be used by light clients to make sure they've received the correct Txs txSha := types.DeriveSha(txs) if txSha != header.TxHash { err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha) return } // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) receiptSha := types.DeriveSha(receipts) if receiptSha != header.ReceiptHash { err = fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha) return } // Verify UncleHash before running other uncle validations unclesSha := types.CalcUncleHash(uncles) if unclesSha != header.UncleHash { err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha) return } // Verify uncles if err = sm.VerifyUncles(state, block, parent); err != nil { return } // Accumulate static rewards; block reward, uncle's and uncle inclusion. AccumulateRewards(state, header, uncles) // Commit state objects/accounts to a temporary trie (does not save) // used to calculate the state root. state.SyncObjects() if header.Root != state.Root() { err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root()) return } // Sync the current block's state to the database state.Sync() return state.Logs(), receipts, nil }