How to set the default value for StorageValue? - substrate

I am trying set default value for StorageValue, but its giving error:
#[pallet::type_value]
pub fn DefaultRegistrationFees<T: Config>() -> u128 { 100u128 }
#[pallet::storage]
#[pallet::getter(fn profile_registration_fees)]
pub type RegistrationFee<T> = StorageValue<_, u128, OptionQuery, DefaultRegistrationFees<T>>;
Error:
lib.rs(81, 12): the trait frame_support::storage::types::QueryKindTrait<u128, pallet::DefaultRegistrationFees<T>> is not implemented for frame_support::pallet_prelude::OptionQuery
https://substrate.dev/docs/en/knowledgebase/runtime/storage#default-values

I guess you want to write:
pub type RegistrationFee<T> = StorageValue<_, u128, ValueQuery, DefaultRegistrationFees<T>>;
So to use a ValueQuery instead of OptionQuery.
the QueryKind generic of the storage determine how the storage should be handled when there is no value in storage. With OptionQuery, when no value is in storage the method get will return None. With ValueQuery, when no value is in storage the method get will return the value configured with the generic OnEmpty.
So when configuring a specific default, you want to use ValueQuery.

Related

How to serialize anchor instruction from non-anchor contract

I am trying to invoke Anchor-contract from a regular solana contract and i am keep getting the error
Program log: AnchorError occurred. Error Code: InstructionMissing. Error Number: 100. Error Message: 8 byte instruction identifier not provided.
This is my instruction
#[derive(Debug, BorshDeserialize, BorshSerialize, PartialEq)]
pub enum ConfigInstruction {
Initialize,
}
pub fn initialize(
program_id: &Pubkey,
config: &Pubkey,
authority: &Pubkey,
) -> Instruction {
let accounts = vec![
AccountMeta::new(*config, true),
AccountMeta::new(*authority, true),
AccountMeta::new_readonly(system_program::id(), false),
];
Instruction::new_with_borsh(
*program_id,
&ConfigInstruction::Initialize,
accounts,
)
}
Seems like anchor is waiting a 8-byte long encoded instruction. While borsh serializes it to a vector with size 1. Any idea what am i doing wrong?
Really took some time to sort this out. Posting so this might be helpful for someone else.
So in order to use anchor's instruction for non-anchor contract you need to import InstructionData trait
use anchor_lang::InstructionData;
You instructions will be available using
use your_anchor_program::instruction::CamelCaseInstructionName
Create instruction as usual
Instruction {
program_id: *program_id,
accounts: vec![
...
],
data: CamelCaseInstructionName.data(),
}

Creating alias for a pandera type: DataFrame with particular pandera schema

I want to define a type to be a DataFrame with a particular pandera schema. However, when I lint this code:
from pandera.typing import DataFrame, Series
class MySchema(pa.SchemaModel):
foo: Series[str]
MyDF = DataFrame[MySchema]
def myfun(df: MyDF) -> bool:
return True
I get
myproject: myfile.py: note: In function "myfun":
myproject: myfile.py:10:15: error: Variable "myproject.myproject.myfile.MyDF" is not valid as a type [valid-type]
I understand I can avoid this error by specifying df: DataFrame[MySchema] in the signature of myfun instead. Is there some way I can define the alias MyDF in a valid manner?

Golang kubernetes client - patching an existing resource with a label

I want to patch an existing secret resource within Kubernetes. The object is called centos-secretstorage within the default namespace. I want to add a simple label of test: empty. However, this fails when the secret object centos-secretstorage exists, but it doesn't have any existing labels. If I manually label the secret with something else beforehand via kubectl label centos-secretstorage hello=world, and rerun my golang code. It is able to add the test: empty label successfully.
However, I want to have this be able to add a label regardless if existing labels exist or not.
type secret struct {
namespace string
name string
}
func main() {
k8sClient := k8CientInit()
vaultSecret := secret{
namespace: "default",
name: "centos-secretstorage",
}
vaultSecret.patchSecret(k8sClient)
}
type patchStringValue struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value"`
}
func (p *secret) patchSecret(k8sClient *kubernetes.Clientset) {
emptyPayload := []patchStringValue{{
Op: "add",
Path: "/metadata/labels/test",
Value: "empty",
}}
emptyPayloadBytes, _ := json.Marshal(emptyPayload)
fmt.Println(string(emptyPayloadBytes))
emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.JSONPatchType, emptyPayloadBytes)
if emptyerr != nil {
log.Fatal(emptyerr.Error())
}
fmt.Println(emptyres.Labels)
}
Error: the server rejected our request due to an error in our request
The problem is that the add operation in the JSON patch strategy requires the path to point to an existing map, while the object you are patching does not have this map at all. This is why when any label exists, the patch succeeds. We can work around this by using a different patch strategy. I think the merge strategy should work well.
I was able to reproduce this (on a namespace, but the object doesn't matter) using kubectl (which is generally useful when debugging the Kubernetes API):
kubectl patch ns a --type='json' -p='[{"op": "merge", "path": "/metadata/labels/test", "value":"empty"}]' -> fails
kubectl patch ns a --type='merge' -p='{"metadata": {"labels": {"test": "empty"}}}' -> succeeds
Using Golang client-go it would look something like this (didn't actually compile / run this):
payload := `{"metadata": {"labels": {"test": "empty"}}}`
emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.MergePatchType, []byte(payload))
You can make the creation of the payload JSON nicer using structs, as you did with patchStringValue.
More info on patch strategies can be found here:
https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
https://erosb.github.io/post/json-patch-vs-merge-patch/

Where is my GenesisConfig entry for my config storage?

I'm trying to reconstruct the Sudo module's root key behaviour before I extend it. Following the v1 documentation on GenesisConfig, I have a config() storage variable in my decl_storage:
RootKey get(fn rootkey) config(): T::AccountId;
(in the node-template template.rs for now)
Yet, if I look at the macro-expanded output, I have no template item in the GenesisConfig struct, and I cannot put in an entry like the following in the chain_spec's testnet_genesis function
template: Some(TemplateConfig {
rootkey: root_key,
}),
Because I get a complaint about both template and TemplateConfig, even though both are supposed to be constructed by the macro expansion.
Edit: Specifically, if it add the above with a TemplateConfig item in the use runtime::{} list, I am informed:
error[E0432]: unresolved import `runtime::TemplateConfig`
--> node-template/src/chain_spec.rs:4:14
|
4 | SudoConfig, TemplateConfig, IndicesConfig, SystemConfig, WASM_BINARY, Signature
| ^^^^^^^^^^^^^^ no `TemplateConfig` in the root
error[E0560]: struct `node_template_runtime::GenesisConfig` has no field named `template`
--> node-template/src/chain_spec.rs:142:3
|
142 | template: Some(TemplateConfig {
| ^^^^^^^^ `node_template_runtime::GenesisConfig` does not have this field
|
= note: available fields are: `system`, `aura`, `grandpa`, `indices`, `balances`, `sudo`
I also don't see any template items in polkadot.js under storage, whereas I do see sudo's key().
What obvious thing am I missing?
When trying to set up the genesis configuration for a runtime module you need to do the following:
Make sure your runtime module has "configurable storage items". This could be as simple as setting config() in the decl_storage! macro, but could also be a bit more complicated as documented here: `decl_storage! - GenesisConfig.
decl_storage! {
trait Store for Module<T: Trait> as Sudo {
Key get(fn key) config(): T::AccountId;
//--------------^^^^^^^^---------------
}
}
This will generate a GenesisConfig in your module, which will be used in the next step.
Next you need to expose your module specific GenesisConfig struct to the rest of your runtime's genesis configuration by adding the Config/Config<T> item to your construct_runtime! macro. In this example, we use Config<T> because we are configuring a generic T::AccountId:
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
//--snip--
TemplateModule: template::{Module, Call, Storage, Event<T>, Config<T>},
//----------------------------------------------------------^^^^^^^^^--
}
}
This will generate an alias to your module specific GenesisConfig object based on the name you configured for your module (name + Config). In this case, the name of the object will be TemplateModuleConfig.
Finally, you need to configure this storage item in the chain_spec.rs file. To do this, make sure to import the TemplateModuleConfig item:
use node_template_runtime::{
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig,
SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, Signature,
TemplateModuleConfig,
//--^^^^^^^^^^^^^^^^^^^^
};
And then configure your genesis information:
template: Some(TemplateModuleConfig {
key: root_key,
}),
It sounds like you're missing use TemplateConfig at the beginning of your chain_spec.rs file. Something like this https://github.com/substrate-developer-hub/substrate-node-template/blob/8fea1dc6dd0c5547117d022fd0d1bf49868ee548/src/chain_spec.rs#L4
If this is not your issue please supply the exact error you're getting, and optionally a link to the full code.

Is it possible to read an SRML error message in Substrate UI, when a transaction fails?

I am not sure of the behaviour of error messages in Substrate runtimes in relation to Substrate UI, and if they inherently cause a transaction failure or not.
For example in the democracy SRML I see the following line:
ensure!(!<Cancellations<T>>::exists(h), "cannot cancel the same proposal twice");
Which presumably is a macro that ensures that the transaction fails or stops processing if the h (the proposal hash) already exists. There is clearly a message associated with this error.
Am I right to assume that the transaction fails (without the rest of the SRML code being executed) when this test fails?
If so, how do I detect the failure in Substrate UI, and possibly see the message itself?
If not, then presumably some further code is necessary in the runtime module which explicitly creates an error. I have seen Err() - but not in conjunction with ensure!()
As https://github.com/paritytech/substrate/pull/3433 is merged, the ExtrinsicFailed event now includes a DispatchError, which will provide additional error code.
There isn't much documentations available so I will just use system module as example.
First you need to decl_error, note the error variants can only be simple C like enum
https://github.com/paritytech/substrate/blob/5420de3face1349a97eb954ae71c5b0b940c31de/srml/system/src/lib.rs#L334
decl_error! {
/// Error for the System module
pub enum Error {
BadSignature,
BlockFull,
RequireSignedOrigin,
RequireRootOrigin,
RequireNoOrigin,
}
}
Then you need to associate the declared Error type
https://github.com/paritytech/substrate/blob/5420de3face1349a97eb954ae71c5b0b940c31de/srml/system/src/lib.rs#L253
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error;
Then you can just return your Error in dispatch calls when things failed
https://github.com/paritytech/substrate/blob/5420de3face1349a97eb954ae71c5b0b940c31de/srml/system/src/lib.rs#L543
pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), Error>
where OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>>
{
match o.into() {
Ok(RawOrigin::Root) => Ok(()),
_ => Err(Error::RequireRootOrigin),
}
}
Right now you will only able to see a two numbers, module index and error code from JS side. Later there could be support to include the error details in metadata so that frontend will be able to provide a better response.
Related issue:
https://github.com/paritytech/substrate/issues/2954
The ensure! macro is expaneded as:
#[macro_export]
macro_rules! fail {
( $y:expr ) => {{
return Err($y);
}}
}
#[macro_export]
macro_rules! ensure {
( $x:expr, $y:expr ) => {{
if !$x {
$crate::fail!($y);
}
}}
}
So basically, it's just a quicker way to return Err. At 1.0, the error msg will only be printed to stdout(at least what I've tested so far), doesn't know if it'll be included in blockchain in the future(so can be viewed in substrate ui)..

Resources