Apps: Use multi-variant enum as an extrinsic parameter

Created on 28 Nov 2019  路  16Comments  路  Source: polkadot-js/apps

I'm having a problem with using multi-variant enum as an extrinsic parameter. In this example, my enum is ValueType and i'm trying to call set_enum which has ValueType enum as one of its parameters through polkadot js api. When the enum only has one variant (any of the 4), all works fine. I could also combine uint32 and uint64. However, the other combinations will report an error. For instance, when i tried having all 4 variants together, I could submit an extrinsic with uint32 and uint64, but using either Bool or Char32 will give me an error.

Enum

#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]
pub enum ValueType {
    Char32([u8; 32]),   
    Uint32(u32),
    Uint64(u64),
    Bool(bool),
}
        fn set_enum(origin, value: ValueType) -> Result {
            // Check if signed
            let sender = ensure_signed(origin)?;
            Ok(())
        }



md5-7b542fcdef953d659ddf40d758da4c72



api.tx.content
    .setEnum({
      char32: "0x12345678123456781234567812345678"
    })
    .signAndSend(alicePair, { nonce }, ({ events = [], status }) => { ... }



md5-481f5ca17d42ca3b7b1b55500ab7d014



2019-11-28 12:26:15        RPC-CORE: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1002: Verification Error: Execution(ApiError("Could not convert parameter `tx` between node and runtime: Error decoding field Call :: Content.0")): RuntimeApi("Execution(ApiError(\"
2019-11-28 12:26:15             DRR: Error: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1002: Verification Error: Execution(ApiError("Could not convert parameter `tx` between node and runtime: Error decoding field Call :: Content.0")): RuntimeApi("Execution(ApiError(\"
    at errorHandler (/Users/anakornk/Code/graph4w3/graph-js-sdk/node_modules/@polkadot/rpc-core/index.js:259:26)
    at /Users/anakornk/Code/graph4w3/graph-js-sdk/node_modules/@polkadot/rpc-core/index.js:233:9
    at processTicksAndRejections (internal/process/task_queues.js:82:5)

Seems like there is something wrong with the encoding/decoding part. Am i missing anything?

-size-s @react-params [bug]

All 16 comments

There really doesn't seem anything wrong above, well, not from what I can see. It should handle the enum correct. Like the u32 & u64, the [u8; 32] should work.

I would appreciate a quick test though, just to see if there is maybe a discrepancy as to how fixed vectors are handled. (Just as a starting point of trying to understand what is breaking and where)

Could you change the type signature for the enum to the following -

ValueType: { 
  Char32: "H256",
  Uint32: "u32",
  Uint64: "u64"
}

And then just test again with the Char32 as you have above. (The 2 types here are equivalent in size and codec representation, just want to see if at least part of it is a fixed vec issue.) This still doesn't explain why bool (which is just a single byte), also creates issues.

Definition of ValueType in Rust

#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]
pub enum ValueType {
    Char32(primitives::H256),   
    Uint32(u32),
    Uint64(u64),
}

Registering types on polkadot-js/api

     ValueType: {
        _enum: {
          Uint32: "u32",
          Uint64: "u64",
          Char32: "H256",
        }
      }

Re-ran the test again with Char32, got a different error this time:

2019-11-28 16:37:33        RPC-CORE: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1010: Invalid Transaction: BadProof
2019-11-28 16:37:33             DRR: Error: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1010: Invalid Transaction: BadProof
    at errorHandler (/Users/anakornk/Code/graph4w3/graph-js-sdk/node_modules/@polkadot/rpc-core/index.js:259:26)
    at /Users/anakornk/Code/graph4w3/graph-js-sdk/node_modules/@polkadot/rpc-core/index.js:233:9
    at processTicksAndRejections (internal/process/task_queues.js:82:5)

Also, tried testing uint64 and uint32 with the above config. Both no longer works now.

2019-11-28 16:44:24        RPC-CORE: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1002: Verification Error: Execution(ApiError("Could not convert parameter `tx` between node and runtime: Error decoding field Call :: Content.0")): RuntimeApi("Execution(ApiError(\"
2019-11-28 16:44:24             DRR: Error: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1002: Verification Error: Execution(ApiError("Could not convert parameter `tx` between node and runtime: Error decoding field Call :: Content.0")): RuntimeApi("Execution(ApiError(\"

I did some additional tests and tried only registering Char32 on the js side. It works.

      ValueType: {
        _enum: {
          // Uint32: "u32",
          // Uint64: "u64",
          Char32: "H256",
        }
      }

However, if i tried registering only uint32 or uint64, i get the same error as before:

2019-11-28 16:41:58        RPC-CORE: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1002: Verification Error: Execution(ApiError("Could not convert parameter `tx` between node and runtime: Error decoding field Call :: Content.0")): RuntimeApi("Execution(ApiError(\"

Thanks for the extensive play-through. Especially the last one is really interesting, it is like any tuple with multiple entries are doing something really, really weird here. (And they are used extensively even in the substrate/polkadot codebases, so this is, well, beyond weird)

Will have to dig around for some ideas. Atm, stumped.

Ahh, wait in your example you have this for Rust -

#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]
pub enum ValueType {
    Char32(primitives::H256),   
    Uint32(u32),
    Uint64(u64),
}

and then this on the JS side -

ValueType: {
        _enum: {
          Uint32: "u32",
          Uint64: "u64",
          Char32: "H256",
        }
      }

The ordering needs to match for enums, the index is used to encode the type following. So if you use the above Rust structure, your equivalent JS structure needs to be -

ValueType: {
    _enum: {
        Char32: 'H256', 
    Uint32: 'u32',
    Uint64: 'u64'
  }
}

So the way enums are encoded - the first byte indicates the index (0-based) and then the value follows.

Ahh, re-did all the tests, everything is working now. I thought i did tried changing the ordering. Thanks!


One last problem i had was with polkadot-js/apps. Not sure if it is the same issue as this one here: https://github.com/polkadot-js/apps/pull/1726
There is this react rendering problem when changing the enum variant in 'Extrinsics' tab. The screen just goes white.

backend.js:6 Error: Minified React error polkadot-js/api#185; visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

Would log the above in the apps repo, that is a bug.

Transferred, since there seems to be an Enum issue with params.

@anakornk Could you please paste the full console logs as to when this issue happens - that will aid in understanding why.

@jacogr
Here are the steps i did to reproduce the error.

  1. ValueType definition in rust.
#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]
pub enum ValueType {
    Char32([u8; 32]),   
    Uint64(u64),
    Bool(bool),
}
  1. Registered ValueType on Settings->Developer Tab
  "ValueType": {
    "_enum": {
      "Char32": "[u8; 32]",
      "Uint64": "u64",
      "Bool": "bool"
    }
  }
  1. When i chose the set_enum extrinsinc, a warning is shown. Everything still functions correctly.
Cannot find component for [u8;32], defaulting to Unknown
  1. When i change Char32 to either Uint64 or Bool, the whole screen goes white. The console logs the following 17 times
backend.js:6 Unable to determine default type for {"info":11,"name":"Char32","type":"[u8;32]","ext":{"length":32,"type":"u8"}}

Then ends with a react error

backend.js:6 Error: Minified React error #185; visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

image

Screen Shot 2019-11-30 at 00 06 51

There are notoriously hard to track down, however I have access to an unlaunched chain with a bunch of enums, nested and otherwise not.

Just have not had a gap in the last day, but this is high on the list to fix - first thing to do next.

@jacogr I think i've found the problem. It got to do with Dropdown.tsx in the react-components folder.
_onChange was called twice, once by the onChange handler and the other by the useEffect hook.
onChange handler first calls _onChange which updates the the state, which then calls the effect hook.

There is no value prop passed down by the EnumParam component, so value is undefined and newValue equals the old/default value. Hence, the second call by the effect hook rewrite the old value to the state causing the state to remain the same (cannot change the enum variant).

packages/react-components/src/Dropdown.tsx

 useEffect((): void => {
    const newValue = isUndefined(value)
      ? defaultValue
      : value;

    // only update parent if we have had something changed
    if (JSON.stringify({ v: newValue }) !== JSON.stringify({ v: stateValue })) {
      _onChange(null, { value: newValue });
    }
  }, [defaultValue, stateValue, value]);

I tried adding a condition so that the effect hook was not called when inside EnumParam. It fixed the white screen and can now submit extrinsics with multi-variant enum as a parameter.

Thank you. Feel free to make a PR, otherwise I'll do so in (my) morning and credit you :)

Thank you. Feel free to make a PR, otherwise I'll do so in (my) morning and credit you :)

I'm not quite sure what is the best way to fix the problem since i'm not quite familiar with the project yet. I passed down a prop from EnumParam. Maybe there're better ways to do it. Also, got to make sure that the effect will still be called to set the default value. Maybe it'll be better if you fix it, I can help you with testing :)

Will have a fix tomorrow morning EU time, will link here.

Sorry this has taken so long to get to it, was a bit snowed under with Kusama CC3 and supporting the latest Substrate master over the last 3 days.

Ok, based on my tests after #1964, I don't get crashes. Would appreciate a check.

After the latest fix, everything works fine.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

illlefr4u picture illlefr4u  路  4Comments

rrtti picture rrtti  路  6Comments

jacogr picture jacogr  路  5Comments

jacogr picture jacogr  路  7Comments

jacogr picture jacogr  路  3Comments