@@ -27,6 +27,7 @@ use std::{
2727} ;
2828
2929use async_trait:: async_trait;
30+ use futures:: FutureExt ;
3031use log:: * ;
3132use ootle_network:: Network ;
3233use tari_common_types:: types:: FixedHash ;
@@ -57,6 +58,7 @@ use tari_validator_node_rpc::client::{
5758} ;
5859
5960use crate :: {
61+ committee_read:: { CommitteeReadTally , MemberResponse , READ_RACE_WIDTH , race_committee} ,
6062 error:: IndexerError ,
6163 substate_cache:: { SubstateCache , SubstateCacheEntry , SubstateCacheEntryRef , caches_nonexistence} ,
6264} ;
@@ -399,93 +401,39 @@ where
399401 } ) ;
400402 }
401403
402- let f = ( committee. len ( ) - 1 ) / 3 ;
403- let mut num_nexist_substate_results = 0 ;
404- let mut last_error = None ;
405- // Highest-version Up/Down response that came back without a proof. Only served if no member
406- // can prove.
407- let mut unproven_result: Option < SubstateResult > = None ;
408- for member in committee. shuffled ( ) {
409- let vn_addr = & member. address ;
410- debug ! ( target: LOG_TARGET , "Getting substate {} from vn {}" , substate_req, vn_addr) ;
411-
412- match self . get_substate_from_vn ( vn_addr, substate_req) . await {
413- Ok ( ( substate_result, verified) ) => {
414- debug ! ( target: LOG_TARGET , "Got substate result for {} from vn {} (verified = {}): {:?}" , substate_req, vn_addr, verified, substate_result) ;
415- match substate_result {
416- SubstateResult :: Up { .. } | SubstateResult :: Down { .. } => {
417- if verified || !self . verify_substate_proofs {
418- return Ok ( SubstateLookupResult {
419- result : substate_result,
420- verified,
421- } ) ;
422- }
423- // The member could not prove its response (e.g. nothing committed since
424- // the epoch started). Keep the highest version as a fallback (a member
425- // that is still syncing may respond with a stale copy) and try the rest
426- // of the committee for a proven copy.
427- if unproven_result
428- . as_ref ( )
429- . is_none_or ( |r| r. version ( ) < substate_result. version ( ) )
430- {
431- unproven_result = Some ( substate_result) ;
432- }
433- } ,
434- SubstateResult :: DoesNotExist => {
435- if num_nexist_substate_results > f {
436- return Ok ( SubstateLookupResult {
437- result : substate_result,
438- verified : false ,
439- } ) ;
440- }
441- num_nexist_substate_results += 1 ;
442- } ,
443- }
444- } ,
445- Err ( e) => {
446- // We ignore a single VN error and keep querying the rest of the committee
447- warn ! (
448- target: LOG_TARGET ,
449- "Could not get substate {} from vn {}: {}" , substate_req, vn_addr, e
450- ) ;
451- last_error = Some ( e) ;
452- } ,
453- }
454- }
455-
456- if let Some ( result) = unproven_result {
457- warn ! (
458- target: LOG_TARGET ,
459- "No committee member could supply a proof for {substate_req}. Returning the substate unverified." ,
460- ) ;
461- return Ok ( SubstateLookupResult {
462- result,
463- verified : false ,
464- } ) ;
465- }
466-
467- // Reaching here means no member returned the substate, so more than f DoesNotExist
468- // responses is f+1 agreement that it does not exist. This answer takes precedence over
469- // errors from unreachable members.
470- if num_nexist_substate_results > f {
471- return Ok ( SubstateLookupResult {
472- result : SubstateResult :: DoesNotExist ,
473- verified : false ,
474- } ) ;
475- }
476-
477- warn ! (
478- target: LOG_TARGET ,
479- "Could not get substate for shard {} from any of the validator nodes" , substate_req,
480- ) ;
404+ let tally = CommitteeReadTally :: new ( committee. len ( ) , self . verify_substate_proofs ) ;
405+ race_committee (
406+ committee
407+ . shuffled ( )
408+ . map ( |member| self . request_substate_from_vn ( & member. address , substate_req) ) ,
409+ READ_RACE_WIDTH ,
410+ tally,
411+ substate_req,
412+ )
413+ // Boxed so that the future's `Send` is settled here, where every lifetime is concrete. Left
414+ // opaque, rustc has to re-prove it from the caller's generic view and gives up with
415+ // "implementation of `Send` is not general enough" (rust-lang/rust#102211).
416+ . boxed ( )
417+ . await
418+ }
481419
482- if let Some ( e) = last_error {
483- return Err ( e) ;
420+ /// One committee member's answer to a read, logged.
421+ async fn request_substate_from_vn (
422+ & self ,
423+ vn_addr : & TAddr ,
424+ substate_req : SubstateRequirementRef < ' _ > ,
425+ ) -> MemberResponse {
426+ debug ! ( target: LOG_TARGET , "Getting substate {} from vn {}" , substate_req, vn_addr) ;
427+ let response = self . get_substate_from_vn ( vn_addr, substate_req) . await ;
428+ match & response {
429+ Ok ( ( substate_result, verified) ) => {
430+ debug ! ( target: LOG_TARGET , "Got substate result for {} from vn {} (verified = {}): {:?}" , substate_req, vn_addr, verified, substate_result) ;
431+ } ,
432+ Err ( e) => {
433+ warn ! ( target: LOG_TARGET , "Could not get substate {} from vn {}: {}" , substate_req, vn_addr, e) ;
434+ } ,
484435 }
485- Ok ( SubstateLookupResult {
486- result : SubstateResult :: DoesNotExist ,
487- verified : false ,
488- } )
436+ response
489437 }
490438
491439 /// Gets a substate directly from querying a VN. The returned flag is true if the result came
0 commit comments