novasamatech / substrate-sdk-android

Native Android SDK for developing client apps for Substrate-based networks
https://novawallet.io
Apache License 2.0
12 stars 7 forks source link

IllegalStateException: Type Address was not found. #84

Closed efeint01 closed 6 months ago

efeint01 commented 6 months ago
fun ExtrinsicBuilder.transfer(
    recipientAccountId: ByteArray,
    amount: BigInteger
): ExtrinsicBuilder {
    return call(
        moduleName = "Balances",
        callName = "transfer",
        arguments = mapOf(
            "dest" to DictEnum.Entry(
                name = "Id",
                value = "340a806419d5e278172e45cb0e50da1b031795366c99ddfe0a680bd53b142c63".fromHex()
            ),
            "value" to amount
        )
    )
}

val extrinsic = extBuilder.transfer(keypair.publicKey, BigInteger.TEN).build() -> Throws (IllegalStateException: Type Address was not found.)
val result = socketService.executeAsync(SubmitExtrinsicRequest(extrinsic)).result
Log.e("TAG", "testQuery: $result" )
efeint01 commented 6 months ago

Websocket connection is successful, We're getting this error on while running funds transfer function.

extrinsic = extBuilder.transfer(keypair.publicKey, BigInteger.TEN).build()

Full Error:

java.lang.IllegalStateException: Type Address was not found.
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205)
                                                                                                        at android.os.Looper.loop(Looper.java:294)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8177)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
                                                                                                    Caused by: java.lang.IllegalStateException: Type Address was not found.
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypeRegistryExtKt.getOrThrow(TypeRegistryExt.kt:8)
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.definitions.types.instances.AddressInstanceConstructor.constructInstance(AddressInstanceConstructor.kt:16)
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.definitions.types.instances.AddressInstanceConstructor.constructInstance(AddressInstanceConstructor.kt:13)
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.extrinsic.ExtrinsicBuilder.buildEncodableAddressInstance(ExtrinsicBuilder.kt:195)
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.extrinsic.ExtrinsicBuilder.build(ExtrinsicBuilder.kt:129)
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.extrinsic.ExtrinsicBuilder.build(ExtrinsicBuilder.kt:94)
                                                                                                        at jp.co.soramitsu.fearless_utils.runtime.extrinsic.ExtrinsicBuilder.build$default(ExtrinsicBuilder.kt:90)
valentunn commented 6 months ago

For better analysis please provide the following:

  1. Type file you are using (particular piece with "Address" type)
  2. How do you construct RuntimeSnapshot
efeint01 commented 6 months ago

Typefile details: typefile.json image

Related code:

suspend fun testQuery(context: Context) {
    val reconnector = Reconnector(strategy = ConstantReconnectStrategy(1000L))
    val requestExecutor = RequestExecutor()
    val socketService = SocketService(
        Gson(),
        StdoutLogger,
        WebSocketFactory(),
        reconnector,
        requestExecutor,
    )

    socketService.start(websocketUrl)

    val blockchainService = BlockchainService()
    val runtime = blockchainService.buildRuntimeV14(context)

    val keypair = SubstrateKeypairFactory.generate(EncryptionType.SR25519, ByteArray(32))

    val extBuilder = ExtrinsicBuilder(
        runtime = runtime,
        signer = KeyPairSigner(
            keypair = keypair,
            encryption = MultiChainEncryption.Substrate(EncryptionType.SR25519)
        ),
        nonce = 0.toBigInteger(),
        runtimeVersion = RuntimeVersion(103, 1),
        accountId = keypair.publicKey.publicKeyToSubstrateAccountId(),
        genesisHash = "0xbc6eb9753e2417476601485f9f8ef8474701ec199d456f989bd397682c9425c5".fromHex()
    )

    fun ExtrinsicBuilder.transfer(
        recipientAccountId: ByteArray,
        amount: BigInteger
    ): ExtrinsicBuilder {
        return call(
            moduleName = "Balances",
            callName = "transfer",
            arguments = mapOf(
                "dest" to DictEnum.Entry(
                    name = "Id",
                    value = "340a806419d5e278172e45cb0e50da1b031795366c99ddfe0a680bd53b142c63".fromHex()
                ),
                "value" to amount
            )
        )
    }

    val extrinsic = extBuilder.transfer(keypair.publicKey, BigInteger.TEN).build()
    val result = socketService.executeAsync(SubmitExtrinsicRequest(extrinsic)).result
    Log.e("TAG", "testQuery: $result")
}
valentunn commented 6 months ago

