github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/integration/blockordelay_test.go (about)

     1  package integration_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/onflow/flow-go/model/flow"
    10  	"github.com/onflow/flow-go/model/messages"
    11  	"github.com/onflow/flow-go/network/channels"
    12  )
    13  
    14  // This file includes functions to simulate network conditions.
    15  // The network conditions are simulated by defining whether a message sent to a receiver should be
    16  // blocked or delayed.
    17  
    18  // blockNodesFirstMessages blocks the _first_ n incoming messages for each member in `denyList`
    19  // (messages are counted individually for each Node).
    20  func blockNodesFirstMessages(n uint64, denyList ...*Node) BlockOrDelayFunc {
    21  	blackList := make(map[flow.Identifier]uint64, len(denyList))
    22  	for _, node := range denyList {
    23  		blackList[node.id.ID()] = n
    24  	}
    25  	lock := new(sync.Mutex)
    26  	return func(channel channels.Channel, event interface{}, sender, receiver *Node) (bool, time.Duration) {
    27  		// filter only consensus messages
    28  		switch event.(type) {
    29  		case *messages.BlockProposal:
    30  		case *messages.BlockVote:
    31  		case *messages.BlockResponse:
    32  		case *messages.TimeoutObject:
    33  		default:
    34  			return false, 0
    35  		}
    36  		lock.Lock()
    37  		defer lock.Unlock()
    38  		count, ok := blackList[receiver.id.ID()]
    39  		if ok && count > 0 {
    40  			blackList[receiver.id.ID()] = count - 1
    41  			return true, 0
    42  		}
    43  		return false, 0
    44  	}
    45  }
    46  
    47  // blockReceiverMessagesRandomly drops messages randomly with a probability of `dropProbability` ∈ [0,1]
    48  func blockReceiverMessagesRandomly(dropProbability float32) BlockOrDelayFunc {
    49  	lock := new(sync.Mutex)
    50  	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
    51  	return func(channel channels.Channel, event interface{}, sender, receiver *Node) (bool, time.Duration) {
    52  		lock.Lock()
    53  		block := prng.Float32() < dropProbability
    54  		lock.Unlock()
    55  		return block, 0
    56  	}
    57  }
    58  
    59  // delayReceiverMessagesByRange delivers all messages, but with a randomly sampled
    60  // delay in the interval [low, high). Panics when `low` < 0 or `low > `high`
    61  func delayReceiverMessagesByRange(low time.Duration, high time.Duration) BlockOrDelayFunc {
    62  	lock := new(sync.Mutex)
    63  	prng := rand.New(rand.NewSource(time.Now().UnixNano()))
    64  	delayRangeNs := int64(high - low)
    65  	minDelayNs := int64(low)
    66  
    67  	// fail early for non-sensical parameter settings
    68  	if int64(low) < 0 {
    69  		panic(fmt.Sprintf("minimal delay cannot be negative, but is %d ns", int64(low)))
    70  	}
    71  	if delayRangeNs < 0 {
    72  		panic(fmt.Sprintf("upper bound on delay (%d ns) cannot be smaller than lower bound (%d ns)", int64(high), int64(low)))
    73  	}
    74  
    75  	// shortcut for low = high: always return low
    76  	if delayRangeNs == 0 {
    77  		return func(channel channels.Channel, event interface{}, sender, receiver *Node) (bool, time.Duration) {
    78  			return false, low
    79  		}
    80  	}
    81  	// general version
    82  	return func(channel channels.Channel, event interface{}, sender, receiver *Node) (bool, time.Duration) {
    83  		lock.Lock()
    84  		d := prng.Int63n(delayRangeNs)
    85  		lock.Unlock()
    86  		return false, time.Duration(minDelayNs + d)
    87  	}
    88  }