You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a limit on maximum receipt size, it should ensure that all receipts have size below max_receipt_size (currently 4MiB). It was added in #11492.
The limit is implemented as a check in validate_receipt:
/// Validates a given receipt. Checks validity of the Action or Data receipt.pub(crate)fn validate_receipt(limit_config:&LimitConfig,receipt:&Receipt,current_protocol_version:ProtocolVersion,) -> Result<(),ReceiptValidationError>{let receipt_size:u64 =
borsh::to_vec(receipt).unwrap().len().try_into().expect("Can't convert usize to u64");if receipt_size > limit_config.max_receipt_size{returnErr(ReceiptValidationError::ReceiptSizeExceeded{size: receipt_size,limit: limit_config.max_receipt_size,});}
validate_receipt is run for every new receipt that is created and receipts that are too large are rejected:
if new_result.result.is_ok(){ifletErr(e) = new_result.new_receipts.iter().try_for_each(|receipt| {validate_receipt(&apply_state.config.wasm_config.limit_config,
receipt,
apply_state.current_protocol_version,)}){
new_result.result = Err(ActionErrorKind::NewReceiptValidationError(e).into());}}
But there is a problem - a new receipt can be modified after the validation is done.
For example, new output_data_receivers can be added:
// Generating outgoing data// A {// B().then(C())} B--data receipt->C// A {// B(); 42}if !action_receipt.output_data_receivers.is_empty(){ifletOk(ReturnData::ReceiptIndex(receipt_index)) = result.result{// Modifying a new receipt instead of sending datamatch result
.new_receipts.get_mut(receipt_index asusize).expect("the receipt for the given receipt index should exist").receipt_mut(){ReceiptEnum::Action(refmut new_action_receipt)
| ReceiptEnum::PromiseYield(refmut new_action_receipt) => new_action_receipt
.output_data_receivers.extend_from_slice(&action_receipt.output_data_receivers),
_ => unreachable!("the receipt should be an action receipt"),}}
It's possible to create a receipt which passes validate_receipt, but then adding output_data_receivers causes it to go above the size limit. Later the modified receipt is validated again (as an incoming receipt) and the validation fails, which causes runtime to panic. The panic makes sense, as we don't expect invalid receipts in the incoming receipts set, the validation check is a sanity check. The problem is that the receipt was allowed to go above the max allowed size.
This issue is already mitigated on 2.3.1 (60687b8) and 2.4.0 (1b2565b). I'll make a PR to master soon.
The text was updated successfully, but these errors were encountered:
Description
There is a limit on maximum receipt size, it should ensure that all receipts have size below
max_receipt_size
(currently 4MiB). It was added in #11492.The limit is implemented as a check in
validate_receipt
:validate_receipt
is run for every new receipt that is created and receipts that are too large are rejected:But there is a problem - a new receipt can be modified after the validation is done.
For example, new
output_data_receivers
can be added:It's possible to create a receipt which passes
validate_receipt
, but then addingoutput_data_receivers
causes it to go above the size limit. Later the modified receipt is validated again (as an incoming receipt) and the validation fails, which causes runtime to panic. The panic makes sense, as we don't expect invalid receipts in the incoming receipts set, the validation check is a sanity check. The problem is that the receipt was allowed to go above the max allowed size.This issue is already mitigated on
2.3.1
(60687b8) and2.4.0
(1b2565b). I'll make a PR tomaster
soon.The text was updated successfully, but these errors were encountered: