Skip to content
This repository has been archived by the owner on May 2, 2022. It is now read-only.

Getting Cannot construct unknown type Result error on deployment #52

Open
cmichi opened this issue Jan 25, 2021 · 3 comments
Open

Getting Cannot construct unknown type Result error on deployment #52

cmichi opened this issue Jan 25, 2021 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@cmichi
Copy link

cmichi commented Jan 25, 2021

When deploying this contract via the UI, the UI just displays this:

Uncaught error. Something went wrong with the query and rendering of this component. createType(Result):: Cannot construct unknown type Result

The console shows:

react.01.5ff66cee.js:2 Error: createType(Result):: Cannot construct unknown type Result
    at u (polkadot.01.dc51e7e6.js:1)
    at io (main.01be78c1.js:2)
    at main.01be78c1.js:2
    at Object.useMemo (react.01.5ff66cee.js:2)
    at t.useMemo (react.01.5ff66cee.js:2)
    at e (main.01be78c1.js:2)
    at Gi (react.01.5ff66cee.js:2)
    at xl (react.01.5ff66cee.js:2)
    at ps (react.01.5ff66cee.js:2)
    at ds (react.01.5ff66cee.js:2)

I think the reason is that the specific contract has this ink! message:

        /// Returns an error.
        #[ink(message)]
        pub fn return_err(&self) -> Result<()> {
            Err(Error::MyError)
        }
@cmichi cmichi added the bug Something isn't working label Jan 25, 2021
@kwingram25 kwingram25 self-assigned this Jan 26, 2021
@achimcc
Copy link

achimcc commented Jan 31, 2021

I debugged the error. The contract is sending a return message and then the UI does a lookup in the registry to dynamically infer the message type from it.

The message is carrying a returnType object of type TypeDef. This object is carrying both optional parameters type and displayName. When the UI tries to dynamically create the type from the given return type, it is trying to match the type of the message against the registry by using then displayName property, or at least it is prioritizing it in favor of the type property.

Changing the formatData function in the Data.tsx component from:

function formatData(registry: Registry, data: AnyJson, type: TypeDef | undefined): Codec {
  return createTypeUnsafe(type?.displayName || registry, type?.type || "Raw", [data]);
}

to

function formatData(registry: Registry, data: AnyJson, type: TypeDef | undefined): Codec {
  return createTypeUnsafe( registry, type?.type || type?.displayName || "Raw", [data]);
}

leads to a correct execution of the call.

However, I'm wondering if it makes any sense at all to infer the displayName for type creation?

@awolokita
Copy link

awolokita commented May 31, 2021

@achimcc I tool your suggested changes to formatData for a spin and found that while that worked, the subsequently returned ReactElement was not falling into the if statement for Option, thus returning a hexidecimal representation of the Codec.

The issue is due to value being checked against instanceof Option instead of codec. Changing references to value to codec results in the correct Some string being returned in a component.

The issue / fix is outlined below, with incorrect logic commented out and subsequent line showing the correct logic.

      // if (type.info === TypeDefInfo.Option && value instanceof Option) { <-- INCORRECT
        if (type.info === TypeDefInfo.Option && codec instanceof Option) {
        //const isSome = value.isSome;
        const isSome = codec.isSome;
        const subType = type.sub as TypeDef;

        if (asJson) {
          // return `${isSome ? 'Some' : 'None'}${isSome ? `(${value.toString()})` : ''}`; <-- INCORRECT
          return `${isSome ? 'Some' : 'None'}${isSome ? `(${codec.unwrap().toString()})` : ''}`;
        }

        return (
          <div className='enum'>
            {isSome ? 'Some' : 'None'}
            {isSome && (
              <>
                {'('}
                <div className='inner'>
                  <Data
                    registry={registry}
                    type={subType}
                    //value={value.toString()} <-- INCORRECT
                    value={codec.unwrap().toString()}
                  />
                </div>
                {')'}
              </>
            )}
          </div>
        );
      }

I'm happy to open a PR containing both your fix to formatData and my fix for Option, if no one else is looking at this issue.

@awolokita
Copy link

awolokita commented May 31, 2021

One more note regarding decoding Option.

The second thing that's done in function Data is

if (isNull(value) || (Array.isArray(value) && value.length === 0)) {
  return '()';
}

An Option that isNone has isNull(value) === true which then immediately returns () instead of going through the formatData and then returning the intended component.

Would it be safe to remove the check for null above and let formatData and the subsequent code do its thing?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants