The treasury module's set_pot
function is dispatchable (declared in decl_module
) and doesn't seem to ensure anything about the origin. Doesn't that mean that anyone can unilaterally adjust the pot at any time?
My experience using the polkadot UI is that anyone can try to call this function but the extrinsic always fails. If it is meant only to be called from sudo or democracy or the like, why isn't it written lower in the impl Module
block?
If you declare a function without origin
as the first parameter in the decl_module!
macro, it will automatically assume that you are trying to declare a "privileged function": a function which requires Root
origin.
From the docs:
If the origin param is omitted, the macro adds it as the first parameter and adds ensure_root(origin) as the first line of the function. These functions are the same:
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn my_privileged_function() -> Result {
// Your implementation
Ok(())
}
fn my_function(origin) -> Result {
ensure_root(origin);
// Your implementation
Ok(())
}
}
}
Functions which require Root
origin should not be thought of like internal or private functions which are put in the impl
block. They should be thought of as "callable privileged functions" which basically does an authorization check that the extrinsic which calls the function must have the origin of Root
. You can think of it similar to the Sudo module which exposes two dispatchable functions, but only the "Sudo key" can successfully call those functions.
In the case of "privileged functions, only the runtime itself can produce a Root
origin extrinsic.
Functions which are dispatchable are inherently different than those "internal/private functions" in the impl block. For example, lets look at the set_pot
function you mentioned in the Treasury module.
This is a "privileged function" which can literally set the balance of the pot
to any number.
If this was an internal function, then yes, you could call it within other runtime functions and it would do what you would expect all within the internals of the runtime. But now let's say you wanted to set up a democratic vote to change the balance of the pot
for whatever reason. You would not be able to access this function since it is not exposed as a "callable" function from the module. So you would lose the ability for proposals to execute such logic.
The set_pot
function is made exactly the way it is because it is meant to be some low level privileged access to the Treasury module through a Root
extrinsic, as are the other Root
origin functions.