pallet-treasury: Ensure we respect max_amount for spend across batch calls (#13468)

* `pallet-treasury`: Ensure we respect `max_amount` for spend across batch calls

When calling `spend` the origin defines the `max_amount` of tokens it is allowed to spend. The
problem is that someone can send a `batch(spend, spend)` to circumvent this restriction as we don't
check across different calls that the `max_amount` is respected. This pull request fixes this
behavior by introducing a so-called dispatch context. This dispatch context is created once per
outer most `dispatch` call. For more information see the docs in this pr. The treasury then uses
this dispatch context to attach information about already spent funds per `max_amount` (we assume
that each origin has a different `max_amount` configured). So, a `batch(spend, spend)` is now
checked to stay inside the allowed spending bounds.

Fixes: https://github.com/paritytech/substrate/issues/13167

* Import `Box` for wasm

* FMT
This commit is contained in:
Bastian Köcher
2023-02-27 18:49:16 +01:00
committed by GitHub
parent 85a5a5db13
commit 6aa4127a74
9 changed files with 353 additions and 24 deletions
@@ -333,22 +333,24 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
self,
origin: Self::RuntimeOrigin
) -> #frame_support::dispatch::DispatchResultWithPostInfo {
match self {
#(
Self::#fn_name { #( #args_name_pattern, )* } => {
#frame_support::sp_tracing::enter_span!(
#frame_support::sp_tracing::trace_span!(stringify!(#fn_name))
);
#maybe_allow_attrs
<#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* )
.map(Into::into).map_err(Into::into)
#frame_support::dispatch_context::run_in_context(|| {
match self {
#(
Self::#fn_name { #( #args_name_pattern, )* } => {
#frame_support::sp_tracing::enter_span!(
#frame_support::sp_tracing::trace_span!(stringify!(#fn_name))
);
#maybe_allow_attrs
<#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* )
.map(Into::into).map_err(Into::into)
},
)*
Self::__Ignore(_, _) => {
let _ = origin; // Use origin for empty Call enum
unreachable!("__PhantomItem cannot be used.");
},
)*
Self::__Ignore(_, _) => {
let _ = origin; // Use origin for empty Call enum
unreachable!("__PhantomItem cannot be used.");
},
}
}
})
}
}