aboutsummaryrefslogtreecommitdiffstats
path: root/eth/handler_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/handler_test.go')
-rw-r--r--eth/handler_test.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/eth/handler_test.go b/eth/handler_test.go
index 8418c28b2..66ff26809 100644
--- a/eth/handler_test.go
+++ b/eth/handler_test.go
@@ -20,6 +20,7 @@ import (
"math/big"
"math/rand"
"testing"
+ "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -28,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
)
@@ -580,3 +582,75 @@ func testGetReceipt(t *testing.T, protocol int) {
t.Errorf("receipts mismatch: %v", err)
}
}
+
+// Tests that post eth protocol handshake, DAO fork-enabled clients also execute
+// a DAO "challenge" verifying each others' DAO fork headers to ensure they're on
+// compatible chains.
+func TestDAOChallengeNoVsNo(t *testing.T) { testDAOChallenge(t, false, false, false) }
+func TestDAOChallengeNoVsPro(t *testing.T) { testDAOChallenge(t, false, true, false) }
+func TestDAOChallengeProVsNo(t *testing.T) { testDAOChallenge(t, true, false, false) }
+func TestDAOChallengeProVsPro(t *testing.T) { testDAOChallenge(t, true, true, false) }
+func TestDAOChallengeNoVsTimeout(t *testing.T) { testDAOChallenge(t, false, false, true) }
+func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) }
+
+func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) {
+ // Reduce the DAO handshake challenge timeout
+ if timeout {
+ defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout)
+ daoChallengeTimeout = 500 * time.Millisecond
+ }
+ // Create a DAO aware protocol manager
+ var (
+ evmux = new(event.TypeMux)
+ pow = new(core.FakePow)
+ db, _ = ethdb.NewMemDatabase()
+ genesis = core.WriteGenesisBlockForTesting(db)
+ config = &core.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
+ blockchain, _ = core.NewBlockChain(db, config, pow, evmux)
+ )
+ pm, err := NewProtocolManager(config, false, NetworkId, evmux, new(testTxPool), pow, blockchain, db)
+ if err != nil {
+ t.Fatalf("failed to start test protocol manager: %v", err)
+ }
+ pm.Start()
+ defer pm.Stop()
+
+ // Connect a new peer and check that we receive the DAO challenge
+ peer, _ := newTestPeer("peer", eth63, pm, true)
+ defer peer.close()
+
+ challenge := &getBlockHeadersData{
+ Origin: hashOrNumber{Number: config.DAOForkBlock.Uint64()},
+ Amount: 1,
+ Skip: 0,
+ Reverse: false,
+ }
+ if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil {
+ t.Fatalf("challenge mismatch: %v", err)
+ }
+ // Create a block to reply to the challenge if no timeout is simualted
+ if !timeout {
+ blocks, _ := core.GenerateChain(nil, genesis, db, 1, func(i int, block *core.BlockGen) {
+ if remoteForked {
+ block.SetExtra(params.DAOForkBlockExtra)
+ }
+ })
+ if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil {
+ t.Fatalf("failed to answer challenge: %v", err)
+ }
+ time.Sleep(100 * time.Millisecond) // Sleep to avoid the verification racing with the drops
+ } else {
+ // Otherwise wait until the test timeout passes
+ time.Sleep(daoChallengeTimeout + 500*time.Millisecond)
+ }
+ // Verify that depending on fork side, the remote peer is maintained or dropped
+ if localForked == remoteForked && !timeout {
+ if peers := pm.peers.Len(); peers != 1 {
+ t.Fatalf("peer count mismatch: have %d, want %d", peers, 1)
+ }
+ } else {
+ if peers := pm.peers.Len(); peers != 0 {
+ t.Fatalf("peer count mismatch: have %d, want %d", peers, 0)
+ }
+ }
+}