Please share code of buildRuntimeV14. In general, missing Address type means that you dont actually apply the additional types file. There are two ways to fix it:

  1. Update to 1.11.2 or higher - in that case you most probably wont even need any type file since SDK will infer all needed types automatically
  2. Ensure you are parasing types and passing the result to TypeRegsitry constructor, example
efeint01 commented 6 months ago

I've updated sdk version to 2.0.1 (latest version) -Here is buildRuntimeV14 code

class BlockchainService {
    fun buildRuntimeV14(context: Context, networkName: String = "network"): RuntimeSnapshot {
        val gson = Gson()

        val metadataRaw = buildRawMetadata(context, networkName)

        val metadataTypePreset =
            TypesParserV14.parse(metadataRaw.metadata[RuntimeMetadataSchemaV14.lookup], v14Preset())

        val networkTypesReader = JsonReader(context.getResourceReader(R.raw.typefile))

        val networkTypesTree =
            gson.fromJson<TypeDefinitionsTree>(networkTypesReader, TypeDefinitionsTree::class.java)

        val completeTypes =
            TypeDefinitionParser.parseBaseDefinitions(networkTypesTree, metadataTypePreset)

        val typeRegistry = TypeRegistry(
            types = completeTypes,
            dynamicTypeResolver = DynamicTypeResolver(
                DynamicTypeResolver.DEFAULT_COMPOUND_EXTENSIONS + GenericsExtension
            )
        )
        val metadata = VersionedRuntimeBuilder.buildMetadata(metadataRaw, typeRegistry)

        return RuntimeSnapshot(typeRegistry, metadata)
    }

    private fun Context.getResourceReader(@RawRes resId: Int): BufferedReader {
        val inputStream: InputStream = resources.openRawResource(resId)
        return BufferedReader(InputStreamReader(inputStream))
    }

    private fun Context.getFileContentFromAssets(fileName: String): String {
        return assets.open(fileName).bufferedReader().use { it.readText() }
    }

    fun buildRawMetadata(context: Context, networkName: String = "metadata") =
        context.getFileContentFromAssets("metadata").run {
            RuntimeMetadataReader.read(this)
        }
}
valentunn commented 6 months ago

If you have updated to 2.0.1 please try to just supply v14Preset() to TypeRegistry constructor without even parsing and passing the types.json file. I think the file itself might contain issues (e.g. not sure what MultiAddress type referes to)

Not passing the types file means SDK will try only types inferred from the metadata and in most cases (at least in 70+ networks we support in Nova) it dervives everything needed

efeint01 commented 6 months ago

Thank you for your reply, Now im only passing v14Preset() while building typeregistry:

        val typeRegistry = TypeRegistry(
            types = v14Preset(),
            dynamicTypeResolver = DynamicTypeResolver(
                DynamicTypeResolver.DEFAULT_COMPOUND_EXTENSIONS + GenericsExtension
            )
        )

but gotIllegalArgumentException: Cannot construct StorageEntryType from io.novasama.substrate_sdk_android.scale.EncodableStruct@a3bdc75

This error comes from while building metadata: val metadata = VersionedRuntimeBuilder.buildMetadata(metadataRaw, typeRegistry)

Full code:

class BlockchainService {
    fun buildRuntimeV14(context: Context, networkName: String = "network"): RuntimeSnapshot {
        val gson = Gson()

        val metadataRaw = buildRawMetadata(context, networkName)

        val metadataTypePreset =
            TypesParserV14.parse(metadataRaw.metadata[RuntimeMetadataSchemaV14.lookup], v14Preset())

        val networkTypesReader = JsonReader(context.getResourceReader(R.raw.typefile))

        val networkTypesTree =
            gson.fromJson<TypeDefinitionsTree>(networkTypesReader, TypeDefinitionsTree::class.java)

        val completeTypes =
            TypeDefinitionParser.parseBaseDefinitions(networkTypesTree, metadataTypePreset)

        val typeRegistry = TypeRegistry(
            types = v14Preset(),
            dynamicTypeResolver = DynamicTypeResolver(
                DynamicTypeResolver.DEFAULT_COMPOUND_EXTENSIONS + GenericsExtension
            )
        )

        val metadata = VersionedRuntimeBuilder.buildMetadata(metadataRaw, typeRegistry)

        return RuntimeSnapshot(typeRegistry, metadata)
    }

