github.com/koko1123/flow-go-1@v0.29.6/model/verification/chunkDataPackRequest.go (about)

     1  package verification
     2  
     3  import (
     4  	"github.com/koko1123/flow-go-1/model/chunks"
     5  	"github.com/koko1123/flow-go-1/model/flow"
     6  	"github.com/koko1123/flow-go-1/model/flow/filter"
     7  )
     8  
     9  // ChunkDataPackRequest is an internal data structure in fetcher engine that is passed between the engine
    10  // and requester module. It conveys required information for requesting a chunk data pack.
    11  type ChunkDataPackRequest struct {
    12  	chunks.Locator // uniquely identifies chunk
    13  	ChunkDataPackRequestInfo
    14  }
    15  
    16  type ChunkDataPackRequestInfo struct {
    17  	ChunkID   flow.Identifier
    18  	Height    uint64              // block height of execution result of the chunk, used to drop chunk requests of sealed heights.
    19  	Agrees    flow.IdentifierList // execution node ids that generated the result of chunk.
    20  	Disagrees flow.IdentifierList // execution node ids that generated a conflicting result with result of chunk.
    21  	Targets   flow.IdentityList   // list of all execution nodes identity at the block height of this chunk (including non-responders).
    22  }
    23  
    24  // SampleTargets returns identifier of execution nodes that can be asked for the chunk data pack, based on
    25  // the agreeing and disagreeing execution nodes of the chunk data pack request.
    26  func (c ChunkDataPackRequestInfo) SampleTargets(count int) flow.IdentifierList {
    27  	// if there are enough receipts produced the same result (agrees), we sample from them.
    28  	if len(c.Agrees) >= count {
    29  		return c.Targets.Filter(filter.HasNodeID(c.Agrees...)).Sample(uint(count)).NodeIDs()
    30  	}
    31  
    32  	// since there is at least one agree, then usually, we just need `count - 1` extra nodes as backup.
    33  	// We pick these extra nodes randomly from the rest nodes who we haven't received its receipt.
    34  	// In the case where all other execution nodes has produced different results, then we will only
    35  	// fetch from the one produced the same result (the only agree)
    36  	need := uint(count - len(c.Agrees))
    37  
    38  	nonResponders := c.Targets.Filter(filter.Not(filter.HasNodeID(c.Disagrees...))).Sample(need).NodeIDs()
    39  	return append(c.Agrees, nonResponders...)
    40  }
    41  
    42  type ChunkDataPackRequestInfoList []*ChunkDataPackRequestInfo
    43  type ChunkDataPackRequestList []*ChunkDataPackRequest
    44  
    45  // ContainsChunkID returns true if list contains a request for chunk ID.
    46  func (c ChunkDataPackRequestList) ContainsChunkID(chunkID flow.Identifier) bool {
    47  	for _, request := range c {
    48  		if request.ChunkID == chunkID {
    49  			return true
    50  		}
    51  	}
    52  
    53  	return false
    54  }
    55  
    56  // ContainsLocator returns true if list contains a request for the given resultID and chunkIndex.
    57  func (c ChunkDataPackRequestList) ContainsLocator(resultID flow.Identifier, chunkIndex uint64) bool {
    58  	for _, request := range c {
    59  		if request.ResultID == resultID && request.Index == chunkIndex {
    60  			return true
    61  		}
    62  	}
    63  
    64  	return false
    65  }
    66  
    67  // UniqueRequestInfo extracts and returns request info based on chunk IDs. Note that a ChunkDataPackRequestList
    68  // may have duplicate requests for the same chunk ID that belongs to distinct execution results.
    69  func (c ChunkDataPackRequestList) UniqueRequestInfo() ChunkDataPackRequestInfoList {
    70  	added := make(map[flow.Identifier]*ChunkDataPackRequestInfo)
    71  
    72  	requestInfoList := ChunkDataPackRequestInfoList{}
    73  
    74  	for _, request := range c {
    75  		var info *ChunkDataPackRequestInfo
    76  		if _, ok := added[request.ChunkID]; !ok {
    77  			info = &request.ChunkDataPackRequestInfo
    78  		} else {
    79  			info = added[request.ChunkID]
    80  			info.Agrees = append(info.Agrees, request.Agrees...)
    81  			info.Disagrees = append(info.Disagrees, request.Disagrees...)
    82  			info.Targets = append(info.Targets, request.Targets...)
    83  		}
    84  
    85  		added[request.ChunkID] = info
    86  	}
    87  
    88  	for chunkID := range added {
    89  		info := added[chunkID]
    90  		requestInfoList = append(requestInfoList, info)
    91  	}
    92  
    93  	return requestInfoList
    94  }