Skip to content
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

Controlc/tx p2p #491

Merged
merged 33 commits into from
Jul 28, 2022
Merged

Controlc/tx p2p #491

merged 33 commits into from
Jul 28, 2022

Conversation

ControlCplusControlV
Copy link
Contributor

Design to closes #477 and #478 . Adds 2 new channels to the txpool designed for p2p to hook into. One channel is a mpsc channel designed to send transactions received on the txpool from the gql endpoint to p2p, so that it can broadcast them to other nodes. The other is a simple broadcast channel which is used to receive transactions from p2p which should be included in the txpool. Tests are bit rough atm and need some polishing, but making a draft PR for general design review and feedback

db: Option<Box<dyn TxPoolDb>>,
import_block_events: Option<broadcast::Receiver<ImportBlockBroadcast>>,
broadcast_txs: Option<mpsc::Sender<TransactionBroadcast>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on our earlier call today, I think we should use P2pRequestEvent instead of the TransactionBroadcast enum for sending.

Another minor nit is that broadcast_txs isn't totally clear which direction the broadcast is going. Maybe something like network_outbox would help clarify the intention?

Suggested change
broadcast_txs: Option<mpsc::Sender<TransactionBroadcast>>,
network_outbox: Option<mpsc::Sender<P2pRequestEvent>>,

Copy link
Contributor Author

@ControlCplusControlV ControlCplusControlV Jul 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this to P2pRequestEvent, I do remember talking about this, I think it got mixed up between fuel-core-interfaces/p2p/P2pRequestEvent::BroadcastNewTransaction and fuel-core-interfaces/p2p/TransactionBroadcast::NewTransaction as both have similar names, and added the rename

