-
Notifications
You must be signed in to change notification settings - Fork 261
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
v1.18: scheduler forward packets (backport of #898) #1663
Conversation
Cherry-pick of fb35f19 has failed:
To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally |
(cherry picked from commit fb35f19) # Conflicts: # core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs # core/src/banking_stage/transaction_scheduler/scheduler_controller.rs # core/src/banking_stage/transaction_scheduler/scheduler_metrics.rs # core/src/banking_stage/transaction_scheduler/transaction_state.rs # core/src/banking_stage/transaction_scheduler/transaction_state_container.rs # core/src/validator.rs
7978888
to
98f9e9b
Compare
@@ -181,8 +196,112 @@ impl SchedulerController { | |||
} | |||
} | |||
|
|||
/// Forward packets to the next leader. | |||
fn forward_packets(&mut self, hold: bool) { |
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.
is this copypasta from the old scheduler?
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.
No this is all new. old scheduler didn't have same container structure, or the same checks we do here (actually checking if tx can pay fees), or timeout.
core/src/banking_stage/transaction_scheduler/scheduler_controller.rs
Outdated
Show resolved
Hide resolved
core/src/banking_stage/transaction_scheduler/scheduler_metrics.rs
Outdated
Show resolved
Hide resolved
core/src/banking_stage/transaction_scheduler/transaction_state.rs
Outdated
Show resolved
Hide resolved
should_forward: bool, | ||
}, | ||
/// Only used during transition. | ||
Transitioning, |
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.
what does "transitioning" mean? is this like "preparing"?
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.
it's an internal "hack" for transitioning from one state to another that allows us to take ownership of the fields without having to fill in dummy information in the other state.
let mut filter_array = [true; CHUNK_SIZE]; | ||
let mut ids = Vec::with_capacity(CHUNK_SIZE); | ||
let mut txs = Vec::with_capacity(CHUNK_SIZE); |
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 like we can do the same allocation optimization 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.
can with ids but not with txs since txs holds references. even if you clear the vec, borrow checker isn't aware that the references are gone.
let transaction = self.container.get_transaction_ttl(&id.id).unwrap(); | ||
txs.push(&transaction.transaction); |
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.
can we not do this in the loop above where we fill ids
?
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.
No. Popping ids is mutating change on container. this is getting reference to something in the container
while let Some(id) = self.container.pop() { | ||
self.container.remove_by_id(&id.id); | ||
} |
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.
seems like we could stand to implement a clear()
on TransactionStateContainer
and call .clear()
on each of its members there
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.
it'd be similar, but not what we want. clearing would remove transaction that are "in-flight".
Example:
We are leader, schedule a transaction for processing.
We stop being leader, but processing thread hasn't yet sent the finished message back to scheduler thread.
If scheduler clears the container then we will remove the id from the map, and when scheduler gets the finished message then it's for an unknown id (since if we cleared it).
He there! I kindly ask you to add two changes: 1. Add an argument to control this behavior:
The first and third options: this can be a conscious choice for some validators. So, it's their responsibility. Constant forwarding can be used as harmful behavior. A low-staked (but enough to be considered staked) node can send copies of transactions to high-staked nodes that are not leaders at the moment. With the current implementation, all of them will forward these transactions to the current leader on their behalf. I ask to make the default behavior the second option. Otherwise, the behavior will either be harmful or not very useful in terms of forwarding as it was originally considered (so that the user does not have to send their transaction multiple times). 2. Remove non-staked nodes filtering |
On 1, the intent here is a quick solution. The scheduler not the right place for it, imo, but we needed something because of the quick adoption of swqos, and it was historically done in block-production. We wanted something simple that was backportable; for us this ended up just being effectively the same behavior as in previous block-production-method.
Any longer term solution we come up for this, imo, should be opt-in and be more configurable. But as I mentioned, many of us don't think pairing this swqos support stuff in the scheduler is a good long-term design - so I'm not sure if this configurability will come as is. On 2, from my view non-staked node forwarding is incredibly harmful and was contributing to congestion a while back. Non-staked forwarding leads to sending to all nodes, even those that are not leader, because they will forward to the leader...this is essentially the network DOSing itself. |
I absolutely agree with this. I observe the same thing. But then the only argument for forwarding remains that it is somehow related to swqos. And here I don't understand. Swqos was presented to validators as a way to allow friendly unstaked RPC nodes to connect to a specific validator node. And this node would be able to forward transactions to the current leader. |
In the swqos implementation, the size of the stake matters. Thus, a validator with a 20K stake can, by forwarding, make their transaction appear to the leader as if it has a priority of 200K or 2M, for example. UPD. I mean a priority in delivery, of course. Because the size of the stake guarantees that your connection won't be dropped. |
Right. Without this sudden swqos adoption we would not have re-added forwarding.
I'm not sure I understand the question here? The flow looks like this, how would you expect the PartnerValidator to get the tx to the actual leader? graph LR;
user --> RPC --> PartnerValidator -->|forwarding| leader;
It's not though, afaik we will only forward for swqos side-deals. Any txs from validators forwarding to us will not be forwarded by us.
validator sends to the current leader (with some time offset to account for avg transit time iirc), it doesn't go through some other validators. |
Oh, I see where the misunderstanding is now. The thing is, bad actors are using tools like https://github.com/helius-labs/atlas-txn-sender or https://github.com/marinade-finance/mtransaction. In short, these are proxies with a QUIC client and a validator key. The spam comes from such tools (I suspect that they are either installed on the validator's machine or additionally proxy traffic to the validator's IP or run a gossip client on the same machine as these proxies, because many validators filter traffic by IP from gossip). For example, I permanently receive 2-3K TPS when I'm not the leader. These tools will send their transactions to the regular TPU (not FWD) port of the validator, which is not the leader. So, these will be transactions from a staked node, and they wasn't forwarded. As a result, the validator will forward this spam. That's essentially the problem. |
I also see this on some of our canary nodes running master.
Interestingly, I do not see this. I see a bunch of packets coming on the TPU port, but all the top IPs spamming me are all unstaked. At least that's what's showing in the output from edit: re-ran with some custom filter, i do see some people sending staked on TPU so it's possible. but it's pretty minimal on order of 6 TPS vs the ~800TPS average spam on the TPU over long period. |
Why do you think it works through forwarding on your own validator? I just tried sending a transaction through my own validator, and it went through successfully, but forwarding is disabled. If I understand correctly, the RPC service sends the transaction to https://github.com/solana-labs/solana/blob/v1.18/send-transaction-service/src/send_transaction_service.rs, where the CurrentLeaderInfo is used, which is updated every second. So, the RPC sends the transaction to the TPU of the current leader. Where am I wrong? |
Ahh, I see https://solana.com/developers/guides/advanced/stake-weighted-qos#configuring-the-rpc-node Friendly RPC sends directly to our TPU. In this case, I think that "do not forward" by default will be the best solution for now. And for those who have friendly RPC providers, it will need to be disabled. |
The wording in this document is incorrect. The term "leader" should be replaced with "peered validator". |
Closing this as stale. If you think this is relevant please re-open and let |
Problem
Summary of Changes
Fixes #
This is an automatic backport of pull request #898 done by [Mergify](https://mergify.com).