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) } }
// 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 }
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() }
// diff 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. func (self *ChainManager) diff(oldBlock, newBlock *types.Block) (types.Blocks, error) { var ( newChain types.Blocks commonBlock *types.Block oldStart = oldBlock newStart = newBlock ) // 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()) { } } 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 nil, fmt.Errorf("Invalid old chain") } if newBlock == nil { return nil, 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 nil, fmt.Errorf("Invalid old chain") } if newBlock == nil { return nil, fmt.Errorf("Invalid new chain") } } 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]) } return newChain, nil }
// Process block will attempt to process the given block's transactions and applies them // on top of the block's parent state (given it exists) and will return wether it was // successful or not. func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, receipts types.Receipts, err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() if sm.bc.HasBlock(block.Hash()) { return nil, nil, &KnownBlockError{block.Number(), block.Hash()} } if !sm.bc.HasBlock(block.ParentHash()) { return nil, nil, ParentError(block.ParentHash()) } parent := sm.bc.GetBlock(block.ParentHash()) return sm.processWithParent(block, parent) }
// See YP section 4.3.4. "Block Header Validity" // Validates a block. Returns an error if the block is invalid. func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow, uncle bool) error { if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) } if uncle { if block.Time.Cmp(common.MaxBig) == 1 { return BlockTSTooBigErr } } else { if block.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 { return BlockFutureErr } } if block.Time.Cmp(parent.Time()) != 1 { return BlockEqualTSErr } expd := CalcDifficulty(block.Time.Uint64(), parent.Time().Uint64(), parent.Number(), parent.Difficulty()) if expd.Cmp(block.Difficulty) != 0 { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) } var a, b *big.Int a = parent.GasLimit() a = a.Sub(a, block.GasLimit) a.Abs(a) b = parent.GasLimit() b = b.Div(b, params.GasLimitBoundDivisor) if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) { return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) } num := parent.Number() num.Sub(block.Number, num) if num.Cmp(big.NewInt(1)) != 0 { return BlockNumberErr } if checkPow { // Verify the nonce of the block. Return an error if it's not valid if !pow.Verify(types.NewBlockWithHeader(block)) { return ValidationError("Block's nonce is invalid (= %x)", block.Nonce) } } return nil }
// WriteBlock writes a block to the database func WriteBlock(db common.Database, block *types.Block) error { tstart := time.Now() enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) key := append(blockHashPre, block.Hash().Bytes()...) err := db.Put(key, enc) if err != nil { glog.Fatal("db write fail:", err) return err } if glog.V(logger.Debug) { glog.Infof("wrote block #%v %s. Took %v\n", block.Number(), common.PP(block.Hash().Bytes()), time.Since(tstart)) } 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 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 }