// newRPCTransaction returns a transaction that will serialize to the RPC representation. func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) { if txIndex >= 0 && txIndex < len(b.Transactions()) { tx := b.Transactions()[txIndex] from, err := tx.From() if err != nil { return nil, err } return &RPCTransaction{ BlockHash: b.Hash(), BlockNumber: rpc.NewHexNumber(b.Number()), From: from, Gas: rpc.NewHexNumber(tx.Gas()), GasPrice: rpc.NewHexNumber(tx.GasPrice()), Hash: tx.Hash(), Input: fmt.Sprintf("0x%x", tx.Data()), Nonce: rpc.NewHexNumber(tx.Nonce()), To: tx.To(), TransactionIndex: rpc.NewHexNumber(txIndex), Value: rpc.NewHexNumber(tx.Value()), }, nil } return nil, nil }
// reportBlock reports the given block and error using the canonical block // reporting tool. Reporting the block to the service is handled in a separate // goroutine. func reportBlock(block *types.Block, err error) { if glog.V(logger.Error) { glog.Errorf("Bad block #%v (%s)\n", block.Number(), block.Hash().Hex()) glog.Errorf(" %v", err) } go ReportBlock(block, err) }
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { fields := map[string]interface{}{ "number": rpc.NewHexNumber(b.Number()), "hash": b.Hash(), "parentHash": b.ParentHash(), "nonce": b.Header().Nonce, "sha3Uncles": b.UncleHash(), "logsBloom": b.Bloom(), "stateRoot": b.Root(), "miner": b.Coinbase(), "difficulty": rpc.NewHexNumber(b.Difficulty()), "totalDifficulty": rpc.NewHexNumber(s.bc.GetTd(b.Hash())), "extraData": fmt.Sprintf("0x%x", b.Extra()), "size": rpc.NewHexNumber(b.Size().Int64()), "gasLimit": rpc.NewHexNumber(b.GasLimit()), "gasUsed": rpc.NewHexNumber(b.GasUsed()), "timestamp": rpc.NewHexNumber(b.Time()), "transactionsRoot": b.TxHash(), "receiptRoot": b.ReceiptHash(), } if inclTx { formatTx := func(tx *types.Transaction) (interface{}, error) { return tx.Hash(), nil } if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { return newRPCTransaction(b, tx.Hash()) } } txs := b.Transactions() transactions := make([]interface{}, len(txs)) var err error for i, tx := range b.Transactions() { if transactions[i], err = formatTx(tx); err != nil { return nil, err } } fields["transactions"] = transactions } uncles := b.Uncles() uncleHashes := make([]common.Hash, len(uncles)) for i, uncle := range uncles { uncleHashes[i] = uncle.Hash() } fields["uncles"] = uncleHashes return fields, 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(10)) // block time is fixed at 10 seconds } return &types.Header{ Root: state.IntermediateRoot(), 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, } }
// ValidateBlock validates the given block's header and uncles and verifies the // the block header's transaction and uncle roots. // // ValidateBlock does not validate the header's pow. The pow work validated // seperately so we can process them in paralel. // // ValidateBlock also validates and makes sure that any previous state (or present) // state that might or might not be present is checked to make sure that fast // sync has done it's job proper. This prevents the block validator form accepting // false positives where a header is present but the state is not. func (v *BlockValidator) ValidateBlock(block *types.Block) error { if v.bc.HasBlock(block.Hash()) { if _, err := state.New(block.Root(), v.bc.chainDb); err == nil { return &KnownBlockError{block.Number(), block.Hash()} } } parent := v.bc.GetBlock(block.ParentHash()) if parent == nil { return ParentError(block.ParentHash()) } if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil { return ParentError(block.ParentHash()) } header := block.Header() // validate the block header if err := ValidateHeader(v.Pow, header, parent.Header(), false, false); err != nil { return err } // verify the uncles are correctly rewarded if err := v.VerifyUncles(block, parent); err != nil { return err } // Verify UncleHash before running other uncle validations unclesSha := types.CalcUncleHash(block.Uncles()) if unclesSha != header.UncleHash { return fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha) } // 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(block.Transactions()) if txSha != header.TxHash { return fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha) } return nil }
// 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 *BlockChain) reorg(oldBlock, newBlock *types.Block) error { var ( newChain types.Blocks commonBlock *types.Block oldStart = oldBlock newStart = newBlock deletedTxs types.Transactions deletedLogs vm.Logs // collectLogs collects the logs that were generated during the // processing of the block that corresponds with the given hash. // These logs are later announced as deleted. collectLogs = func(h common.Hash) { // Coalesce logs receipts := GetBlockReceipts(self.chainDb, h) for _, receipt := range receipts { deletedLogs = append(deletedLogs, receipt.Logs...) } } ) // 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()...) collectLogs(oldBlock.Hash()) } } 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) deletedTxs = append(deletedTxs, oldBlock.Transactions()...) collectLogs(oldBlock.Hash()) 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") } } 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]) } var addedTxs types.Transactions // 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 if err := WriteTransactions(self.chainDb, block); err != nil { return err } receipts := GetBlockReceipts(self.chainDb, block.Hash()) // write receipts if err := WriteReceipts(self.chainDb, receipts); err != nil { return err } // Write map map bloom filters if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil { return err } addedTxs = append(addedTxs, block.Transactions()...) } // calculate the difference between deleted and added transactions diff := types.TxDifference(deletedTxs, addedTxs) // When transactions get deleted from the database that means the // receipts that were created in the fork must also be deleted for _, tx := range diff { DeleteReceipt(self.chainDb, tx.Hash()) DeleteTransaction(self.chainDb, tx.Hash()) } // Must be posted in a goroutine because of the transaction pool trying // to acquire the chain manager lock if len(diff) > 0 { go self.eventMux.Post(RemovedTransactionEvent{diff}) } if len(deletedLogs) > 0 { go self.eventMux.Post(RemovedLogEvent{deletedLogs}) } return nil }