Open eskimor opened 1 year ago
My understanding is that bids would be regular Substrate extrinsics/transactions or possibly UnsignedTransaction
s with a special validate_unsigned
method, and we could use the standard extrinsic validation APIs to achieve all goals. We should be able to use the code that Substrate already has for TX queuing/pruning/invalidity checking
Fee calculation pallet: https://paritytech.github.io/substrate/master/pallet_transaction_payment/index.html More info: https://docs.substrate.io/build/tx-weights-fees/
Other forms of fees (bonds, deposits, ...) exist as well. Deposits will be needed for registering a CollatorId
.
Dispatch class for orders will be "normal". Classification can be dynamic.
Unsigned extriniscs need more care than signed extrinisics. E.g. CheckNonce
only exists for signed extrinsics.
Unsigned extrinsics are checked via ValidateUnsigned
.
Example implementation for claims. For slashing.
Tipping would also need to be implemented manually.
Signed extensions on Kusama:
let extra: SignedExtra = (
frame_system::CheckNonZeroSender::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckMortality::<Runtime>::from(generic::Era::mortal(
period,
current_block,
)),
frame_system::CheckNonce::<Runtime>::from(nonce),
frame_system::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
);
signed extensions can be used to define checks that all transactions need to pass. We would only need validation for our new extrinsic. If it is unsigned, this should be doable via ValidateUnsigned
above. For a signed extrinsic, this could work like this ... is there a better way? Actually: In the signed case we should not strictly require any additional validation: We can charge someone, so it is "valid" - even if not, we can accept and charge the account - so it is "valid" in the sense, that it is safe to put into a block.
For signed extrinsic which we can use in the proxy account scenario, we don't really need to worry about validation too much. The only things to figure out:
With an unsigned extrinsic we can provide our own ValidateUnsigned
implementation and use that to implement orders via CollatorId
. Full flexibility, but also no checks by default hence easier to get wrong. Above list (SignedExtra) provides some things like nonce, weight checks, ... we should consider for a
ValidateUnsigned` variant.
Actually: In the signed case we should not strictly require any additional validation: We can charge someone, so it is "valid" - even if not, we can accept and charge the account - so it is "valid" in the sense, that it is safe to put into a block.
Indeed. if the transaction has no effect the user still pays for the weight used. It's like making a balance transfer which transfers more funds than exist in the account. It's actually crucial for blockchains to be able to include such transactions, because it can create block author DoS if they must be discarded (block author spends time/resources that are not reflected in the block itself)
However, there is another concern here. It might be that well-meaning but under-bidding transactions are included too early. i.e. any time a collator issues a bid, the collator should expect to be charged for the weight of processing the bid on-chain. This actually disincentivizes bids which are nonsensical, as every bid carries a fixed cost, and should reduce spam.
How to implement such a secure proxy account.
Proxies are quite simple to implement, actually. There is a ProxyKind
enum defined in every runtime that uses the proxy pallet, and it implements CallFilter
or some similar trait that allows allowed call types by the proxy to be filtered.
Block producers need to be able to verify incoming bids in order to immediately reject invalid ones (and punish/disconnect peers providing them). We need some runtime API providing this functionality. Likely the call will accept a batch (vec/bounded vec) of bids and provides information on their validity (Likely just a bool, true for valid, false for invalid).
Something similar exists for transactions apparently: Draw inspiration from there, figure out what can be re-used.
A bid is valid for inclusion in the next block, if all of the following hold true:
ParaId
exists/has a registered PVF - (that has been pre-checked already?)ParaId
*)Obviously the same checks will be done on block import/block creation.
*) If not the sender is just wasting money: Paying for a core that is not usable, but this would mean that random people can make any parathread produce a block, which might not be desirable. Also if we limit the number of blocks to be be bid on at a given time per parathread, this could result in DoS (costly, but still): We might be able to punt on that one for a first run.