    private fun Context.getResourceReader(@RawRes resId: Int): BufferedReader {
        val inputStream: InputStream = resources.openRawResource(resId)
        return BufferedReader(InputStreamReader(inputStream))
    }

    private fun Context.getFileContentFromAssets(fileName: String): String {
        return assets.open(fileName).bufferedReader().use { it.readText() }
    }

    fun buildRawMetadata(context: Context, networkName: String = "metadata") =
        context.getFileContentFromAssets("metadata").run {
            RuntimeMetadataReader.read(this)
        }
}

Full Error:

java.lang.IllegalArgumentException: Cannot construct StorageEntryType from io.novasama.substrate_sdk_android.scale.EncodableStruct@a3bdc75
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205)
                                                                                                        at android.os.Looper.loop(Looper.java:294)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8177)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
                                                                                                    Caused by: java.lang.IllegalArgumentException: Cannot construct StorageEntryType from io.novasama.substrate_sdk_android.scale.EncodableStruct@a3bdc75
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.V14RuntimeBuilder.cannotConstructStorageEntry(V14RuntimeBuilder.kt:268)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.V14RuntimeBuilder.buildEntryType(V14RuntimeBuilder.kt:227)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.V14RuntimeBuilder.buildStorage(V14RuntimeBuilder.kt:105)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.V14RuntimeBuilder.buildModule(V14RuntimeBuilder.kt:81)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.V14RuntimeBuilder.buildModules(V14RuntimeBuilder.kt:66)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.V14RuntimeBuilder.buildMetadata(V14RuntimeBuilder.kt:56)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.VersionedRuntimeBuilder.buildMetadata(RuntimeBuilder.kt:26)
                                                                                                        at io.novasama.substrate_sdk_android.runtime.metadata.builder.RuntimeBuilder$DefaultImpls.buildMetadata$default(RuntimeBuilder.kt:14)
                                                                                                        at com.sweb.wallet.BlockchainService.buildRuntimeV14(MainActivity.kt:163)
                                                                                                        at com.sweb.wallet.BlockchainService.buildRuntimeV14$default(MainActivity.kt:140)
                                                                                                        at com.sweb.wallet.MainActivityKt.testQuery(MainActivity.kt:199)
                                                                                                        at com.sweb.wallet.TestRun$callCoroutine$1.invokeSuspend(MainActivity.kt:86)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                        at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
                                                                                                        at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
                                                                                                        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
                                                                                                        at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
                                                                                                        at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
                                                                                                        at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
                                                                                                        at com.sweb.wallet.TestRun.callCoroutine(MainActivity.kt:85)
                                                                                                        at com.sweb.wallet.TestRun.<init>(MainActivity.kt:81)
                                                                                                        at com.sweb.wallet.MainActivity.onCreate(MainActivity.kt:73)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8595)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8573)
                                                                                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922) 
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96) 
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443) 
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205) 
                                                                                                        at android.os.Looper.loop(Looper.java:294) 
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8177) 
                                                                                                        at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 
valentunn commented 6 months ago

Please share the minimum reproducable example (it should be self-contained, to be able to run it in the test):

  1. It should contain a metadata file you are using
  2. Please describe how you obtained the metadata stored in the file. In general it is not good idea to store in in the hard-coded file since it might change with chain update
  3. Please also provide the node URL we can connect and investigate futher
efeint01 commented 6 months ago

Since in the examples loading metadata using hardcoded file, How we can obtain metadata with connecting node websocket?

valentunn commented 6 months ago

