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 }