feat(network-monitor): add fees support - #2526
Conversation
b5e9f07 to
41c0222
Compare
I think this should not be needed - instead, the sponsorship note should pay for the network transactions. These notes are created by operator account which should have tokens already. Two things to keep in mind here:
|
This works now, but it will need to change at the point when batch builders' tx acceptance criteria change and they require fee payment.
Thanks, good catch! I created a |
Even though the notes are currently priced at 0 and the batch builders will accept transactions with 0 fees, the current situation is that
|
41c0222 to
dc2daab
Compare
|
I moved the deps bump and genesis changes to #2538 , which will be ready to merge after the fix of the protocol releases. |
igamigo
left a comment
There was a problem hiding this comment.
Looking good. Leaving some general comments/quetsions for now.
| let mut fee_schedule = vec![(increment_script.root(), increment_note_fee)]; | ||
|
|
||
| if verification_base_fee > 0 { | ||
| allowed_scripts.insert(FeeSponsorshipNote::script_root()); |
There was a problem hiding this comment.
nit: I think this is not nedeed if you use AuthNetworkAccount::new/NetworkAccount::builder because it's already included by default
There was a problem hiding this comment.
Using AuthNetworkAccount::new is actually a bit (not much really) more lines than the custom approach due to AccountConfigure. This particular line that you mentioned was already refactored.
| .into(); | ||
| let increment_note_fee = AssetAmount::new(max_fee_per_transaction(verification_base_fee)) | ||
| .expect("the per-transaction fee bound fits an asset amount"); | ||
| let mut fee_schedule = vec![(increment_script.root(), increment_note_fee)]; |
There was a problem hiding this comment.
nit: I think the whole function would be a bit more readable if we were using more concrete types instead of having mut variables, (e.g., BasicConstantFeePolicy::new().with_fee(...), etc.)
There was a problem hiding this comment.
Continuing with this, would be nice to have an CounterNetworkAcc type or something similar that generalizes this logic. This can also have different initializers depending on the network (e.g., CounterNetworkAcc::new_with_fees(...))
There was a problem hiding this comment.
Continuing with this, would be nice to have an CounterNetworkAcc type or something similar that generalizes this logic. This can also have different initializers depending on the network (e.g., CounterNetworkAcc::new_with_fees(...))
This is no longer needed since I removed the branching.
nit: I think the whole function would be a bit more readable if we were using more concrete types instead of having mut variables, (e.g., BasicConstantFeePolicy::new().with_fee(...), etc.)
Replaced the mut with:
let fee_schedule = [
(increment_script.root(), increment_note_fee),
(FeeSponsorshipNote::script_root(), AssetAmount::ZERO),
(P2idNote::script_root(), AssetAmount::ZERO),
];
let allowed_scripts = BTreeSet::from(fee_schedule.map(|(root, _)| root));
| allowed_scripts.insert(FeeSponsorshipNote::script_root()); | ||
| fee_schedule.push((FeeSponsorshipNote::script_root(), AssetAmount::ZERO)); | ||
| allowed_scripts.insert(P2idNote::script_root()); | ||
| fee_schedule.push((P2idNote::script_root(), AssetAmount::ZERO)); |
There was a problem hiding this comment.
Do we need P2ID support? I think fee sponsorship notes should be enough to cover the ntx fees
There was a problem hiding this comment.
Ah actually I think we need it for deploying the account and not necessarily for the network txs, right? This happened in the client integration tests and I think the solution was similar. I meant to ask @mmagician or maybe @partylikeits1983 if there were any other simpler ways to deploy network accounts.
To state the problem clearly: the developer of the account needs to deploy the network account through a transaction, and this transaction needs to pay for fees. You can't use a sponsorship note because it needs to be tied to a feature note, which means your best option (other than developing a new, custom note) is to add a basic wallet + P2ID support for the network account. Is this expected? Seems a bit overkill for only one transaction, but maybe the expectation is that all accounts should do this regardless. If this is the case, then I think the P2ID note root should be allowed by default in the auth component (as done with the other script roots). cc @bobbinth
EDIT: Actually thinking more about this, in this case we should be able to consume an increment counter note plus its FeeSponsorshipNote? But those funds need to come from somewhere.
There was a problem hiding this comment.
I tried it and it worked. It makes a bit more complex the deployment and messes a bit with the counter which makes us to offset in some places. If you think that the approach is worth anyways I can push it.
| if verification_base_fee > 0 { | ||
| builder = builder.with_component(BasicWallet); | ||
| } |
There was a problem hiding this comment.
Similar to the other comment, I don't think we need wallet support in the account. If for some reason we do need it, I think it'd be fine to always include the component
| self.client.clone(), | ||
| self.rpc_url.clone(), | ||
| self.funding.clone(), | ||
| self.interval, | ||
| self.probe_tx.clone(), | ||
| self.name.clone(), |
There was a problem hiding this comment.
I was following where the FeeFunding was being created to be passed to the services and realized that it seems like mostly all of these parameters are derived from MonitorConfig. The new FeeFunding parameter goes through a lot of functions too. Could these functions just take MonitorConfig instead? Or maybe there could be different config structs derived for each service.
There was a problem hiding this comment.
I like this and it is correct, but we probably need to do it as a follow up and apply the same pattern in all the monitor tasks, since this is a repeated pattern. Wdyt?
|
|
||
| /// Requests fee tokens from the faucet for the monitor's accounts. | ||
| #[derive(Clone, Debug)] | ||
| pub struct FeeFunding { |
There was a problem hiding this comment.
nit: Would FaucetClient describe this better?
| let last_error = match request_tokens( | ||
| &self.client, | ||
| &self.url, | ||
| &self.account_id, | ||
| MINT_AMOUNT, | ||
| self.solve_timeout, | ||
| ) | ||
| .await |
There was a problem hiding this comment.
Could this use the FeeFunding code instead?
| pub async fn fund( | ||
| &self, | ||
| rpc_client: &mut RpcClient, | ||
| account_id: AccountId, | ||
| fee_faucet_id: AccountId, | ||
| amount: u64, | ||
| ) -> Result<Note> { |
There was a problem hiding this comment.
I wonder if fee_faucet_id could be a field of FeeFunding and it could do the asset ID check internally. Similarly with teh rpc_client it could be nice if the FeeFunding struct could have its own instance, but maybe this does not work for some other reason.
There was a problem hiding this comment.
FaucetClient stays as the HTTP client and added FeeFunder to bind it to the RPC client and the genesis fee faucet ID, so fund() now takes just an account and an amount
Mirko-von-Leipzig
left a comment
There was a problem hiding this comment.
Not a solid review from me; but I think perhaps that's okay, its not super critical. We'll pick up issues I'm sure.
Closes #2450
Summary
On fee-charging chains the monitor now funds its accounts from the faucet (reusing the existing PoW token-request flow) and keeps itself funded:
FEE_SPONSORSHIPnote that pays for the network transaction consuming it. It also allowlists the sponsorship and P2ID scripts and carriesBasicWallet(as does the wallet, to consume P2ID notes).--faucet-urlfails the monitor at startupMainnet, which has no faucet, is a follow-up.
Also in this PR:
0.16.0-rc.4to0.16.0-rc.6(version pins only, no code changes needed).TEsted it against a live local stack (fee-enabled genesis, base fee 500) with the faucet from 0xMiden/faucet#289: funding, deployment, increments with sponsorships, and automatic top-up all worked end to end.
Changelog