@@ -20,6 +20,7 @@ import (
2020 "bytes"
2121 "encoding/binary"
2222 "math/big"
23+ "sort"
2324
2425 "github.com/ethereum/go-ethereum/common"
2526 "github.com/ethereum/go-ethereum/core/types"
@@ -702,6 +703,102 @@ func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
702703 DeleteTd (db , hash , number )
703704}
704705
706+ const badBlockToKeep = 10
707+
708+ type badBlock struct {
709+ Header * types.Header
710+ Body * types.Body
711+ }
712+
713+ // badBlockList implements the sort interface to allow sorting a list of
714+ // bad blocks by their number in the reverse order.
715+ type badBlockList []* badBlock
716+
717+ func (s badBlockList ) Len () int { return len (s ) }
718+ func (s badBlockList ) Less (i , j int ) bool {
719+ return s [i ].Header .Number .Uint64 () < s [j ].Header .Number .Uint64 ()
720+ }
721+ func (s badBlockList ) Swap (i , j int ) { s [i ], s [j ] = s [j ], s [i ] }
722+
723+ // ReadBadBlock retrieves the bad block with the corresponding block hash.
724+ func ReadBadBlock (db ethdb.Reader , hash common.Hash ) * types.Block {
725+ blob , err := db .Get (badBlockKey )
726+ if err != nil {
727+ return nil
728+ }
729+ var badBlocks badBlockList
730+ if err := rlp .DecodeBytes (blob , & badBlocks ); err != nil {
731+ return nil
732+ }
733+ for _ , bad := range badBlocks {
734+ if bad .Header .Hash () == hash {
735+ return types .NewBlockWithHeader (bad .Header ).WithBody (bad .Body .Transactions , bad .Body .Uncles )
736+ }
737+ }
738+ return nil
739+ }
740+
741+ // ReadAllBadBlocks retrieves all the bad blocks in the database.
742+ // All returned blocks are sorted in reverse order by number.
743+ func ReadAllBadBlocks (db ethdb.Reader ) []* types.Block {
744+ blob , err := db .Get (badBlockKey )
745+ if err != nil {
746+ return nil
747+ }
748+ var badBlocks badBlockList
749+ if err := rlp .DecodeBytes (blob , & badBlocks ); err != nil {
750+ return nil
751+ }
752+ var blocks []* types.Block
753+ for _ , bad := range badBlocks {
754+ blocks = append (blocks , types .NewBlockWithHeader (bad .Header ).WithBody (bad .Body .Transactions , bad .Body .Uncles ))
755+ }
756+ return blocks
757+ }
758+
759+ // WriteBadBlock serializes the bad block into the database. If the cumulated
760+ // bad blocks exceeds the limitation, the oldest will be dropped.
761+ func WriteBadBlock (db ethdb.KeyValueStore , block * types.Block ) {
762+ blob , err := db .Get (badBlockKey )
763+ if err != nil {
764+ log .Warn ("Failed to load old bad blocks" , "error" , err )
765+ }
766+ var badBlocks badBlockList
767+ if len (blob ) > 0 {
768+ if err := rlp .DecodeBytes (blob , & badBlocks ); err != nil {
769+ log .Crit ("Failed to decode old bad blocks" , "error" , err )
770+ }
771+ }
772+ for _ , b := range badBlocks {
773+ if b .Header .Number .Uint64 () == block .NumberU64 () && b .Header .Hash () == block .Hash () {
774+ log .Info ("Skip duplicated bad block" , "number" , block .NumberU64 (), "hash" , block .Hash ())
775+ return
776+ }
777+ }
778+ badBlocks = append (badBlocks , & badBlock {
779+ Header : block .Header (),
780+ Body : block .Body (),
781+ })
782+ sort .Sort (sort .Reverse (badBlocks ))
783+ if len (badBlocks ) > badBlockToKeep {
784+ badBlocks = badBlocks [:badBlockToKeep ]
785+ }
786+ data , err := rlp .EncodeToBytes (badBlocks )
787+ if err != nil {
788+ log .Crit ("Failed to encode bad blocks" , "err" , err )
789+ }
790+ if err := db .Put (badBlockKey , data ); err != nil {
791+ log .Crit ("Failed to write bad blocks" , "err" , err )
792+ }
793+ }
794+
795+ // DeleteBadBlocks deletes all the bad blocks from the database
796+ func DeleteBadBlocks (db ethdb.KeyValueWriter ) {
797+ if err := db .Delete (badBlockKey ); err != nil {
798+ log .Crit ("Failed to delete bad blocks" , "err" , err )
799+ }
800+ }
801+
705802// FindCommonAncestor returns the last common ancestor of two block headers
706803func FindCommonAncestor (db ethdb.Reader , a , b * types.Header ) * types.Header {
707804 for bn := b .Number .Uint64 (); a .Number .Uint64 () > bn ; {
0 commit comments