Please try the following code to fetch & construct runtime snapshot from the latest chain state:

 private suspend fun SocketService.fetchRuntimeSnapshot(): RuntimeSnapshot {
        val metadataHex = stateGetMetadata()
        val metadataReader = RuntimeMetadataReader.read(metadataHex)

        val types = TypesParserV14.parse(
            lookup = metadataReader.metadata[RuntimeMetadataSchemaV14.lookup],
            typePreset = v14Preset(),
        )

        val typeRegistry = TypeRegistry(types, DynamicTypeResolver(DynamicTypeResolver.DEFAULT_COMPOUND_EXTENSIONS + GenericsExtension))
        val runtimeMetadata = VersionedRuntimeBuilder.buildMetadata(metadataReader, typeRegistry)

        return RuntimeSnapshot(typeRegistry, runtimeMetadata)
    }

suspend fun SocketService.stateGetMetadata(): String {
    return executeAsync(GetMetadataRequest, mapper = pojo<String>().nonNull())
}
efeint01 commented 6 months ago

I can get socket: start log but metadata log doesn't get printed.

suspend fun testQuery() {
    val reconnector = Reconnector(strategy = ConstantReconnectStrategy(1000L))
    val requestExecutor = RequestExecutor()
    val socketService = SocketService(
        Gson(),
        StdoutLogger,
        WebSocketFactory(),
        reconnector,
        requestExecutor,
    )

    val websocketUrl = "wss://commune.api.onfinality.io/public-ws"
    socketService.start(websocketUrl)
    Log.d("TAG", "socket: start" )

    val metadataHex = socketService.executeAsync(GetMetadataRequest, mapper = pojo<String>().nonNull())
    Log.d("TAG", "metadata: $metadataHex")

    val metadataReader = RuntimeMetadataReader.read(metadataHex)
    val types = TypesParserV14.parse(
        lookup = metadataReader.metadata[RuntimeMetadataSchemaV14.lookup],
        typePreset = v14Preset(),
    )

    val typeRegistry = TypeRegistry(types, DynamicTypeResolver(DynamicTypeResolver.DEFAULT_COMPOUND_EXTENSIONS + GenericsExtension))
    val runtimeMetadata = VersionedRuntimeBuilder.buildMetadata(metadataReader, typeRegistry)

    val runtime = RuntimeSnapshot(typeRegistry, runtimeMetadata)
    Log.d("TAG", "runtime: created $runtime")
}
valentunn commented 6 months ago

After debugging it for some time - there seems to be a bug that prevents response to be propagated when socket doesn't have a response interceptor set. Try setting an interceptor which always returns ResponseDelivery.DELIVER_TO_SENDER (via socket.setInterceptor) We will fix it in the next version

efeint01 commented 6 months ago

Socket service worked but we're got error Caused by: io.novasama.substrate_sdk_android.runtime.definitions.types.errors.EncodeDecodeException: null (null) is not a valid instance of (Alias)

While building extrinsic: val extrinsic = extBuilder.build()

    val extBuilder = ExtrinsicBuilder(
        runtime = runtime,
        signer = KeyPairSigner(
            keypair = keypair,
            encryption = MultiChainEncryption.Substrate(EncryptionType.SR25519)
        ),
        nonce = Nonce.singleTx(1.toBigInteger()),
        runtimeVersion = RuntimeVersion(103, 1),
        accountId = keypair.publicKey,
        genesisHash = "0xbc6eb9753e2417476601485f9f8ef8474701ec199d456f989bd397682c9425c5".fromHex()
    )

    extBuilder.call(
        moduleName = "SubspaceModule",
        callName = "add_stake",
        arguments = mapOf(
            "netuid" to 0.toBigInteger(),
            "moduleKey" to SS58Encoder.decode("5EhxqnrHHFy32DhcaqYrWiwC82yDiVS4xySysGxsUn462nX2"),
            "amount" to 1.toBigInteger()
        )
    )

    val extrinsic = extBuilder.build()

    val res = socketService.executeAsync(SubmitExtrinsicRequest(extrinsic)).result
    Log.d("TAG", "testQuery: $res")
    Log.d("TAG", "Runtime: $runtime") // Log the runtime for testing
valentunn commented 6 months ago

Please do not put everything into single issue. If original problem is solved please close this issue and open a new one, with the new problem. Closing this one as the issue was solved

Regarding the next problem - seems like you either not passing one of the arguments to the call or you misspelled argument name for one of those you passed. Most likely "moduleKey" should be "module_key". Or else check other arguments