aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2015-04-01 19:55:42 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2015-04-01 19:55:42 +0800
commit4a4da9a24e39c45db6535ca5ad51dc1385f2491b (patch)
treec5b31c90566931e6a1a859f98da549181805f62c
parent936ddf2ad1b7306dfe7f5ae9ca122a4968dd98e8 (diff)
parentf56fc9cd9d13e88ee1a244ea590e249e324b8b84 (diff)
downloaddexon-4a4da9a24e39c45db6535ca5ad51dc1385f2491b.tar.gz
dexon-4a4da9a24e39c45db6535ca5ad51dc1385f2491b.tar.zst
dexon-4a4da9a24e39c45db6535ca5ad51dc1385f2491b.zip
Merge pull request #588 from ethersphere/frontier/SEC-29
Frontier/sec 29
-rw-r--r--core/types/block.go17
-rw-r--r--eth/protocol.go11
-rw-r--r--eth/protocol_test.go214
3 files changed, 225 insertions, 17 deletions
diff --git a/core/types/block.go b/core/types/block.go
index 5cdde4462..d5cd8a21e 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -148,6 +148,23 @@ func NewBlockWithHeader(header *Header) *Block {
return &Block{header: header}
}
+func (self *Block) ValidateFields() error {
+ if self.header == nil {
+ return fmt.Errorf("header is nil")
+ }
+ for i, transaction := range self.transactions {
+ if transaction == nil {
+ return fmt.Errorf("transaction %d is nil", i)
+ }
+ }
+ for i, uncle := range self.uncles {
+ if uncle == nil {
+ return fmt.Errorf("uncle %d is nil", i)
+ }
+ }
+ return nil
+}
+
func (self *Block) DecodeRLP(s *rlp.Stream) error {
var eb extblock
if err := s.Decode(&eb); err != nil {
diff --git a/eth/protocol.go b/eth/protocol.go
index e32ea233b..a0ab177cd 100644
--- a/eth/protocol.go
+++ b/eth/protocol.go
@@ -185,7 +185,10 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&txs); err != nil {
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
}
- for _, tx := range txs {
+ for i, tx := range txs {
+ if tx == nil {
+ return self.protoError(ErrDecode, "transaction %d is nil", i)
+ }
jsonlogger.LogJson(&logger.EthTxReceived{
TxHash: tx.Hash().Hex(),
RemoteId: self.peer.ID().String(),
@@ -268,6 +271,9 @@ func (self *ethProtocol) handle() error {
return self.protoError(ErrDecode, "msg %v: %v", msg, err)
}
}
+ if err := block.ValidateFields(); err != nil {
+ return self.protoError(ErrDecode, "block validation %v: %v", msg, err)
+ }
self.blockPool.AddBlock(&block, self.id)
}
@@ -276,6 +282,9 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&request); err != nil {
return self.protoError(ErrDecode, "%v: %v", msg, err)
}
+ if err := request.Block.ValidateFields(); err != nil {
+ return self.protoError(ErrDecode, "block validation %v: %v", msg, err)
+ }
hash := request.Block.Hash()
_, chainHead, _ := self.chainManager.Status()
diff --git a/eth/protocol_test.go b/eth/protocol_test.go
index 8ca6d1be6..d3466326a 100644
--- a/eth/protocol_test.go
+++ b/eth/protocol_test.go
@@ -63,6 +63,10 @@ func (self *testChainManager) GetBlockHashesFromHash(hash common.Hash, amount ui
func (self *testChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) {
if self.status != nil {
td, currentBlock, genesisBlock = self.status()
+ } else {
+ td = common.Big1
+ currentBlock = common.Hash{1}
+ genesisBlock = common.Hash{2}
}
return
}
@@ -163,14 +167,29 @@ func (self *ethProtocolTester) run() {
self.quit <- err
}
+func (self *ethProtocolTester) handshake(t *testing.T, mock bool) {
+ td, currentBlock, genesis := self.chainManager.Status()
+ // first outgoing msg should be StatusMsg.
+ err := p2p.ExpectMsg(self, StatusMsg, &statusMsgData{
+ ProtocolVersion: ProtocolVersion,
+ NetworkId: NetworkId,
+ TD: td,
+ CurrentBlock: currentBlock,
+ GenesisBlock: genesis,
+ })
+ if err != nil {
+ t.Fatalf("incorrect outgoing status: %v", err)
+ }
+ if mock {
+ go p2p.Send(self, StatusMsg, &statusMsgData{ProtocolVersion, NetworkId, td, currentBlock, genesis})
+ }
+}
+
func TestStatusMsgErrors(t *testing.T) {
logInit()
eth := newEth(t)
- td := common.Big1
- currentBlock := common.Hash{1}
- genesis := common.Hash{2}
- eth.chainManager.status = func() (*big.Int, common.Hash, common.Hash) { return td, currentBlock, genesis }
go eth.run()
+ td, currentBlock, genesis := eth.chainManager.Status()
tests := []struct {
code uint64
@@ -195,18 +214,7 @@ func TestStatusMsgErrors(t *testing.T) {
},
}
for _, test := range tests {
- // first outgoing msg should be StatusMsg.
- err := p2p.ExpectMsg(eth, StatusMsg, &statusMsgData{
- ProtocolVersion: ProtocolVersion,
- NetworkId: NetworkId,
- TD: td,
- CurrentBlock: currentBlock,
- GenesisBlock: genesis,
- })
- if err != nil {
- t.Fatalf("incorrect outgoing status: %v", err)
- }
-
+ eth.handshake(t, false)
// the send call might hang until reset because
// the protocol might not read the payload.
go p2p.Send(eth, test.code, test.data)
@@ -216,3 +224,177 @@ func TestStatusMsgErrors(t *testing.T) {
go eth.run()
}
}
+
+func TestNewBlockMsg(t *testing.T) {
+ // logInit()
+ eth := newEth(t)
+
+ var disconnected bool
+ eth.blockPool.removePeer = func(peerId string) {
+ disconnected = true
+ }
+
+ go eth.run()
+
+ eth.handshake(t, true)
+ err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
+ if err != nil {
+ t.Errorf("transactions expected, got %v", err)
+ }
+
+ var tds = make(chan *big.Int)
+ eth.blockPool.addPeer = func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool) {
+ tds <- td
+ return
+ }
+
+ var delay = 1 * time.Second
+ // eth.reset()
+ block := types.NewBlock(common.Hash{1}, common.Address{1}, common.Hash{1}, common.Big1, 1, "extra")
+
+ go p2p.Send(eth, NewBlockMsg, &newBlockMsgData{Block: block})
+ timer := time.After(delay)
+
+ select {
+ case td := <-tds:
+ if td.Cmp(common.Big0) != 0 {
+ t.Errorf("incorrect td %v, expected %v", td, common.Big0)
+ }
+ case <-timer:
+ t.Errorf("no td recorded after %v", delay)
+ return
+ case err := <-eth.quit:
+ t.Errorf("no error expected, got %v", err)
+ return
+ }
+
+ go p2p.Send(eth, NewBlockMsg, &newBlockMsgData{block, common.Big2})
+ timer = time.After(delay)
+
+ select {
+ case td := <-tds:
+ if td.Cmp(common.Big2) != 0 {
+ t.Errorf("incorrect td %v, expected %v", td, common.Big2)
+ }
+ case <-timer:
+ t.Errorf("no td recorded after %v", delay)
+ return
+ case err := <-eth.quit:
+ t.Errorf("no error expected, got %v", err)
+ return
+ }
+
+ go p2p.Send(eth, NewBlockMsg, []interface{}{})
+ // Block.DecodeRLP: validation failed: header is nil
+ eth.checkError(ErrDecode, delay)
+
+}
+
+func TestBlockMsg(t *testing.T) {
+ // logInit()
+ eth := newEth(t)
+ blocks := make(chan *types.Block)
+ eth.blockPool.addBlock = func(block *types.Block, peerId string) (err error) {
+ blocks <- block
+ return
+ }
+
+ var disconnected bool
+ eth.blockPool.removePeer = func(peerId string) {
+ disconnected = true
+ }
+
+ go eth.run()
+
+ eth.handshake(t, true)
+ err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
+ if err != nil {
+ t.Errorf("transactions expected, got %v", err)
+ }
+
+ var delay = 3 * time.Second
+ // eth.reset()
+ newblock := func(i int64) *types.Block {
+ return types.NewBlock(common.Hash{byte(i)}, common.Address{byte(i)}, common.Hash{byte(i)}, big.NewInt(i), uint64(i), string(i))
+ }
+ b := newblock(0)
+ b.Header().Difficulty = nil // check if nil as *big.Int decodes as 0
+ go p2p.Send(eth, BlocksMsg, types.Blocks{b, newblock(1), newblock(2)})
+ timer := time.After(delay)
+ for i := int64(0); i < 3; i++ {
+ select {
+ case block := <-blocks:
+ if (block.ParentHash() != common.Hash{byte(i)}) {
+ t.Errorf("incorrect block %v, expected %v", block.ParentHash(), common.Hash{byte(i)})
+ }
+ if block.Difficulty().Cmp(big.NewInt(i)) != 0 {
+ t.Errorf("incorrect block %v, expected %v", block.Difficulty(), big.NewInt(i))
+ }
+ case <-timer:
+ t.Errorf("no td recorded after %v", delay)
+ return
+ case err := <-eth.quit:
+ t.Errorf("no error expected, got %v", err)
+ return
+ }
+ }
+
+ go p2p.Send(eth, BlocksMsg, []interface{}{[]interface{}{}})
+ eth.checkError(ErrDecode, delay)
+ if !disconnected {
+ t.Errorf("peer not disconnected after error")
+ }
+
+ // test empty transaction
+ eth.reset()
+ go eth.run()
+ eth.handshake(t, true)
+ err = p2p.ExpectMsg(eth, TxMsg, []interface{}{})
+ if err != nil {
+ t.Errorf("transactions expected, got %v", err)
+ }
+ b = newblock(0)
+ b.AddTransaction(nil)
+ go p2p.Send(eth, BlocksMsg, types.Blocks{b})
+ eth.checkError(ErrDecode, delay)
+
+}
+
+func TestTransactionsMsg(t *testing.T) {
+ logInit()
+ eth := newEth(t)
+ txs := make(chan *types.Transaction)
+
+ eth.txPool.addTransactions = func(t []*types.Transaction) {
+ for _, tx := range t {
+ txs <- tx
+ }
+ }
+ go eth.run()
+
+ eth.handshake(t, true)
+ err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
+ if err != nil {
+ t.Errorf("transactions expected, got %v", err)
+ }
+
+ var delay = 3 * time.Second
+ tx := &types.Transaction{}
+
+ go p2p.Send(eth, TxMsg, []interface{}{tx, tx})
+ timer := time.After(delay)
+ for i := int64(0); i < 2; i++ {
+ select {
+ case <-txs:
+ case <-timer:
+ return
+ case err := <-eth.quit:
+ t.Errorf("no error expected, got %v", err)
+ return
+ }
+ }
+
+ go p2p.Send(eth, TxMsg, []interface{}{[]interface{}{}})
+ eth.checkError(ErrDecode, delay)
+
+}