Merge pull request #20546 from karalabe/validate-block-broadcast
eth: check propagated block malformation on receiption
This commit is contained in:
commit
e9e69d6e29
@ -687,6 +687,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||
if err := msg.Decode(&request); err != nil {
|
||||
return errResp(ErrDecode, "%v: %v", msg, err)
|
||||
}
|
||||
if hash := types.CalcUncleHash(request.Block.Uncles()); hash != request.Block.UncleHash() {
|
||||
log.Warn("Propagated block has invalid uncles", "have", hash, "exp", request.Block.UncleHash())
|
||||
break // TODO(karalabe): return error eventually, but wait a few releases
|
||||
}
|
||||
if hash := types.DeriveSha(request.Block.Transactions()); hash != request.Block.TxHash() {
|
||||
log.Warn("Propagated block has invalid body", "have", hash, "exp", request.Block.TxHash())
|
||||
break // TODO(karalabe): return error eventually, but wait a few releases
|
||||
}
|
||||
if err := request.sanityCheck(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -634,3 +634,65 @@ outer:
|
||||
t.Errorf("block broadcast to %d peers, expected %d", receivedCount, broadcastExpected)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that a propagated malformed block (uncles or transactions don't match
|
||||
// with the hashes in the header) gets discarded and not broadcast forward.
|
||||
func TestBroadcastMalformedBlock(t *testing.T) {
|
||||
// Create a live node to test propagation with
|
||||
var (
|
||||
engine = ethash.NewFaker()
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
config = ¶ms.ChainConfig{}
|
||||
gspec = &core.Genesis{Config: config}
|
||||
genesis = gspec.MustCommit(db)
|
||||
)
|
||||
blockchain, err := core.NewBlockChain(db, nil, config, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new blockchain: %v", err)
|
||||
}
|
||||
pm, err := NewProtocolManager(config, nil, downloader.FullSync, DefaultConfig.NetworkId, new(event.TypeMux), new(testTxPool), engine, blockchain, db, 1, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to start test protocol manager: %v", err)
|
||||
}
|
||||
pm.Start(2)
|
||||
defer pm.Stop()
|
||||
|
||||
// Create two peers, one to send the malformed block with and one to check
|
||||
// propagation
|
||||
source, _ := newTestPeer("source", eth63, pm, true)
|
||||
defer source.close()
|
||||
|
||||
sink, _ := newTestPeer("sink", eth63, pm, true)
|
||||
defer sink.close()
|
||||
|
||||
// Create various combinations of malformed blocks
|
||||
chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) {})
|
||||
|
||||
malformedUncles := chain[0].Header()
|
||||
malformedUncles.UncleHash[0]++
|
||||
malformedTransactions := chain[0].Header()
|
||||
malformedTransactions.TxHash[0]++
|
||||
malformedEverything := chain[0].Header()
|
||||
malformedEverything.UncleHash[0]++
|
||||
malformedEverything.TxHash[0]++
|
||||
|
||||
// Keep listening to broadcasts and notify if any arrives
|
||||
notify := make(chan struct{})
|
||||
go func() {
|
||||
if _, err := sink.app.ReadMsg(); err == nil {
|
||||
notify <- struct{}{}
|
||||
}
|
||||
}()
|
||||
// Try to broadcast all malformations and ensure they all get discarded
|
||||
for _, header := range []*types.Header{malformedUncles, malformedTransactions, malformedEverything} {
|
||||
block := types.NewBlockWithHeader(header).WithBody(chain[0].Transactions(), chain[0].Uncles())
|
||||
if err := p2p.Send(source.app, NewBlockMsg, []interface{}{block, big.NewInt(131136)}); err != nil {
|
||||
t.Fatalf("failed to broadcast block: %v", err)
|
||||
}
|
||||
select {
|
||||
case <-notify:
|
||||
t.Fatalf("malformed block forwarded")
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user