@@ -10,9 +13,11 @@ pub struct ServiceBuilder {
sender: txpool::Sender,
receiver: mpsc::Receiver<TxPoolMpsc>,
config: Config,
broadcast: broadcast::Sender<TxStatusBroadcast>,
consumer: broadcast::Sender<TxStatusBroadcast>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consumer could mean a lot of things... we could just call this tx_status_updates?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I am aiming to disambiguate some of the naming: sender, receiver, consumer, etc., are pretty vague and I find it can be confusing trying to understand which channels are used for what. I am taking a stab at that now.

@bvrooman
Copy link
Contributor

I noticed that the test insert_from_p2p seems to be flaky when I run it locally: most of the times it passes but sometimes it fails. It looks like there's a race condition. We're expecting the same transaction to be sent twice and for an error to raise on the second submission. However, in some cases, it looks like we get to the assert and check the receiver before both submissions are received, causing the test to fail.

@ControlCplusControlV
Copy link
Contributor Author

I noticed that the test insert_from_p2p seems to be flaky when I run it locally: most of the times it passes but sometimes it fails. It looks like there's a race condition. We're expecting the same transaction to be sent twice and for an error to raise on the second submission. However, in some cases, it looks like we get to the assert and check the receiver before both submissions are received, causing the test to fail.

@bvrooman Race condition is most likely because send isn't awaited in any way, so if the send doesn't process in time then insertion could possible go through (as the previous transaction hasn't been inserted yet), leading to no error and the test failing. This is one thing that needs to be fixed in the test, which ideally should just have a base way to test the sending of the transaction rather than measuring side affects

@bvrooman
Copy link
Contributor

bvrooman commented Jul 15, 2022

I have some additional thoughts:

As currently designed in this PR, the txpool service (and inner context) has a new receiver that will receive events for incoming transactions. When it receives one, it will insert it into the txpool.

This is similar to when the existing txpool receiver gets an insert event, where it then signals the service to insert the transactions into the txpool. However, the difference between inserting transactions and receiving an incoming transaction is that we must broadcast the transactions and status (submitted, squeezed out, etc.) on insertion, but not on an incoming transaction.

Because this PR currently uses the same TxPool::insert method in both cases, we had to augment the signature to accept an optional broadcaster: we pass Some(network_outbox) on insertion, but None on incoming transactions. Inside insert, we then check against the Option, to see if we need to put anything in that outbox. This is a bit of a hack we employed to get our draft working. I'd argue that this approach can be improved upon, and the insert method isn't well suited for the latter case of an incoming transaction. Rather, we can introduce a new TxPool method, something like TxPool::insert_one to handle this case. This is further evidenced by the fact that insert is designed to operate on a vector of transactions, rather than a single transaction, and we have to wrap any incoming transaction in a 1-sized vector to accommodate this interface.

When I get a chance, I will look at this refactor and push a commit here, along with the ongoing refactoring of the existing service and context channel names.

@bvrooman
Copy link
Contributor

bvrooman commented Jul 15, 2022

We also do not seem to have much consistency on our channel naming conventions. In a number of places, we use terms like "sender", "producer", and now "outbox" to refer to objects of Sender. We use terms like "receiver", "incoming", and "events", for objects of type Receiver. Personally, I find this can be fairly confusing and unintuitive to read. It would be great to consolidate on some naming convention for channels.

I am aiming to address naming consistency issues in areas localized to this PR, but I'd like to hear any thoughts/suggestions you guys might have on this.

@ControlCplusControlV
Copy link
Contributor Author

I agree @bvrooman that fixing naming would be nice to add, I also think it would be good to have a single insert, as it cuts out of a lot interation logic which isn't needed for a singular tx. I think this may be best for a later PR though as we will eventually want to do batch insert from p2p, which will then require a different flow. Unless you think it will be worth having both flows built out? (ie p2p_insert_single, and p2p_insert_many)

@bvrooman
Copy link
Contributor

bvrooman commented Jul 20, 2022

I had a conversation on Monday with @Voxelot regarding the feature as well as the currently proposed code:

One key discussion point was that we do not need to perform any broadcasting on new local transactions (at least, not at this time). The agreed action item was to simplify the current implementation, and to remove the broadcasting on this event.

This means a couple of things:

  • The handler for this event becomes simpler, and we do not need to send anything to the network_outbox
  • We do not need to test for broadcasts on local insertions
  • The network_outbox itself is unnecessary, and it can be removed entirely from the service and context, along with the corresponding service builder methods
  • The existing TxPool::insert function signature can be reverted back to its original signature, and we no longer need the Option<Sender> parameter

This simplifies things in the current PR. I am putting up the commit for this shortly.

I'd just like to get @Voxelot to confirm that my understanding of this is correct.

When it comes to future flows, like supporting batch insert from p2p, I think we should address that when the time comes. We can take an iterative approach and build up. As long as we are careful not to paint ourselves into any corners right now, we should be in a good position to build out further use cases when they are required.

CC: @ControlCplusControlV

@Voxelot
Copy link
Member

Voxelot commented Jul 21, 2022

I think there's some confusion around the terminology of what was meant by local insert. What I thought we were discussing is that we don't need to do any additional p2p broadcast for insert_local (which is confusingly only actually used when receiving txs from non-local sources like the p2p network). We would still need to broadcast from the main TxPool::insert method since that's what the GraphQL API uses to insert txs from a locally submitted txn. If we rip out the p2p request sender/outbox entirely from the TxPool service, I don't know how other nodes would be expected to receive anything in that case if there's no mechanism at all to send messages when a user submits a tx.

@ControlCplusControlV
Copy link
Contributor Author

ControlCplusControlV commented Jul 21, 2022

@Voxelot yes this is in line with what I was originally thinking. Were you still thinking of using TxPool::Insert or breaking that out into a new a mspc method to use an entirely different function to insert from p2p or to insert from gql. I am locked of my slack until I am back from ETHcc (passcode issue) but happy to discuss on here and over something like TG

EDIT : Also looking at CI issues

@bvrooman
Copy link
Contributor

I talked with @Voxelot today, and did a bit of refactoring based on our discussion. I am introducing Txpool::insert_with_broadcast that effectively wraps Txpool::insert and broadcasts a new p2p transaction if the insertion was successful. Now, we perform insert on p2p transactions, and insert_with_broadcast on local transactions (i.e., graphql).

@ControlCplusControlV ControlCplusControlV removed the request for review from rakita July 26, 2022 17:31
@ControlCplusControlV ControlCplusControlV marked this pull request as ready for review July 26, 2022 17:31
@@ -56,9 +59,15 @@ pub async fn start_modules(config: &Config, database: &Database) -> Result<Modul
.unwrap(),
);

// Meant to simulate p2p's channels which hook in to communicate with txpool
let (network_sender, _) = mpsc::channel(100);
Copy link
Member

@Voxelot Voxelot Jul 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without any network_receiver, this queue will fill up and may stop the txpool from working once it's reached 100 txs.

We likely need to spawn a task to drain this queue whenever txs are added until the p2p service can perform this function.

@ControlCplusControlV ControlCplusControlV marked this pull request as draft July 27, 2022 22:58
@bvrooman bvrooman changed the base branch from master to bvrooman-tx_p2p_merge July 28, 2022 22:23
@bvrooman
Copy link
Contributor

I am squashing & merging this branch into another dev branch to make future rebases easier. We are going to rebase with Elvis's development branch to continue development.

@bvrooman bvrooman marked this pull request as ready for review July 28, 2022 22:25
@bvrooman bvrooman merged commit cb70e24 into bvrooman-tx_p2p_merge Jul 28, 2022
@bvrooman bvrooman deleted the controlc/tx_p2p branch July 28, 2022 22:25
bvrooman added a commit that referenced this pull request Jul 28, 2022
* added p2p stuff, tests still WIP

* Restructure DummyP2PInterface and use it in tests

* Added p2p stuff for real this time I think

* ooops

* tests go green

* ooops

* partial test

* comment

* ooops

* ooops

* Separate network_outbox and incoming_txs on txpool service builder

* updated test

* updated test

* oops

* Remove `network_outbox` and rename senders/receivers

* Fmt

* Missed refactor

* Typo

* insert_with_broadcast

* Fmt

* Add network sender to modules

* Fmt imports

* retrigger checks

* retrigger checks

* Fix flaky test

* Update test name

* Replace insert call with duplicate logic

* Add additional test

* some fixes but not a lot

Co-authored-by: Brandon Vrooman <brandon.vrooman@gmail.com>
Co-authored-by: Brandon Vrooman <brandon@DESKTOP-CNCCSJQ.localdomain>
Co-authored-by: ControlC ControlV <controlc@ControlCs-MacBook-Pro.local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request fuel-txpool
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Broadcast transactions to peers when they're inserted into txpool via GraphQL API
3 participants