@@ -2,10 +2,13 @@ package bor
22
33import (
44 "context"
5+ "errors"
6+ "math"
57 "math/big"
68 "testing"
79 "time"
810
11+ "github.com/ethereum/go-ethereum/crypto"
912 "github.com/holiman/uint256"
1013 "github.com/stretchr/testify/require"
1114
@@ -732,3 +735,88 @@ func TestCustomBlockTimeBackwardCompatibility(t *testing.T) {
732735 require .True (t , header .ActualTime .IsZero (), "ActualTime should not be set when blockTime is 0" )
733736 })
734737}
738+
739+ func TestVerifySealRejectsOversizedDifficulty (t * testing.T ) {
740+ t .Parallel ()
741+
742+ // real key so ecrecover works
743+ privKey , err := crypto .GenerateKey ()
744+ require .NoError (t , err )
745+
746+ signerAddr := crypto .PubkeyToAddress (privKey .PublicKey )
747+
748+ sp := & fakeSpanner {
749+ vals : []* valset.Validator {
750+ {Address : signerAddr , VotingPower : 1 },
751+ },
752+ }
753+
754+ borCfg := & params.BorConfig {
755+ Sprint : map [string ]uint64 {"0" : 64 },
756+ Period : map [string ]uint64 {"0" : 2 },
757+ }
758+
759+ // devFake=false, we need real signatures for the sake of this test
760+ chain , b := newChainAndBorForTest (t , sp , borCfg , false , common.Address {})
761+
762+ parent := chain .HeaderChain ().GetHeaderByNumber (0 )
763+ require .NotNil (t , parent )
764+
765+ header := & types.Header {
766+ ParentHash : parent .Hash (),
767+ Number : big .NewInt (1 ),
768+ Time : parent .Time + borCfg .Period ["0" ],
769+ }
770+
771+ // Build snapshot so we can compute the expected difficulty
772+ snap , err := b .snapshot (chain .HeaderChain (), header , []* types.Header {parent }, true )
773+ require .NoError (t , err )
774+ require .NotNil (t , snap )
775+
776+ expected := Difficulty (snap .ValidatorSet , signerAddr )
777+
778+ // Craft a huge difficulty whose low 64 bits match the expected
779+ hugeDiff := new (big.Int ).Add (
780+ new (big.Int ).SetUint64 (expected ),
781+ new (big.Int ).Lsh (big .NewInt (1 ), 64 ),
782+ )
783+ header .Difficulty = hugeDiff
784+
785+ // 32 bytes vanity + 65 bytes for the signature
786+ header .Extra = make ([]byte , 32 + 65 )
787+
788+ // Compute the seal hash over the header
789+ sigHash := SealHash (header , borCfg )
790+
791+ // Sign the seal hash
792+ sig , err := crypto .Sign (sigHash .Bytes (), privKey )
793+ require .NoError (t , err )
794+ require .Len (t , sig , 65 )
795+
796+ // Put the signature in the last 65 bytes of Extra
797+ copy (header .Extra [len (header .Extra )- 65 :], sig )
798+
799+ // verify the seal: we expect the difficulty validation to reject it
800+ err = b .verifySeal (chain .HeaderChain (), header , []* types.Header {parent })
801+ if err == nil {
802+ t .Fatalf ("expected verifySeal to reject oversized difficulty, got nil" )
803+ }
804+
805+ var diffErr * WrongDifficultyError
806+ ok := errors .As (err , & diffErr )
807+ if ! ok {
808+ t .Fatalf ("expected WrongDifficultyError, got %T (%v)" , err , err )
809+ }
810+ if diffErr .Number != header .Number .Uint64 () {
811+ t .Fatalf ("unexpected Number in WrongDifficultyError: got %d, want %d" ,
812+ diffErr .Number , header .Number .Uint64 ())
813+ }
814+ if diffErr .Expected != expected {
815+ t .Fatalf ("unexpected Expected in WrongDifficultyError: got %d, want %d" ,
816+ diffErr .Expected , expected )
817+ }
818+ if diffErr .Actual != math .MaxUint64 {
819+ t .Fatalf ("unexpected Actual in WrongDifficultyError: got %d, want %d" ,
820+ diffErr .Actual , uint64 (math .MaxUint64 ))
821+ }
822+ }
0 commit comments