Unsigned transactions should include some ValidateUnsigned
logic which is used in the transaction queue to determine if an unsigned transaction should even be included in the block.
You can find an example of that here for the Claims Pallet: https://github.com/paritytech/polkadot/blob/master/runtime/common/src/claims.rs#L467
#[pallet::validate_unsigned]
impl<T: Config> ValidateUnsigned for Pallet<T> {
type Call = Call<T>;
fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity {
// Verification logic here.
// Must be lightweight so it does not take any significant weight,
// else a transaction spammer could attack this chain.
Ok(ValidTransaction {
priority: PRIORITY,
requires: vec![],
provides: vec![("claims", signer).encode()],
longevity: TransactionLongevity::max_value(),
propagate: true,
})
}
}
This validate_unsigned
function must be very lightweight since it will be processed for every unsigned transaction which matches the verification logic.
But ultimately, if you do not have an appropriate validate_unsigned
logic, then yes, your chain can totally be filled up by unsigned transactions. So unsigned transactions are only appropriate where you can guarantee how many of them there will be that is valid, and that it wont DDOS your chain
Two examples:
- Allow up to N unsigned transaction per block. Reject the rest until the next block.
- Allow up to N users 1 free unsigned transaction. After which, the unsigned transaction is not valid anymore. (This is what happens in claims pallet)