aboutsummaryrefslogtreecommitdiffstats
path: root/eth/protocol_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/protocol_test.go')
-rw-r--r--eth/protocol_test.go300
1 files changed, 169 insertions, 131 deletions
diff --git a/eth/protocol_test.go b/eth/protocol_test.go
index 322aec7b7..ab2aa289f 100644
--- a/eth/protocol_test.go
+++ b/eth/protocol_test.go
@@ -1,35 +1,48 @@
package eth
import (
+ "bytes"
"io"
+ "log"
"math/big"
+ "os"
"testing"
+ "time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p"
)
+var sys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel))
+
type testMsgReadWriter struct {
in chan p2p.Msg
- out chan p2p.Msg
+ out []p2p.Msg
}
func (self *testMsgReadWriter) In(msg p2p.Msg) {
self.in <- msg
}
-func (self *testMsgReadWriter) Out(msg p2p.Msg) {
- self.in <- msg
+func (self *testMsgReadWriter) Out() (msg p2p.Msg, ok bool) {
+ if len(self.out) > 0 {
+ msg = self.out[0]
+ self.out = self.out[1:]
+ ok = true
+ }
+ return
}
func (self *testMsgReadWriter) WriteMsg(msg p2p.Msg) error {
- self.out <- msg
+ self.out = append(self.out, msg)
return nil
}
func (self *testMsgReadWriter) EncodeMsg(code uint64, data ...interface{}) error {
- return self.WriteMsg(p2p.NewMsg(code, data))
+ return self.WriteMsg(p2p.NewMsg(code, data...))
}
func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) {
@@ -40,145 +53,83 @@ func (self *testMsgReadWriter) ReadMsg() (p2p.Msg, error) {
return msg, nil
}
-func errorCheck(t *testing.T, expCode int, err error) {
- perr, ok := err.(*protocolError)
- if ok && perr != nil {
- if code := perr.Code; code != expCode {
- ok = false
- }
- }
- if !ok {
- t.Errorf("expected error code %v, got %v", ErrNoStatusMsg, err)
- }
-}
-
-type TestBackend struct {
+type testTxPool struct {
getTransactions func() []*types.Transaction
addTransactions func(txs []*types.Transaction)
- getBlockHashes func(hash []byte, amount uint32) (hashes [][]byte)
- addBlockHashes func(next func() ([]byte, bool), peerId string)
- getBlock func(hash []byte) *types.Block
- addBlock func(block *types.Block, peerId string) (err error)
- addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, invalidBlock func(error)) (best bool)
- removePeer func(peerId string)
- status func() (td *big.Int, currentBlock []byte, genesisBlock []byte)
}
-func (self *TestBackend) GetTransactions() (txs []*types.Transaction) {
- if self.getTransactions != nil {
- txs = self.getTransactions()
- }
- return
+type testChainManager struct {
+ getBlockHashes func(hash []byte, amount uint64) (hashes [][]byte)
+ getBlock func(hash []byte) *types.Block
+ status func() (td *big.Int, currentBlock []byte, genesisBlock []byte)
}
-func (self *TestBackend) AddTransactions(txs []*types.Transaction) {
+type testBlockPool struct {
+ addBlockHashes func(next func() ([]byte, bool), peerId string)
+ addBlock func(block *types.Block, peerId string) (err error)
+ addPeer func(td *big.Int, currentBlock []byte, peerId string, requestHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(int, string, ...interface{})) (best bool)
+ removePeer func(peerId string)
+}
+
+// func (self *testTxPool) GetTransactions() (txs []*types.Transaction) {
+// if self.getTransactions != nil {
+// txs = self.getTransactions()
+// }
+// return
+// }
+
+func (self *testTxPool) AddTransactions(txs []*types.Transaction) {
if self.addTransactions != nil {
self.addTransactions(txs)
}
}
-func (self *TestBackend) GetBlockHashes(hash []byte, amount uint32) (hashes [][]byte) {
+func (self *testChainManager) GetBlockHashesFromHash(hash []byte, amount uint64) (hashes [][]byte) {
if self.getBlockHashes != nil {
hashes = self.getBlockHashes(hash, amount)
}
return
}
-<<<<<<< HEAD
-<<<<<<< HEAD
-func (self *TestBackend) AddBlockHashes(next func() ([]byte, bool), peerId string) {
- if self.addBlockHashes != nil {
- self.addBlockHashes(next, peerId)
- }
-}
-
-=======
-func (self *TestBackend) AddHash(hash []byte, peer *p2p.Peer) (more bool) {
- if self.addHash != nil {
- more = self.addHash(hash, peer)
-=======
-func (self *TestBackend) AddBlockHashes(next func() ([]byte, bool), peerId string) {
- if self.addBlockHashes != nil {
- self.addBlockHashes(next, peerId)
->>>>>>> eth protocol changes
+func (self *testChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
+ if self.status != nil {
+ td, currentBlock, genesisBlock = self.status()
}
+ return
}
-<<<<<<< HEAD
->>>>>>> initial commit for eth-p2p integration
-=======
->>>>>>> eth protocol changes
-func (self *TestBackend) GetBlock(hash []byte) (block *types.Block) {
+func (self *testChainManager) GetBlock(hash []byte) (block *types.Block) {
if self.getBlock != nil {
block = self.getBlock(hash)
}
return
}
-<<<<<<< HEAD
-<<<<<<< HEAD
-func (self *TestBackend) AddBlock(block *types.Block, peerId string) (err error) {
- if self.addBlock != nil {
- err = self.addBlock(block, peerId)
-=======
-func (self *TestBackend) AddBlock(td *big.Int, block *types.Block, peer *p2p.Peer) (fetchHashes bool, err error) {
- if self.addBlock != nil {
- fetchHashes, err = self.addBlock(td, block, peer)
->>>>>>> initial commit for eth-p2p integration
-=======
-func (self *TestBackend) AddBlock(block *types.Block, peerId string) (err error) {
+func (self *testBlockPool) AddBlockHashes(next func() ([]byte, bool), peerId string) {
+ if self.addBlockHashes != nil {
+ self.addBlockHashes(next, peerId)
+ }
+}
+
+func (self *testBlockPool) AddBlock(block *types.Block, peerId string) {
if self.addBlock != nil {
- err = self.addBlock(block, peerId)
->>>>>>> eth protocol changes
+ self.addBlock(block, peerId)
}
- return
}
-<<<<<<< HEAD
-<<<<<<< HEAD
-func (self *TestBackend) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, invalidBlock func(error)) (best bool) {
- if self.addPeer != nil {
- best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, invalidBlock)
-=======
-func (self *TestBackend) AddPeer(td *big.Int, currentBlock []byte, peer *p2p.Peer) (fetchHashes bool) {
+func (self *testBlockPool) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, peerError func(int, string, ...interface{})) (best bool) {
if self.addPeer != nil {
- fetchHashes = self.addPeer(td, currentBlock, peer)
->>>>>>> initial commit for eth-p2p integration
-=======
-func (self *TestBackend) AddPeer(td *big.Int, currentBlock []byte, peerId string, requestBlockHashes func([]byte) error, requestBlocks func([][]byte) error, invalidBlock func(error)) (best bool) {
- if self.addPeer != nil {
- best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, invalidBlock)
->>>>>>> eth protocol changes
+ best = self.addPeer(td, currentBlock, peerId, requestBlockHashes, requestBlocks, peerError)
}
return
}
-<<<<<<< HEAD
-<<<<<<< HEAD
-=======
->>>>>>> eth protocol changes
-func (self *TestBackend) RemovePeer(peerId string) {
+func (self *testBlockPool) RemovePeer(peerId string) {
if self.removePeer != nil {
self.removePeer(peerId)
}
}
-<<<<<<< HEAD
-=======
->>>>>>> initial commit for eth-p2p integration
-=======
->>>>>>> eth protocol changes
-func (self *TestBackend) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
- if self.status != nil {
- td, currentBlock, genesisBlock = self.status()
- }
- return
-}
-
-<<<<<<< HEAD
-<<<<<<< HEAD
-=======
->>>>>>> eth protocol changes
// TODO: refactor this into p2p/client_identity
type peerId struct {
pubkey []byte
@@ -201,32 +152,119 @@ func testPeer() *p2p.Peer {
return p2p.NewPeer(&peerId{}, []p2p.Cap{})
}
-func TestErrNoStatusMsg(t *testing.T) {
-<<<<<<< HEAD
-=======
-func TestEth(t *testing.T) {
->>>>>>> initial commit for eth-p2p integration
-=======
->>>>>>> eth protocol changes
- quit := make(chan bool)
- rw := &testMsgReadWriter{make(chan p2p.Msg, 10), make(chan p2p.Msg, 10)}
- testBackend := &TestBackend{}
- var err error
- go func() {
-<<<<<<< HEAD
-<<<<<<< HEAD
- err = runEthProtocol(testBackend, testPeer(), rw)
-=======
- err = runEthProtocol(testBackend, nil, rw)
->>>>>>> initial commit for eth-p2p integration
-=======
- err = runEthProtocol(testBackend, testPeer(), rw)
->>>>>>> eth protocol changes
- close(quit)
- }()
+type ethProtocolTester struct {
+ quit chan error
+ rw *testMsgReadWriter // p2p.MsgReadWriter
+ txPool *testTxPool // txPool
+ chainManager *testChainManager // chainManager
+ blockPool *testBlockPool // blockPool
+ t *testing.T
+}
+
+func newEth(t *testing.T) *ethProtocolTester {
+ return &ethProtocolTester{
+ quit: make(chan error),
+ rw: &testMsgReadWriter{in: make(chan p2p.Msg, 10)},
+ txPool: &testTxPool{},
+ chainManager: &testChainManager{},
+ blockPool: &testBlockPool{},
+ t: t,
+ }
+}
+
+func (self *ethProtocolTester) reset() {
+ self.rw = &testMsgReadWriter{in: make(chan p2p.Msg, 10)}
+ self.quit = make(chan error)
+}
+
+func (self *ethProtocolTester) checkError(expCode int, delay time.Duration) (err error) {
+ var timer = time.After(delay)
+ select {
+ case err = <-self.quit:
+ case <-timer:
+ self.t.Errorf("no error after %v, expected %v", delay, expCode)
+ return
+ }
+ perr, ok := err.(*protocolError)
+ if ok && perr != nil {
+ if code := perr.Code; code != expCode {
+ self.t.Errorf("expected protocol error (code %v), got %v (%v)", expCode, code, err)
+ }
+ } else {
+ self.t.Errorf("expected protocol error (code %v), got %v", expCode, err)
+ }
+ return
+}
+
+func (self *ethProtocolTester) In(msg p2p.Msg) {
+ self.rw.In(msg)
+}
+
+func (self *ethProtocolTester) Out() (p2p.Msg, bool) {
+ return self.rw.Out()
+}
+
+func (self *ethProtocolTester) checkMsg(i int, code uint64, val interface{}) (msg p2p.Msg) {
+ if i >= len(self.rw.out) {
+ self.t.Errorf("expected at least %v msgs, got %v", i, len(self.rw.out))
+ return
+ }
+ msg = self.rw.out[i]
+ if msg.Code != code {
+ self.t.Errorf("expected msg code %v, got %v", code, msg.Code)
+ }
+ if val != nil {
+ if err := msg.Decode(val); err != nil {
+ self.t.Errorf("rlp encoding error: %v", err)
+ }
+ }
+ return
+}
+
+func (self *ethProtocolTester) run() {
+ err := runEthProtocol(self.txPool, self.chainManager, self.blockPool, testPeer(), self.rw)
+ self.quit <- err
+}
+
+func TestStatusMsgErrors(t *testing.T) {
+ logInit()
+ eth := newEth(t)
+ td := ethutil.Big1
+ currentBlock := []byte{1}
+ genesis := []byte{2}
+ eth.chainManager.status = func() (*big.Int, []byte, []byte) { return td, currentBlock, genesis }
+ go eth.run()
statusMsg := p2p.NewMsg(4)
- rw.In(statusMsg)
- <-quit
- errorCheck(t, ErrNoStatusMsg, err)
- // read(t, remote, []byte("hello, world"), nil)
+ eth.In(statusMsg)
+ delay := 1 * time.Second
+ eth.checkError(ErrNoStatusMsg, delay)
+ var status statusMsgData
+ eth.checkMsg(0, StatusMsg, &status) // first outgoing msg should be StatusMsg
+ if status.TD.Cmp(td) != 0 ||
+ status.ProtocolVersion != ProtocolVersion ||
+ status.NetworkId != NetworkId ||
+ status.TD.Cmp(td) != 0 ||
+ bytes.Compare(status.CurrentBlock, currentBlock) != 0 ||
+ bytes.Compare(status.GenesisBlock, genesis) != 0 {
+ t.Errorf("incorrect outgoing status")
+ }
+
+ eth.reset()
+ go eth.run()
+ statusMsg = p2p.NewMsg(0, uint32(48), uint32(0), td, currentBlock, genesis)
+ eth.In(statusMsg)
+ eth.checkError(ErrProtocolVersionMismatch, delay)
+
+ eth.reset()
+ go eth.run()
+ statusMsg = p2p.NewMsg(0, uint32(49), uint32(1), td, currentBlock, genesis)
+ eth.In(statusMsg)
+ eth.checkError(ErrNetworkIdMismatch, delay)
+
+ eth.reset()
+ go eth.run()
+ statusMsg = p2p.NewMsg(0, uint32(49), uint32(0), td, currentBlock, []byte{3})
+ eth.In(statusMsg)
+ eth.checkError(ErrGenesisBlockMismatch, delay)
+
}