From 11225600c10ca4995f9808758f7e094ae169fe8a Mon Sep 17 00:00:00 2001 From: valentunn <70131744+valentunn@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:36:24 +0300 Subject: [PATCH] Feature/generic signed extensions (#62) * Rework signed extensions * Code style * Bump versions * Comments * Handle nonce as struct * Handle nonce as struct * update image link * change to using install workflow * Force older version of log * change install dep fix spelling push cargo toml change location fix syntax remove fmt remove semicolon from expression remove directory switching adding ndk change installation action and add crago-c fix syntax remove cargo-c return toolchain back try to install libgcc fix syntx adding sudo update version of image remove toolchain update version return installation through action decrease version try to install target separatelly fix shell add gcc-multilib fix syntax change to macos install all libraries fix syntax E: Unable to locate package lib32ncurses5 try to fix libgcc problem change to stable version adding aarch64-linux-android * update other actions * remove debug info * remove additional libraries --------- Co-authored-by: Stepan Lavrentev --- .github/workflows/android.yml | 9 +-- .github/workflows/install/action.yml | 32 ++++++++ .github/workflows/release.yml | 21 +++-- .github/workflows/stage.yml | 21 +++-- .gitignore | 5 ++ build.gradle | 2 +- .../definitions/registry/TypePreset.kt | 2 +- .../definitions/types/composite/Alias.kt | 5 ++ .../definitions/types/composite/Struct.kt | 7 ++ .../definitions/types/composite/Tuple.kt | 8 ++ .../types/generics/DefaultSignedExtensions.kt | 26 +++++++ .../definitions/types/generics/Extrinsic.kt | 14 +--- .../types/generics/ExtrinsicExt.kt | 12 --- .../types/generics/ExtrinsicPayloadExtras.kt | 76 +++++++++---------- .../definitions/types/generics/Null.kt | 6 ++ .../v14/typeMapping/SiTypeMapping.kt | 28 ++++++- .../runtime/extrinsic/ExtrinsicBuilder.kt | 54 +++++++------ .../runtime/extrinsic/signer/Signer.kt | 4 +- .../runtime/extrinsic/signer/SignerExt.kt | 10 ++- .../runtime/metadata/RuntimeMetadata.kt | 28 ++++++- .../metadata/builder/RuntimeBuilder.kt | 15 +++- .../metadata/builder/V13RuntimeBuilder.kt | 26 +++++-- .../metadata/builder/V14RuntimeBuilder.kt | 18 ++++- .../types/generics/ExtrinsicTest.kt | 12 +-- .../types/generics/SignedExtrasTest.kt | 57 ++++++++------ .../runtime/extrinsic/ExtrinsicBuilderTest.kt | 9 +-- sr25519-java/Cargo.toml | 1 + sr25519-java/src/lib.rs | 2 +- 28 files changed, 337 insertions(+), 173 deletions(-) create mode 100644 .github/workflows/install/action.yml create mode 100644 fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/DefaultSignedExtensions.kt diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 4e55f3ff..efdb7b27 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -5,17 +5,14 @@ on: jobs: test: - runs-on: ubuntu-latest - container: - image: ghcr.io/nova-wallet/build_tools:pr-5 - credentials: - username: stepanLav - password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v2 + - name: 🔧 Install dependencies + uses: ./.github/workflows/install/ + - name: Lint run: ./gradlew ktlint diff --git a/.github/workflows/install/action.yml b/.github/workflows/install/action.yml new file mode 100644 index 00000000..0e4c1dfc --- /dev/null +++ b/.github/workflows/install/action.yml @@ -0,0 +1,32 @@ +name: Install dependencies for Android build +description: Contains all dependencies for Android build +runs: + using: "composite" + steps: + - name: ☕️ Install Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '8' + cache: 'gradle' + + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r21d + local-cache: true + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt, clippy + + - name: Add targets + run: | + rustup target add armv7-linux-androideabi + rustup target add i686-linux-android + rustup target add x86_64-linux-android + rustup target add aarch64-linux-android + shell: bash diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a2a73a39..ecd65e58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,24 +4,23 @@ on: release: types: [released] +env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} + jobs: build: runs-on: ubuntu-latest - container: - image: ghcr.io/nova-wallet/build_tools:pr-5 - credentials: - username: stepanLav - password: ${{ secrets.GITHUB_TOKEN }} - env: - OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} - SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} steps: - uses: actions/checkout@v2 + - name: 🔧 Install dependencies + uses: ./.github/workflows/install/ + - name: Kotlin linter run: ./gradlew ktlint diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index ce5cbca4..c2fa2ffa 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -5,24 +5,23 @@ on: branches: - "develop" +env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} + jobs: build: runs-on: ubuntu-latest - container: - image: ghcr.io/nova-wallet/build_tools:pr-5 - credentials: - username: stepanLav - password: ${{ secrets.GITHUB_TOKEN }} - env: - OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} - SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} steps: - uses: actions/checkout@v2 + - name: 🔧 Install dependencies + uses: ./.github/workflows/install/ + - name: Kotlin linter run: ./gradlew ktlint diff --git a/.gitignore b/.gitignore index 0987d220..d3f985a3 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,8 @@ app/*.apk *.lock /sr25519-java/target /sr25519-java/.idea + + +# Added by cargo + +/target diff --git a/build.gradle b/build.gradle index 40326cc1..4581b38f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext { // App version - versionName = '1.8.0' + versionName = '1.9.0' versionCode = 1 // SDK and tools diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/TypePreset.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/TypePreset.kt index b5b8cf43..0eada6c4 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/TypePreset.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/TypePreset.kt @@ -133,7 +133,7 @@ fun v13Preset(): TypePreset = typePreset { type(Bytes) type(BitVec) - type(Extrinsic.Default) + type(Extrinsic) type(CallBytes) // seems to be unused in runtime type(EraType) diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Alias.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Alias.kt index fc0bf046..706dd51e 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Alias.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Alias.kt @@ -3,6 +3,7 @@ package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite import io.emeraldpay.polkaj.scale.ScaleCodecReader import io.emeraldpay.polkaj.scale.ScaleCodecWriter import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference @@ -23,3 +24,7 @@ class Alias(alias: String, val aliasedReference: TypeReference) : Type(ali override val isFullyResolved: Boolean get() = aliasedReference.isResolved() } + +fun RuntimeType<*, *>.aliasedAs(newName: String): Alias { + return Alias(newName, TypeReference(this)) +} diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Struct.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Struct.kt index f2d88e12..6e334e3b 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Struct.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Struct.kt @@ -3,6 +3,7 @@ package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite import io.emeraldpay.polkaj.scale.ScaleCodecReader import io.emeraldpay.polkaj.scale.ScaleCodecWriter import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliases @@ -44,3 +45,9 @@ class Struct( override val isFullyResolved: Boolean get() = mapping.all { (_, ref) -> ref.isResolved() } } + +fun RuntimeType<*, *>.isEmptyStruct(): Boolean { + val asStruct = skipAliases() as? Struct ?: return false + + return asStruct.mapping.isEmpty() +} diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Tuple.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Tuple.kt index 19df0cbc..6a4cda13 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Tuple.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Tuple.kt @@ -3,8 +3,10 @@ package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite import io.emeraldpay.polkaj.scale.ScaleCodecReader import io.emeraldpay.polkaj.scale.ScaleCodecWriter import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliases import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliasesOrNull class Tuple(name: String, val typeReferences: List) : Type>(name) { @@ -36,3 +38,9 @@ class Tuple(name: String, val typeReferences: List) : Type.isEmptyTuple(): Boolean { + val asTuple = skipAliases() as? Tuple ?: return false + + return asTuple.typeReferences.isEmpty() +} diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/DefaultSignedExtensions.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/DefaultSignedExtensions.kt new file mode 100644 index 00000000..32690a8f --- /dev/null +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/DefaultSignedExtensions.kt @@ -0,0 +1,26 @@ +package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics + +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.Compact +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u32 +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata.Companion.onlyAdditional +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata.Companion.onlySigned + +object DefaultSignedExtensions { + + const val CHECK_MORTALITY = "CheckMortality" + const val CHECK_NONCE = "CheckNonce" + const val CHECK_TX_PAYMENT = "ChargeTransactionPayment" + const val CHECK_GENESIS = "CheckGenesis" + const val CHECK_SPEC_VERSION = "CheckSpecVersion" + const val CHECK_TX_VERSION = "CheckTxVersion" + + val ALL = listOf( + SignedExtensionMetadata(CHECK_MORTALITY, type = EraType, additionalSigned = H256), + onlySigned(CHECK_NONCE, Compact("Compact")), + onlySigned(CHECK_TX_PAYMENT, Compact("Compact")), + onlyAdditional(CHECK_GENESIS, H256), + onlyAdditional(CHECK_SPEC_VERSION, u32), + onlyAdditional(CHECK_TX_VERSION, u32), + ) +} diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Extrinsic.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Extrinsic.kt index 95d0c3d5..dbc4d517 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Extrinsic.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Extrinsic.kt @@ -18,14 +18,8 @@ private val SIGNED_MASK = 0b1000_0000.toUByte() private const val TYPE_ADDRESS = "Address" private const val TYPE_SIGNATURE = "ExtrinsicSignature" -class Extrinsic( - val signedExtrasType: ExtrinsicPayloadExtras = SignedExtras.default -) : - RuntimeType("ExtrinsicsDecoder") { - - companion object { - val Default = Extrinsic() - } +@OptIn(ExperimentalUnsignedTypes::class) +object Extrinsic : RuntimeType("ExtrinsicsDecoder") { class EncodingInstance( val signature: Signature?, @@ -71,7 +65,7 @@ class Extrinsic( Signature( accountIdentifier = addressType(runtime).decode(scaleCodecReader, runtime), signature = signatureType(runtime).decode(scaleCodecReader, runtime), - signedExtras = signedExtrasType.decode(scaleCodecReader, runtime) + signedExtras = SignedExtras.decode(scaleCodecReader, runtime) ) } else { null @@ -113,7 +107,7 @@ class Extrinsic( val addressBytes = addressType(runtime).bytes(runtime, signature.accountIdentifier) val signatureBytes = signatureType(runtime).bytes(runtime, signature.signature) - val signedExtrasBytes = signedExtrasType.bytes(runtime, signature.signedExtras) + val signedExtrasBytes = SignedExtras.bytes(runtime, signature.signedExtras) addressBytes + signatureBytes + signedExtrasBytes } else { diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicExt.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicExt.kt index f76034d6..89440c1c 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicExt.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicExt.kt @@ -2,7 +2,6 @@ package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics import jp.co.soramitsu.fearless_utils.encrypt.EncryptionType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum -import jp.co.soramitsu.fearless_utils.runtime.extrinsic.SignedExtension class MultiSignature(val encryptionType: EncryptionType, val value: ByteArray) @@ -16,17 +15,6 @@ fun Extrinsic.Signature.tryExtractMultiSignature(): MultiSignature? { return MultiSignature(encryptionType, value) } -fun Extrinsic.Companion.create(customSignedExtensions: Collection): Extrinsic { - val customSignedExtensionTypes = customSignedExtensions.associateBy( - keySelector = { it.name }, - valueTransform = { it.type } - ) - - val allSignedExtensions = SignedExtras.default.extras + customSignedExtensionTypes - - return Extrinsic(ExtrinsicPayloadExtras(allSignedExtensions)) -} - private val EncryptionType.multiSignatureName get() = rawName.capitalize() diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicPayloadExtras.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicPayloadExtras.kt index a0bdfbaa..992b1c51 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicPayloadExtras.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicPayloadExtras.kt @@ -3,47 +3,32 @@ package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics import io.emeraldpay.polkaj.scale.ScaleCodecReader import io.emeraldpay.polkaj.scale.ScaleCodecWriter import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.Compact -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u32 +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.isEmptyStruct +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.isEmptyTuple +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionId +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata -object SignedExtras { +object SignedExtras : ExtrinsicPayloadExtras("ExtrinsicPayloadExtras.SignedExtras") { - const val MORTALITY = "CheckMortality" - const val NONCE = "CheckNonce" - const val TIP = "ChargeTransactionPayment" - - val default = ExtrinsicPayloadExtras( - mapOf( - MORTALITY to EraType, - NONCE to Compact("Compact"), - TIP to Compact("Compact") - ) - ) + override fun getTypeFrom(signedExtension: SignedExtensionMetadata): Type<*>? { + return signedExtension.type + } } -object AdditionalExtras { - - const val GENESIS = "CheckGenesis" - const val SPEC_VERSION = "CheckSpecVersion" - const val TX_VERSION = "CheckTxVersion" - const val BLOCK_HASH = SignedExtras.MORTALITY - - val default = ExtrinsicPayloadExtras( - mapOf( - BLOCK_HASH to H256, - GENESIS to H256, - SPEC_VERSION to u32, - TX_VERSION to u32 - ) - ) +object AdditionalSignedExtras : + ExtrinsicPayloadExtras("ExtrinsicPayloadExtras.AdditionalSignedExtras") { + override fun getTypeFrom(signedExtension: SignedExtensionMetadata): Type<*>? { + return signedExtension.additionalSigned + } } -typealias ExtrinsicPayloadExtrasInstance = Map +typealias ExtrinsicPayloadExtrasInstance = Map + +abstract class ExtrinsicPayloadExtras(name: String) : Type(name) { -class ExtrinsicPayloadExtras( - val extras: Map> -) : Type("ExtrinsicPayloadExtras") { + protected abstract fun getTypeFrom(signedExtension: SignedExtensionMetadata): Type<*>? override fun decode( scaleCodecReader: ScaleCodecReader, @@ -51,9 +36,12 @@ class ExtrinsicPayloadExtras( ): ExtrinsicPayloadExtrasInstance { val enabledSignedExtras = runtime.metadata.extrinsic.signedExtensions - return enabledSignedExtras.associateWith { name -> - extras[name]?.decode(scaleCodecReader, runtime) - } + return enabledSignedExtras.associateBy( + keySelector = { it.id }, + valueTransform = { signedExtension -> + getTypeFrom(signedExtension)?.decode(scaleCodecReader, runtime) + } + ) } override fun encode( @@ -63,8 +51,13 @@ class ExtrinsicPayloadExtras( ) { val enabledSignedExtras = runtime.metadata.extrinsic.signedExtensions - return enabledSignedExtras.forEach { name -> - extras[name]?.encodeUnsafe(scaleCodecWriter, runtime, value[name]) + return enabledSignedExtras.forEach { signedExtension -> + getTypeFrom(signedExtension)?.let { type -> + if (!shouldSkipEncoding(type)) { + val signedExtensionValue = value[signedExtension.id] + type.encodeUnsafe(scaleCodecWriter, runtime, signedExtensionValue) + } + } } } @@ -73,4 +66,11 @@ class ExtrinsicPayloadExtras( override fun isValidInstance(instance: Any?): Boolean { return instance is Map<*, *> && instance.keys.all { it is String } } + + private fun shouldSkipEncoding(type: RuntimeType<*, *>): Boolean { + // this is for better backward-compatibility - + // clients might pass null instead of empty struct / empty tuple that are specified in + // RuntimeMetadata.signedExtensions v14 + return type.isNullType() || type.isEmptyStruct() || type.isEmptyTuple() + } } diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Null.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Null.kt index 84220452..74fcf551 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Null.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Null.kt @@ -3,7 +3,9 @@ package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics import io.emeraldpay.polkaj.scale.ScaleCodecReader import io.emeraldpay.polkaj.scale.ScaleCodecWriter import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.Primitive +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliases object Null : Primitive("Null") { @@ -19,3 +21,7 @@ object Null : Primitive("Null") { return instance == null } } + +fun RuntimeType<*, *>.isNullType(): Boolean { + return skipAliases() is Null +} diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/v14/typeMapping/SiTypeMapping.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/v14/typeMapping/SiTypeMapping.kt index 342fafd4..56c1ee9d 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/v14/typeMapping/SiTypeMapping.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/v14/typeMapping/SiTypeMapping.kt @@ -8,6 +8,8 @@ import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Alias import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Option import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.SetType +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.aliasedAs +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.EraType import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.DynamicByteArray import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.FixedByteArray import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u8 @@ -171,13 +173,37 @@ object SiByteArrayMapping : SiTypeMapping { } } +class ReplaceTypesSiTypeMapping( + vararg cases: Pair> +) : SiTypeMapping { + + companion object { + fun default(): SiTypeMapping { + return ReplaceTypesSiTypeMapping( + "sp_runtime.generic.era.Era" to EraType + ) + } + } + + private val casesById = cases.toMap() + + override fun map( + originalDefinition: EncodableStruct, + suggestedTypeName: String, + typesBuilder: TypePresetBuilder + ): Type<*>? { + return casesById[suggestedTypeName]?.aliasedAs(suggestedTypeName) + } +} + fun SiTypeMapping.Companion.default(): OneOfSiTypeMapping { return OneOfSiTypeMapping( listOf( SiByteArrayMapping, SiOptionTypeMapping, SiSetTypeMapping, - SiCompositeNoneToAliasTypeMapping + SiCompositeNoneToAliasTypeMapping, + ReplaceTypesSiTypeMapping.default(), ) ) } diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilder.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilder.kt index c1877bd3..73427d17 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilder.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilder.kt @@ -4,31 +4,30 @@ import jp.co.soramitsu.fearless_utils.encrypt.SignatureWrapper import jp.co.soramitsu.fearless_utils.runtime.AccountId import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.AdditionalExtras +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Struct +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.DefaultSignedExtensions import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Era import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Extrinsic import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Extrinsic.EncodingInstance.CallRepresentation import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.ExtrinsicPayloadExtrasInstance import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.GenericCall -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.SignedExtras -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.create import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.new import jp.co.soramitsu.fearless_utils.runtime.definitions.types.instances.AddressInstanceConstructor import jp.co.soramitsu.fearless_utils.runtime.definitions.types.instances.SignatureInstanceConstructor +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliases import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHexUntyped import jp.co.soramitsu.fearless_utils.runtime.extrinsic.signer.Signer import jp.co.soramitsu.fearless_utils.runtime.extrinsic.signer.SignerPayloadExtrinsic +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionId import jp.co.soramitsu.fearless_utils.runtime.metadata.call +import jp.co.soramitsu.fearless_utils.runtime.metadata.findSignedExtension import jp.co.soramitsu.fearless_utils.runtime.metadata.module import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain.RuntimeVersion import java.math.BigInteger private val DEFAULT_TIP = BigInteger.ZERO -class SignedExtension(val name: String, val type: Type<*>) - class ExtrinsicBuilder( val runtime: RuntimeSnapshot, private val nonce: BigInteger, @@ -39,15 +38,13 @@ class ExtrinsicBuilder( private val blockHash: ByteArray = genesisHash, private val era: Era = Era.Immortal, private val tip: BigInteger = DEFAULT_TIP, - private val customSignedExtensions: Map = emptyMap(), + private val customSignedExtensions: Map = emptyMap(), private val addressInstanceConstructor: RuntimeType.InstanceConstructor = AddressInstanceConstructor, private val signatureConstructor: RuntimeType.InstanceConstructor = SignatureInstanceConstructor ) { private val calls = mutableListOf() - private val extrinsicType = Extrinsic.create(customSignedExtensions.keys) - fun call( moduleIndex: Int, callIndex: Int, @@ -133,7 +130,7 @@ class ExtrinsicBuilder( callRepresentation = callRepresentation ) - return extrinsicType.toHex(runtime, extrinsic) + return Extrinsic.toHex(runtime, extrinsic) } private suspend fun buildSignature( @@ -141,7 +138,7 @@ class ExtrinsicBuilder( ): String { val multiSignature = buildSignatureObject(callRepresentation) - val signatureType = extrinsicType.signatureType(runtime) + val signatureType = Extrinsic.signatureType(runtime) return signatureType.toHexUntyped(runtime, multiSignature) } @@ -158,19 +155,18 @@ class ExtrinsicBuilder( val signedExtrasInstance = buildSignedExtras() val additionalExtrasInstance = mapOf( - AdditionalExtras.BLOCK_HASH to blockHash, - AdditionalExtras.GENESIS to genesisHash, - AdditionalExtras.SPEC_VERSION to runtimeVersion.specVersion.toBigInteger(), - AdditionalExtras.TX_VERSION to runtimeVersion.transactionVersion.toBigInteger() + DefaultSignedExtensions.CHECK_MORTALITY to blockHash, + DefaultSignedExtensions.CHECK_GENESIS to genesisHash, + DefaultSignedExtensions.CHECK_SPEC_VERSION to runtimeVersion.specVersion.toBigInteger(), + DefaultSignedExtensions.CHECK_TX_VERSION to runtimeVersion.transactionVersion.toBigInteger() ) val signerPayload = SignerPayloadExtrinsic( runtime = runtime, - extrinsicType = extrinsicType, accountId = accountId, call = callRepresentation, signedExtras = signedExtrasInstance, - additionalExtras = additionalExtrasInstance, + additionalSignedExtras = additionalExtrasInstance, ) val signatureWrapper = signer.signExtrinsic(signerPayload) @@ -197,14 +193,28 @@ class ExtrinsicBuilder( private fun buildSignedExtras(): ExtrinsicPayloadExtrasInstance { val default = mapOf( - SignedExtras.MORTALITY to era, - SignedExtras.TIP to tip, - SignedExtras.NONCE to nonce + DefaultSignedExtensions.CHECK_MORTALITY to era, + DefaultSignedExtensions.CHECK_TX_PAYMENT to tip, + DefaultSignedExtensions.CHECK_NONCE to encodeNonce(nonce) ) - val custom = customSignedExtensions.mapKeys { (extension, _) -> extension.name } + return default + customSignedExtensions + } + + private fun encodeNonce(nonce: BigInteger): Any { + val nonceExtension = runtime.metadata.extrinsic + .findSignedExtension(DefaultSignedExtensions.CHECK_NONCE) ?: return nonce - return default + custom + val nonceType = nonceExtension.type?.skipAliases() + + return when { + nonceType is Struct && nonceType.mapping.size == 1 -> { + val fieldName = nonceType.mapping.keys.single() + + Struct.Instance(mapOf(fieldName to nonce)) + } + else -> nonce + } } private fun requireNotMixingBytesAndInstanceCalls() { diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/Signer.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/Signer.kt index 2f497ecb..8accce9e 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/Signer.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/Signer.kt @@ -4,7 +4,6 @@ import jp.co.soramitsu.fearless_utils.encrypt.SignatureWrapper import jp.co.soramitsu.fearless_utils.extensions.fromHex import jp.co.soramitsu.fearless_utils.runtime.AccountId import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Extrinsic import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Extrinsic.EncodingInstance.CallRepresentation class SignerPayloadRaw( @@ -17,13 +16,12 @@ class SignerPayloadRaw( class SignerPayloadExtrinsic( val runtime: RuntimeSnapshot, - val extrinsicType: Extrinsic, val accountId: AccountId, val call: CallRepresentation, val signedExtras: Map, - val additionalExtras: Map + val additionalSignedExtras: Map ) fun SignerPayloadRaw.Companion.fromUtf8( diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/SignerExt.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/SignerExt.kt index 8304da05..e844357c 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/SignerExt.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/signer/SignerExt.kt @@ -2,9 +2,11 @@ package jp.co.soramitsu.fearless_utils.runtime.extrinsic.signer import io.emeraldpay.polkaj.scale.ScaleCodecWriter import jp.co.soramitsu.fearless_utils.hash.Hasher.blake2b256 -import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.AdditionalExtras +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.AdditionalSignedExtras +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.DefaultSignedExtensions import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Extrinsic import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.GenericCall +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.SignedExtras import jp.co.soramitsu.fearless_utils.runtime.definitions.types.useScaleWriter import jp.co.soramitsu.fearless_utils.scale.utils.directWrite @@ -28,8 +30,8 @@ fun SignerPayloadExtrinsic.encodeCallDataTo(writer: ScaleCodecWriter) { fun SignerPayloadExtrinsic.encodedCallData() = bytesOf(::encodeCallDataTo) fun SignerPayloadExtrinsic.encodeExtensionsTo(writer: ScaleCodecWriter) { - extrinsicType.signedExtrasType.encode(writer, runtime, signedExtras) - AdditionalExtras.default.encode(writer, runtime, additionalExtras) + SignedExtras.encode(writer, runtime, signedExtras) + AdditionalSignedExtras.encode(writer, runtime, additionalSignedExtras) } fun SignerPayloadExtrinsic.encodedExtensions() = bytesOf(::encodeExtensionsTo) @@ -50,4 +52,4 @@ fun SignerPayloadExtrinsic.encodedSignaturePayload(hashBigPayloads: Boolean = tr } val SignerPayloadExtrinsic.genesisHash - get() = additionalExtras[AdditionalExtras.GENESIS] as ByteArray + get() = additionalSignedExtras[DefaultSignedExtensions.CHECK_GENESIS] as ByteArray diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/RuntimeMetadata.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/RuntimeMetadata.kt index 4239c311..490989a4 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/RuntimeMetadata.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/RuntimeMetadata.kt @@ -1,5 +1,7 @@ package jp.co.soramitsu.fearless_utils.runtime.metadata +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.RuntimeType +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Null import jp.co.soramitsu.fearless_utils.runtime.metadata.module.Module import java.math.BigInteger @@ -17,5 +19,29 @@ class RuntimeMetadata( class ExtrinsicMetadata( val version: BigInteger, - val signedExtensions: List + val signedExtensions: List ) + +typealias SignedExtensionId = String + +class SignedExtensionMetadata( + val id: SignedExtensionId, + val type: RuntimeType<*, *>?, + val additionalSigned: RuntimeType<*, *>? +) { + + companion object { + + fun onlySigned(id: String, type: RuntimeType<*, *>): SignedExtensionMetadata { + return SignedExtensionMetadata(id, type, Null) + } + + fun onlyAdditional(id: String, additionalSigned: RuntimeType<*, *>): SignedExtensionMetadata { + return SignedExtensionMetadata(id, Null, additionalSigned) + } + } +} + +fun ExtrinsicMetadata.findSignedExtension(id: SignedExtensionId): SignedExtensionMetadata? { + return signedExtensions.find { it.id == id } +} diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/RuntimeBuilder.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/RuntimeBuilder.kt index 95897ea3..c92af083 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/RuntimeBuilder.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/RuntimeBuilder.kt @@ -1,23 +1,30 @@ package jp.co.soramitsu.fearless_utils.runtime.metadata.builder import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypeRegistry +import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.DefaultSignedExtensions import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadata import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadataReader +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata interface RuntimeBuilder { - fun buildMetadata(reader: RuntimeMetadataReader, typeRegistry: TypeRegistry): RuntimeMetadata + fun buildMetadata( + reader: RuntimeMetadataReader, + typeRegistry: TypeRegistry, + knownSignedExtensions: List = DefaultSignedExtensions.ALL, + ): RuntimeMetadata } object VersionedRuntimeBuilder : RuntimeBuilder { override fun buildMetadata( reader: RuntimeMetadataReader, - typeRegistry: TypeRegistry + typeRegistry: TypeRegistry, + knownSignedExtensions: List, ): RuntimeMetadata { return when (reader.metadataVersion) { - 14 -> V14RuntimeBuilder.buildMetadata(reader, typeRegistry) - else -> V13RuntimeBuilder.buildMetadata(reader, typeRegistry) + 14 -> V14RuntimeBuilder.buildMetadata(reader, typeRegistry, knownSignedExtensions) + else -> V13RuntimeBuilder.buildMetadata(reader, typeRegistry, knownSignedExtensions) } } } diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V13RuntimeBuilder.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V13RuntimeBuilder.kt index bbd56db2..bd876efa 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V13RuntimeBuilder.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V13RuntimeBuilder.kt @@ -15,6 +15,7 @@ import jp.co.soramitsu.fearless_utils.runtime.metadata.NMapSchema import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadata import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadataReader import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadataSchema +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata import jp.co.soramitsu.fearless_utils.runtime.metadata.StorageEntryMetadataSchema import jp.co.soramitsu.fearless_utils.runtime.metadata.StorageMetadataSchema import jp.co.soramitsu.fearless_utils.runtime.metadata.groupByName @@ -34,14 +35,18 @@ internal object V13RuntimeBuilder : RuntimeBuilder { override fun buildMetadata( reader: RuntimeMetadataReader, - typeRegistry: TypeRegistry + typeRegistry: TypeRegistry, + knownSignedExtensions: List ): RuntimeMetadata { val metadataStruct = reader.metadata require(metadataStruct.schema is RuntimeMetadataSchema) return RuntimeMetadata( - extrinsic = buildExtrinsic(metadataStruct[RuntimeMetadataSchema.extrinsic]), + extrinsic = buildExtrinsic( + struct = metadataStruct[RuntimeMetadataSchema.extrinsic], + knownSignedExtensions = knownSignedExtensions + ), modules = buildModules(metadataStruct[RuntimeMetadataSchema.modules], typeRegistry), runtimeVersion = reader.metadataVersion.toBigInteger() ) @@ -202,11 +207,18 @@ internal object V13RuntimeBuilder : RuntimeBuilder { } private fun buildExtrinsic( - struct: EncodableStruct - ) = ExtrinsicMetadata( - version = struct[ExtrinsicMetadataSchema.version].toInt().toBigInteger(), - signedExtensions = struct[ExtrinsicMetadataSchema.signedExtensions] - ) + struct: EncodableStruct, + knownSignedExtensions: List + ): ExtrinsicMetadata { + val knownSignedExtensionsById = knownSignedExtensions.associateBy { it.id } + + return ExtrinsicMetadata( + version = struct[ExtrinsicMetadataSchema.version].toInt().toBigInteger(), + signedExtensions = struct[ExtrinsicMetadataSchema.signedExtensions].mapNotNull { + knownSignedExtensionsById[it] + } + ) + } private fun cannotConstructStorageEntry(from: Any?): Nothing { throw IllegalArgumentException("Cannot construct StorageEntryType from $from") diff --git a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V14RuntimeBuilder.kt b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V14RuntimeBuilder.kt index dfc7910d..062494ec 100644 --- a/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V14RuntimeBuilder.kt +++ b/fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/V14RuntimeBuilder.kt @@ -11,6 +11,7 @@ import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.Null import jp.co.soramitsu.fearless_utils.runtime.metadata.ExtrinsicMetadata import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadata import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadataReader +import jp.co.soramitsu.fearless_utils.runtime.metadata.SignedExtensionMetadata import jp.co.soramitsu.fearless_utils.runtime.metadata.groupByName import jp.co.soramitsu.fearless_utils.runtime.metadata.module.Constant import jp.co.soramitsu.fearless_utils.runtime.metadata.module.Error @@ -40,14 +41,18 @@ object V14RuntimeBuilder : RuntimeBuilder { override fun buildMetadata( reader: RuntimeMetadataReader, - typeRegistry: TypeRegistry + typeRegistry: TypeRegistry, + knownSignedExtensions: List, ): RuntimeMetadata { val metadataStruct = reader.metadata require(metadataStruct.schema is RuntimeMetadataSchemaV14) return RuntimeMetadata( - extrinsic = buildExtrinsic(metadataStruct[RuntimeMetadataSchemaV14.extrinsic]), + extrinsic = buildExtrinsic( + metadataStruct[RuntimeMetadataSchemaV14.extrinsic], + typeRegistry + ), modules = buildModules(metadataStruct[RuntimeMetadataSchemaV14.pallets], typeRegistry), runtimeVersion = reader.metadataVersion.toBigInteger() ) @@ -242,11 +247,16 @@ object V14RuntimeBuilder : RuntimeBuilder { } private fun buildExtrinsic( - struct: EncodableStruct + struct: EncodableStruct, + typeRegistry: TypeRegistry, ) = ExtrinsicMetadata( version = struct[ExtrinsicMetadataV14.version].toInt().toBigInteger(), signedExtensions = struct[ExtrinsicMetadataV14.signedExtensions].map { - it[SignedExtensionMetadataV14.identifier] + SignedExtensionMetadata( + id = it[SignedExtensionMetadataV14.identifier], + type = typeRegistry[it[SignedExtensionMetadataV14.type].toString()], + additionalSigned = typeRegistry[it[SignedExtensionMetadataV14.additionalSigned].toString()] + ) } ) diff --git a/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicTest.kt b/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicTest.kt index 481458db..dac45146 100644 --- a/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicTest.kt +++ b/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ExtrinsicTest.kt @@ -27,7 +27,7 @@ class ExtrinsicTest { @Test fun `should decode transfer extrinsic`() { - val decoded = Extrinsic().fromHex(runtime, inHex) + val decoded = Extrinsic.fromHex(runtime, inHex) val multiSignature = decoded.signature!!.tryExtractMultiSignature()!! @@ -39,7 +39,7 @@ class ExtrinsicTest { val batch = "0x01038400fdc41550fb5186d71cae699c31731b3e1baa10680c7bd6b3831a6d222cf4d16800b2b0e48ec54dd07af525e605c2d674ef57eef7d9932c3ad16f68c1e41a18ce579a207aa910b22bcddcf0a2eea96d4617fe618dff95de548bbf53e1773416700815009000100008040000340a806419d5e278172e45cb0e50da1b031795366c99ddfe0a680bd53b142c630f0000c16ff28623040000340a806419d5e278172e45cb0e50da1b031795366c99ddfe0a680bd53b142c630f00106644db8723" - val decoded = Extrinsic().fromHex(runtime, batch) + val decoded = Extrinsic.fromHex(runtime, batch) assertEquals(16 to 0, decoded.call.function.index) assertEquals(2, (decoded.call.arguments["calls"] as List<*>).size) @@ -63,9 +63,9 @@ class ExtrinsicTest { ) val signedExtras = mapOf( - SignedExtras.TIP to 0.toBigInteger(), - SignedExtras.NONCE to 100.toBigInteger(), - SignedExtras.MORTALITY to Era.Mortal(64, 12) + DefaultSignedExtensions.CHECK_TX_PAYMENT to 0.toBigInteger(), + DefaultSignedExtensions.CHECK_NONCE to 100.toBigInteger(), + DefaultSignedExtensions.CHECK_MORTALITY to Era.Mortal(64, 12) ) val signature = SignatureInstanceConstructor.constructInstance( @@ -85,7 +85,7 @@ class ExtrinsicTest { callRepresentation = CallRepresentation.Instance(call) ) - val encoded = Extrinsic().toHex(runtime, extrinsic) + val encoded = Extrinsic.toHex(runtime, extrinsic) assertEquals(inHex, encoded) } diff --git a/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/SignedExtrasTest.kt b/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/SignedExtrasTest.kt index 670ddfcc..3bf2ebfb 100644 --- a/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/SignedExtrasTest.kt +++ b/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/SignedExtrasTest.kt @@ -36,30 +36,37 @@ class SignedExtrasTest { @Test fun `should encode full set of extras`() { - extrinsicContainsExtras(SignedExtras.MORTALITY, SignedExtras.NONCE, SignedExtras.TIP) + extrinsicContainsExtras( + DefaultSignedExtensions.CHECK_MORTALITY, + DefaultSignedExtensions.CHECK_NONCE, + DefaultSignedExtensions.CHECK_TX_PAYMENT + ) val extras = mapOf( - SignedExtras.TIP to BigInteger.ONE, - SignedExtras.NONCE to BigInteger.TEN, - SignedExtras.MORTALITY to Era.Immortal + DefaultSignedExtensions.CHECK_TX_PAYMENT to BigInteger.ONE, + DefaultSignedExtensions.CHECK_NONCE to BigInteger.TEN, + DefaultSignedExtensions.CHECK_MORTALITY to Era.Immortal ) - val encoded = SignedExtras.default.toHex(runtime, extras) + val encoded = SignedExtras.toHex(runtime, extras) assertEquals("0x002804", encoded) } @Test fun `should encode partial set of extras and ignore unused arguments`() { - extrinsicContainsExtras(SignedExtras.NONCE, SignedExtras.TIP) + extrinsicContainsExtras( + DefaultSignedExtensions.CHECK_NONCE, + DefaultSignedExtensions.CHECK_TX_PAYMENT + ) val extras = mapOf( - SignedExtras.TIP to BigInteger.ONE, - SignedExtras.NONCE to BigInteger.TEN, - SignedExtras.MORTALITY to Era.Immortal // CheckMortality is unused + DefaultSignedExtensions.CHECK_TX_PAYMENT to BigInteger.ONE, + DefaultSignedExtensions.CHECK_NONCE to BigInteger.TEN, + DefaultSignedExtensions.CHECK_MORTALITY to Era.Immortal // CheckMortality is unused ) - val encoded = SignedExtras.default.toHex(runtime, extras) + val encoded = SignedExtras.toHex(runtime, extras) assertEquals("0x2804", encoded) } @@ -70,47 +77,50 @@ class SignedExtrasTest { // all are unused val extras = mapOf( - SignedExtras.TIP to BigInteger.ONE, - SignedExtras.NONCE to BigInteger.TEN, - SignedExtras.MORTALITY to Era.Immortal + DefaultSignedExtensions.CHECK_TX_PAYMENT to BigInteger.ONE, + DefaultSignedExtensions.CHECK_NONCE to BigInteger.TEN, + DefaultSignedExtensions.CHECK_MORTALITY to Era.Immortal ) - val encoded = SignedExtras.default.toHex(runtime, extras) + val encoded = SignedExtras.toHex(runtime, extras) assertEquals("0x", encoded) } @Test fun `should require used extras`() { - extrinsicContainsExtras(SignedExtras.NONCE, SignedExtras.TIP) + extrinsicContainsExtras( + DefaultSignedExtensions.CHECK_NONCE, + DefaultSignedExtensions.CHECK_TX_PAYMENT + ) val extras = mapOf( - SignedExtras.TIP to BigInteger.ONE, + DefaultSignedExtensions.CHECK_TX_PAYMENT to BigInteger.ONE, ) assertThrows { - SignedExtras.default.toHex(runtime, extras) + SignedExtras.toHex(runtime, extras) } } @Test fun `should decode full set of extras`() { - extrinsicContainsExtras(SignedExtras.MORTALITY, SignedExtras.NONCE, SignedExtras.TIP) + extrinsicContainsExtras(DefaultSignedExtensions.CHECK_MORTALITY, DefaultSignedExtensions.CHECK_NONCE, DefaultSignedExtensions.CHECK_TX_PAYMENT) val inHex = "0x002804" - val decoded = SignedExtras.default.fromHex(runtime, inHex) + val decoded = SignedExtras.fromHex(runtime, inHex) assertEquals(decoded.size, 3) } @Test fun `should decode partial set of extras`() { - extrinsicContainsExtras(SignedExtras.NONCE, SignedExtras.TIP) + extrinsicContainsExtras(DefaultSignedExtensions.CHECK_NONCE, DefaultSignedExtensions.CHECK_TX_PAYMENT) val inHex = "0x2804" - val decoded = SignedExtras.default.fromHex(runtime, inHex) + val decoded = SignedExtras.fromHex(runtime, inHex) assertEquals(decoded.size, 2) } @@ -121,12 +131,13 @@ class SignedExtrasTest { val inHex = "0x" - val decoded = SignedExtras.default.fromHex(runtime, inHex) + val decoded = SignedExtras.fromHex(runtime, inHex) assertEquals(decoded.size, 0) } private fun extrinsicContainsExtras(vararg extras: String) { - `when`(extrinsicMetadata.signedExtensions).thenReturn(extras.toList()) + val signedExtensions = DefaultSignedExtensions.ALL.filter { it.id in extras } + `when`(extrinsicMetadata.signedExtensions).thenReturn(signedExtensions) } } \ No newline at end of file diff --git a/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilderTest.kt b/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilderTest.kt index bd2eb47a..acdd332d 100644 --- a/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilderTest.kt +++ b/fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilderTest.kt @@ -129,7 +129,7 @@ class ExtrinsicBuilderTest { } val encoded = extrinsicBuilder.build(useBatchAll = true) - val decoded = Extrinsic().fromHex(runtime, encoded) + val decoded = Extrinsic.fromHex(runtime, encoded) assertEquals(decoded.call.function.name, "batch_all") } @@ -157,11 +157,6 @@ class ExtrinsicBuilderTest { val extrinsicInHex = "0x45028400fdc41550fb5186d71cae699c31731b3e1baa10680c7bd6b3831a6d222cf4d1680045ba1f9d291fff7dddf36f7ec060405d5e87ac8fab8832cfcc66858e6975141748ce89c41bda6c3a84204d3c6f929b928702168ca38bbed69b172044b599a10ab5038800000a0000bcc5ecf679ebd776866a04c212a4ec5dc45cefab57d7aa858c389844e212693f0700e40b5402" - val chargeAssetTxPayment = SignedExtension( - name = "ChargeAssetTxPayment", - type = runtime.typeRegistry["pallet_asset_tx_payment.ChargeAssetTxPayment"]!! - ) - val builder = ExtrinsicBuilder( runtime = runtime, nonce = 34.toBigInteger(), @@ -171,7 +166,7 @@ class ExtrinsicBuilderTest { accountId = KEYPAIR.publicKey.publicKeyToSubstrateAccountId(), era = Era.Mortal(64, 59), customSignedExtensions = mapOf( - chargeAssetTxPayment to Struct.Instance( + "ChargeAssetTxPayment" to Struct.Instance( mapOf( "tip" to BigInteger.ZERO, "assetId" to null diff --git a/sr25519-java/Cargo.toml b/sr25519-java/Cargo.toml index 153027bb..98a1fbf7 100644 --- a/sr25519-java/Cargo.toml +++ b/sr25519-java/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] zeroize = { version="<=1.1.1" } zeroize_derive = { version="<=1.1.1" } +log = { version="<=0.4.11" } jni = { version = "0.17.0", default-features = false } schnorrkel = { version="<=0.9.1" } diff --git a/sr25519-java/src/lib.rs b/sr25519-java/src/lib.rs index 992405af..d514d20b 100644 --- a/sr25519-java/src/lib.rs +++ b/sr25519-java/src/lib.rs @@ -47,7 +47,7 @@ macro_rules! r#try_or_throw { macro_rules! r#try_or_throw_null { ($jni_env: ident, $expr:expr) => { - try_or_throw!($jni_env, $expr, ptr::null_mut()); + try_or_throw!($jni_env, $expr, ptr::null_mut()) } }