-
Notifications
You must be signed in to change notification settings - Fork 147
Add ephemeral history gossiper #1851
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ephemeral history gossiper #1851
Conversation
a8cb9ba
to
860fd2f
Compare
@morph-dev this PR is ready to review now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is one/two high level comments that I would like to discuss.
But no major concerns and PR looks mostly ok.
bin/portal-bridge/src/bridge/ephemeral_history/ephemeral_bundle.rs
Outdated
Show resolved
Hide resolved
.collect() | ||
} | ||
|
||
async fn send_offer_with_header_series( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe rename to send_multi_offer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function assumes that the content is a header series. Multi offer would imply you could multi offer any set of data which isn't the case here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true for gossip_content_header_series
(because of the select_random_peers
), but how would this function be different for other type of content?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will change it's input parameter's then to restrict it more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand your arguments, can you elaborate more?
Multi offer would imply you could multi offer any set of data which isn't the case here
Why couldn't we offer any set of data usign this function? If you have a peer and you want to send it multiple content items, why can't you use this function?
I will change it's input parameter's then to restrict it more
No change was done to this function (or it's parameters). Why would you rectrict function if it can be broad (without downsides)?
Ultimately, it doesn't matter much, it's just a function name. I think it would be nice if we have both send_offer
and send_multi_offer
and they behave similarly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well this function can't be used to gossip not ephemeral content, and there is no justification to added support for that. It isn't a priority and this function can't be used on generic content. It requests for random peers. send_multi_offer
would require logic we don't need now, this clearly isn't a 1 line change.
|
||
/// The finalized state root should be for a finalized period. The beacon blocks passed in must | ||
/// be contained with that respective period's block roots to be provable. | ||
pub async fn gossiped_proven_headers( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not mistaken, this would start close to 8192*2
gossiping tasks.
I'm worried that all these tasks might starve the offer permit semaphore, especially because semaphore is fair. Meaning, we might not be able to gossip ephemeral content for some time.
Instead, we could do one of the following:
- send this content sequentially (it will take longer)
- use different semaphore
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did the third non-listed option of using a future stream then buffering the futures, which will basically rate limit it so only X futures can run at the same time.
- sequentially
this one isn't good - semaphore
There are many ways this could be implemented using semaphore, so the suggestion is too broad for me to make any direct statements.
Anyways let me know what you think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you implementation doesn't work as you want it. I tried it in simplified form here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f9efd12f88caac5f19a20c9e2b8a1310
The reason is that because we have tokio::spawn
, background task will start as soon as it's called (not when it's buffered).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your simplifed code isn't the same as our code hence it gives an invalid result. I updated it so that tokio::spawn
is awaited in the function called and it works as expected https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=5acc022e9180d573e1e0b4769a2377da
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We talked on the call, and I did have an oversight in my implementation. After discussion using a semaphore makes the most sense, so I implemented it.
@morph-dev ready for another look, let me know if I missed anything |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that buffered futures doesn't work as you are expecting. Happy to have a call and discuss it.
Other than that, no big concerns.
bin/portal-bridge/src/bridge/ephemeral_history/ephemeral_bundle.rs
Outdated
Show resolved
Hide resolved
bin/portal-bridge/src/bridge/ephemeral_history/ephemeral_bundle.rs
Outdated
Show resolved
Hide resolved
let mut bodies = vec![]; | ||
let mut receipts = vec![]; | ||
for (header, body, receipt) in ephemeral_bundle.blocks { | ||
bodies.push((header.hash_slow(), body)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe calculate header.hash_slow()
once and reuse?
.collect() | ||
} | ||
|
||
async fn send_offer_with_header_series( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand your arguments, can you elaborate more?
Multi offer would imply you could multi offer any set of data which isn't the case here
Why couldn't we offer any set of data usign this function? If you have a peer and you want to send it multiple content items, why can't you use this function?
I will change it's input parameter's then to restrict it more
No change was done to this function (or it's parameters). Why would you rectrict function if it can be broad (without downsides)?
Ultimately, it doesn't matter much, it's just a function name. I think it would be nice if we have both send_offer
and send_multi_offer
and they behave similarly.
|
||
/// The finalized state root should be for a finalized period. The beacon blocks passed in must | ||
/// be contained with that respective period's block roots to be provable. | ||
pub async fn gossiped_proven_headers( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you implementation doesn't work as you want it. I tried it in simplified form here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f9efd12f88caac5f19a20c9e2b8a1310
The reason is that because we have tokio::spawn
, background task will start as soon as it's called (not when it's buffered).
@morph-dev ready for another review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! 🚀
} | ||
|
||
impl Gossiper { | ||
pub fn new( | ||
census: Census, | ||
history_network: Arc<HistoryNetwork>, | ||
metrics: BridgeMetricsReporter, | ||
offer_limit: usize, | ||
head_offer_limit: usize, | ||
proven_headers_offer_limit: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe name the variable (proven_headers_offer_limit
) and semaphore (non_ephemeral_headers_semaphore
) in the same way? Meaning, non_ephemeral_offer_limit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I missed this when renaming the variables, nice catch
let offer_permit = if is_head_offer { | ||
self.head_semaphore | ||
.clone() | ||
.acquire_owned() | ||
.await | ||
.expect("to be able to acquire semaphore") | ||
} else { | ||
self.non_ephemeral_headers_semaphore | ||
.clone() | ||
.acquire_owned() | ||
.await | ||
.expect("to be able to acquire semaphore") | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let offer_permit = if is_head_offer { | |
self.head_semaphore | |
.clone() | |
.acquire_owned() | |
.await | |
.expect("to be able to acquire semaphore") | |
} else { | |
self.non_ephemeral_headers_semaphore | |
.clone() | |
.acquire_owned() | |
.await | |
.expect("to be able to acquire semaphore") | |
}; | |
let semaphore = if is_head_offer { | |
self.head_semaphore.clone() | |
} else { | |
self.non_ephemeral_headers_semaphore.clone() | |
}; | |
let offer_permit = semaphore | |
.acquire_owned() | |
.await | |
.expect("to be able to acquire semaphore") |
This PR depends on
What was wrong?
This is a chunk from #1846
We need a Gossiper which handles the unique cases fund in the Ephemeral History Bridge we do different functions
How was it fixed?
Add the code
Work for followup PR's