test for invalid rlp encoding of block in BlocksMsg

- rename Validate -> ValidateFields not to confure consensus block validation
- add nil transaction and nil uncle header validation
- remove bigint field checks: rlp already decodes *big.Int to big.NewInt(0)
- add test for nil header, nil transaction
This commit is contained in:
zelig 2015-03-30 13:48:07 +01:00
parent d677190f39
commit 82da6bf4d2
3 changed files with 44 additions and 22 deletions

View File

@ -148,22 +148,19 @@ func NewBlockWithHeader(header *Header) *Block {
return &Block{header: header} return &Block{header: header}
} }
func (self *Block) Validate() error { func (self *Block) ValidateFields() error {
if self.header == nil { if self.header == nil {
return fmt.Errorf("header is nil") return fmt.Errorf("header is nil")
} }
// check *big.Int fields for i, transaction := range self.transactions {
if self.header.Difficulty == nil { if transaction == nil {
return fmt.Errorf("Difficulty undefined") return fmt.Errorf("transaction %d is nil", i)
}
} }
if self.header.GasLimit == nil { for i, uncle := range self.uncles {
return fmt.Errorf("GasLimit undefined") if uncle == nil {
} return fmt.Errorf("uncle %d is nil", i)
if self.header.GasUsed == nil { }
return fmt.Errorf("GasUsed undefined")
}
if self.header.Number == nil {
return fmt.Errorf("Number undefined")
} }
return nil return nil
} }
@ -253,10 +250,10 @@ func (self *Block) AddReceipt(receipt *Receipt) {
} }
func (self *Block) RlpData() interface{} { func (self *Block) RlpData() interface{} {
return []interface{}{self.header, self.transactions, self.uncles} // return []interface{}{self.header, self.transactions, self.uncles}
} // }
func (self *Block) RlpDataForStorage() interface{} { // func (self *Block) RlpDataForStorage() interface{} {
return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */} return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */}
} }

View File

@ -268,6 +268,9 @@ func (self *ethProtocol) handle() error {
return self.protoError(ErrDecode, "msg %v: %v", msg, err) 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) self.blockPool.AddBlock(&block, self.id)
} }
@ -276,7 +279,7 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&request); err != nil { if err := msg.Decode(&request); err != nil {
return self.protoError(ErrDecode, "%v: %v", msg, err) return self.protoError(ErrDecode, "%v: %v", msg, err)
} }
if err := request.Block.Validate(); err != nil { if err := request.Block.ValidateFields(); err != nil {
return self.protoError(ErrDecode, "block validation %v: %v", msg, err) return self.protoError(ErrDecode, "block validation %v: %v", msg, err)
} }
hash := request.Block.Hash() hash := request.Block.Hash()

View File

@ -1,7 +1,6 @@
package eth package eth
import ( import (
"fmt"
"log" "log"
"math/big" "math/big"
"os" "os"
@ -227,12 +226,11 @@ func TestStatusMsgErrors(t *testing.T) {
} }
func TestNewBlockMsg(t *testing.T) { func TestNewBlockMsg(t *testing.T) {
logInit() // logInit()
eth := newEth(t) eth := newEth(t)
var disconnected bool var disconnected bool
eth.blockPool.removePeer = func(peerId string) { eth.blockPool.removePeer = func(peerId string) {
fmt.Printf("peer <%s> is disconnected\n", peerId)
disconnected = true disconnected = true
} }
@ -293,7 +291,7 @@ func TestNewBlockMsg(t *testing.T) {
} }
func TestBlockMsg(t *testing.T) { func TestBlockMsg(t *testing.T) {
logInit() // logInit()
eth := newEth(t) eth := newEth(t)
blocks := make(chan *types.Block) blocks := make(chan *types.Block)
eth.blockPool.addBlock = func(block *types.Block, peerId string) (err error) { eth.blockPool.addBlock = func(block *types.Block, peerId string) (err error) {
@ -303,7 +301,6 @@ func TestBlockMsg(t *testing.T) {
var disconnected bool var disconnected bool
eth.blockPool.removePeer = func(peerId string) { eth.blockPool.removePeer = func(peerId string) {
fmt.Printf("peer <%s> is disconnected\n", peerId)
disconnected = true disconnected = true
} }
@ -320,7 +317,9 @@ func TestBlockMsg(t *testing.T) {
newblock := func(i int64) *types.Block { 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)) return types.NewBlock(common.Hash{byte(i)}, common.Address{byte(i)}, common.Hash{byte(i)}, big.NewInt(i), uint64(i), string(i))
} }
go p2p.Send(eth, BlocksMsg, types.Blocks{newblock(0), newblock(1), newblock(2)}) 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) timer := time.After(delay)
for i := int64(0); i < 3; i++ { for i := int64(0); i < 3; i++ {
select { select {
@ -328,6 +327,9 @@ func TestBlockMsg(t *testing.T) {
if (block.ParentHash() != common.Hash{byte(i)}) { if (block.ParentHash() != common.Hash{byte(i)}) {
t.Errorf("incorrect block %v, expected %v", 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: case <-timer:
t.Errorf("no td recorded after %v", delay) t.Errorf("no td recorded after %v", delay)
return return
@ -336,4 +338,24 @@ func TestBlockMsg(t *testing.T) {
return 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)
} }