@@ -20,6 +20,7 @@ import (
20
20
"math/big"
21
21
"math/rand"
22
22
"testing"
23
+ "time"
23
24
24
25
"github.com/ethereum/go-ethereum/common"
25
26
"github.com/ethereum/go-ethereum/core"
@@ -28,6 +29,7 @@ import (
28
29
"github.com/ethereum/go-ethereum/crypto"
29
30
"github.com/ethereum/go-ethereum/eth/downloader"
30
31
"github.com/ethereum/go-ethereum/ethdb"
32
+ "github.com/ethereum/go-ethereum/event"
31
33
"github.com/ethereum/go-ethereum/p2p"
32
34
"github.com/ethereum/go-ethereum/params"
33
35
)
@@ -580,3 +582,74 @@ func testGetReceipt(t *testing.T, protocol int) {
580
582
t .Errorf ("receipts mismatch: %v" , err )
581
583
}
582
584
}
585
+
586
+ // Tests that post eth protocol handshake, DAO fork-enabled clients also execute
587
+ // a DAO "challenge" verifying each others' DAO fork headers to ensure they're on
588
+ // compatible chains.
589
+ func TestDAOChallengeNoVsNo (t * testing.T ) { testDAOChallenge (t , false , false , false ) }
590
+ func TestDAOChallengeNoVsPro (t * testing.T ) { testDAOChallenge (t , false , true , false ) }
591
+ func TestDAOChallengeProVsNo (t * testing.T ) { testDAOChallenge (t , true , false , false ) }
592
+ func TestDAOChallengeProVsPro (t * testing.T ) { testDAOChallenge (t , true , true , false ) }
593
+ func TestDAOChallengeNoVsTimeout (t * testing.T ) { testDAOChallenge (t , false , false , true ) }
594
+ func TestDAOChallengeProVsTimeout (t * testing.T ) { testDAOChallenge (t , true , true , true ) }
595
+
596
+ func testDAOChallenge (t * testing.T , localForked , remoteForked bool , timeout bool ) {
597
+ // Reduce the DAO handshake challenge timeout
598
+ if timeout {
599
+ defer func (old time.Duration ) { daoChallengeTimeout = old }(daoChallengeTimeout )
600
+ daoChallengeTimeout = 500 * time .Millisecond
601
+ }
602
+ // Create a DAO aware protocol manager
603
+ var (
604
+ evmux = new (event.TypeMux )
605
+ pow = new (core.FakePow )
606
+ db , _ = ethdb .NewMemDatabase ()
607
+ genesis = core .WriteGenesisBlockForTesting (db )
608
+ config = & core.ChainConfig {DAOForkBlock : big .NewInt (1 ), DAOForkSupport : localForked }
609
+ blockchain , _ = core .NewBlockChain (db , config , pow , evmux )
610
+ )
611
+ pm , err := NewProtocolManager (config , false , NetworkId , evmux , new (testTxPool ), pow , blockchain , db )
612
+ if err != nil {
613
+ t .Fatalf ("failed to start test protocol manager: %v" , err )
614
+ }
615
+ pm .Start ()
616
+ defer pm .Stop ()
617
+
618
+ // Connect a new peer and check that we receive the DAO challenge
619
+ peer , _ := newTestPeer ("peer" , eth63 , pm , true )
620
+ defer peer .close ()
621
+
622
+ challenge := & getBlockHeadersData {
623
+ Origin : hashOrNumber {Number : config .DAOForkBlock .Uint64 ()},
624
+ Amount : 1 ,
625
+ Skip : 0 ,
626
+ Reverse : false ,
627
+ }
628
+ if err := p2p .ExpectMsg (peer .app , GetBlockHeadersMsg , challenge ); err != nil {
629
+ t .Fatalf ("challenge mismatch: %v" , err )
630
+ }
631
+ // Create a block to reply to the challenge if no timeout is simualted
632
+ if ! timeout {
633
+ blocks , _ := core .GenerateChain (genesis , db , 1 , func (i int , block * core.BlockGen ) {
634
+ if remoteForked {
635
+ block .SetExtra (params .DAOForkBlockExtra )
636
+ }
637
+ })
638
+ if err := p2p .Send (peer .app , BlockHeadersMsg , []* types.Header {blocks [0 ].Header ()}); err != nil {
639
+ t .Fatalf ("failed to answer challenge: %v" , err )
640
+ }
641
+ } else {
642
+ // Otherwise wait until the test timeout passes
643
+ time .Sleep (daoChallengeTimeout + 500 * time .Millisecond )
644
+ }
645
+ // Verify that depending on fork side, the remote peer is maintained or dropped
646
+ if localForked == remoteForked && ! timeout {
647
+ if peers := pm .peers .Len (); peers != 1 {
648
+ t .Fatalf ("peer count mismatch: have %d, want %d" , peers , 1 )
649
+ }
650
+ } else {
651
+ if peers := pm .peers .Len (); peers != 0 {
652
+ t .Fatalf ("peer count mismatch: have %d, want %d" , peers , 0 )
653
+ }
654
+ }
655
+ }
0 commit comments