From 132aeb56f5eae077ecc6c339a819988f8f8c7734 Mon Sep 17 00:00:00 2001 From: valentunn <70131744+valentunn@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:34:56 +0300 Subject: [PATCH] Combine full extrinsic and signature creation (#96) * Reworked build extrinsic for consistency and convinience * Bump version * Code style --- build.gradle | 2 +- .../runtime/extrinsic/ExtrinsicBuilder.kt | 116 ++++++++---------- .../extrinsic/signer/SendableExtrinsic.kt | 8 ++ .../extrinsic/SendIntegrationTest.kt | 4 +- .../runtime/extrinsic/ExtrinsicBuilderTest.kt | 53 ++++---- 5 files changed, 87 insertions(+), 96 deletions(-) create mode 100644 substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/signer/SendableExtrinsic.kt diff --git a/build.gradle b/build.gradle index add2bf64..0f590510 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext { // App version - versionName = '2.1.4' + versionName = '2.2.0' versionCode = 1 // SDK and tools diff --git a/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilder.kt b/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilder.kt index 49ca9b71..072e0cd9 100644 --- a/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilder.kt +++ b/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilder.kt @@ -15,6 +15,7 @@ import io.novasama.substrate_sdk_android.runtime.definitions.types.instances.Add import io.novasama.substrate_sdk_android.runtime.definitions.types.instances.SignatureInstanceConstructor import io.novasama.substrate_sdk_android.runtime.definitions.types.toHex import io.novasama.substrate_sdk_android.runtime.definitions.types.toHexUntyped +import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.SendableExtrinsic import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.SignedExtrinsic import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.Signer import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.SignerPayloadExtrinsic @@ -87,12 +88,6 @@ class ExtrinsicBuilder( _customSignedExtensions[id] = value } - @Deprecated( - message = "Use restCalls() for better readability", - replaceWith = ReplaceWith(expression = "resetCalls()") - ) - fun reset(): ExtrinsicBuilder = resetCalls() - fun resetCalls(): ExtrinsicBuilder { calls.clear() @@ -105,70 +100,18 @@ class ExtrinsicBuilder( return maybeWrapInBatch(batchMode) } - suspend fun build( + suspend fun buildExtrinsic( batchMode: BatchMode = BatchMode.BATCH - ): String { + ): SendableExtrinsic { val call = maybeWrapInBatch(batchMode) - - return build(CallRepresentation.Instance(call)) + return buildSendableExtrinsic(CallRepresentation.Instance(call)) } - suspend fun build( + suspend fun buildExtrinsic( rawCallBytes: ByteArray - ): String { + ): SendableExtrinsic { requireNotMixingBytesAndInstanceCalls() - - return build(CallRepresentation.Bytes(rawCallBytes)) - } - - suspend fun buildSignature( - batchMode: BatchMode = BatchMode.BATCH - ): String { - val call = maybeWrapInBatch(batchMode) - - return buildSignature(CallRepresentation.Instance(call)) - } - - suspend fun buildSignature( - rawCallBytes: ByteArray - ): String { - requireNotMixingBytesAndInstanceCalls() - - return buildSignature(CallRepresentation.Bytes(rawCallBytes)) - } - - private suspend fun build(callRepresentation: CallRepresentation): String { - val signedExtrinsic = buildSignedExtrinsic(callRepresentation) - - val multiSignature = signatureConstructor.constructInstance( - runtime.typeRegistry, - signedExtrinsic.signatureWrapper - ) - - val extrinsic = Extrinsic.EncodingInstance( - signature = Extrinsic.Signature.new( - accountIdentifier = buildEncodableAddressInstance(signedExtrinsic.payload.accountId), - signature = multiSignature, - signedExtras = signedExtrinsic.payload.signedExtras.includedInExtrinsic - ), - callRepresentation = signedExtrinsic.payload.call - ) - - return Extrinsic.toHex(runtime, extrinsic) - } - - private suspend fun buildSignature( - callRepresentation: CallRepresentation - ): String { - val signedExtrinsic = buildSignedExtrinsic(callRepresentation) - val multiSignature = signatureConstructor.constructInstance( - runtime.typeRegistry, - signedExtrinsic.signatureWrapper - ) - - val signatureType = Extrinsic.signatureType(runtime) - - return signatureType.toHexUntyped(runtime, multiSignature) + return buildSendableExtrinsic(CallRepresentation.Bytes(rawCallBytes)) } private fun maybeWrapInBatch(batchMode: BatchMode): GenericCall.Instance { @@ -179,7 +122,9 @@ class ExtrinsicBuilder( } } - private suspend fun buildSignedExtrinsic(callRepresentation: CallRepresentation): SignedExtrinsic { + private suspend fun buildSendableExtrinsic( + callRepresentation: CallRepresentation + ): SendableExtrinsic { val signerPayload = SignerPayloadExtrinsic( runtime = runtime, accountId = accountId, @@ -192,7 +137,9 @@ class ExtrinsicBuilder( nonce = nonce ) - return signer.signExtrinsic(signerPayload) + val signedExtrinsic = signer.signExtrinsic(signerPayload) + + return RealSendableExtrinsic(signedExtrinsic) } private fun buildIncludedInSignature(): Map { @@ -257,4 +204,41 @@ class ExtrinsicBuilder( "Cannot mix instance and raw bytes calls" } } + + private inner class RealSendableExtrinsic( + private val signedExtrinsic: SignedExtrinsic + ) : SendableExtrinsic { + + private val multiSignature = signatureConstructor.constructInstance( + runtime.typeRegistry, + signedExtrinsic.signatureWrapper + ) + + override val extrinsicHex by lazy { + createExtrinsicHex() + } + + override val signatureHex by lazy { + createSignatureHex() + } + + private fun createExtrinsicHex(): String { + val address = buildEncodableAddressInstance(signedExtrinsic.payload.accountId) + val extrinsic = Extrinsic.EncodingInstance( + signature = Extrinsic.Signature.new( + accountIdentifier = address, + signature = multiSignature, + signedExtras = signedExtrinsic.payload.signedExtras.includedInExtrinsic + ), + callRepresentation = signedExtrinsic.payload.call + ) + + return Extrinsic.toHex(runtime, extrinsic) + } + + private fun createSignatureHex(): String { + val signatureType = Extrinsic.signatureType(runtime) + return signatureType.toHexUntyped(runtime, multiSignature) + } + } } diff --git a/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/signer/SendableExtrinsic.kt b/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/signer/SendableExtrinsic.kt new file mode 100644 index 00000000..4fdc924b --- /dev/null +++ b/substrate-sdk-android/src/main/java/io/novasama/substrate_sdk_android/runtime/extrinsic/signer/SendableExtrinsic.kt @@ -0,0 +1,8 @@ +package io.novasama.substrate_sdk_android.runtime.extrinsic.signer + +interface SendableExtrinsic { + + val signatureHex: String + + val extrinsicHex: String +} diff --git a/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/integration/extrinsic/SendIntegrationTest.kt b/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/integration/extrinsic/SendIntegrationTest.kt index 20d94257..673a048a 100644 --- a/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/integration/extrinsic/SendIntegrationTest.kt +++ b/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/integration/extrinsic/SendIntegrationTest.kt @@ -51,9 +51,9 @@ class SendIntegrationTest : BaseIntegrationTest(WESTEND_URL) { ) } - val extrinsic = builder.build() + val extrinsic = builder.buildExtrinsic() - print(socketService.executeAsync(SubmitExtrinsicRequest(extrinsic)).result!!) + print(socketService.executeAsync(SubmitExtrinsicRequest(extrinsic.extrinsicHex)).result!!) } } diff --git a/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilderTest.kt b/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilderTest.kt index 03b3fff2..9c2fec51 100644 --- a/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilderTest.kt +++ b/substrate-sdk-android/src/test/java/io/novasama/substrate_sdk_android/runtime/extrinsic/ExtrinsicBuilderTest.kt @@ -13,7 +13,6 @@ import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.Era import io.novasama.substrate_sdk_android.runtime.definitions.types.generics.Extrinsic import io.novasama.substrate_sdk_android.runtime.extrinsic.signer.KeyPairSigner import io.novasama.substrate_sdk_android.runtime.metadata.MetadataTestCommon -import io.novasama.substrate_sdk_android.runtime.metadata.RuntimeMetadata import io.novasama.substrate_sdk_android.runtime.metadata.SignedExtensionValue import io.novasama.substrate_sdk_android.ss58.SS58Encoder.publicKeyToSubstrateAccountId import io.novasama.substrate_sdk_android.ss58.SS58Encoder.toAccountId @@ -52,35 +51,35 @@ class ExtrinsicBuilderTest { @Test fun `should build extrinsic from raw call bytes`() = runBlockingTest { val extrinsic = createExtrinsicBuilder() - .build(TRANSFER_CALL_BYTES) + .buildExtrinsic(TRANSFER_CALL_BYTES) - assertEquals(SINGLE_TRANSFER_EXTRINSIC, extrinsic) + assertEquals(SINGLE_TRANSFER_EXTRINSIC, extrinsic.extrinsicHex) } @Test fun `should build single transfer extrinsic`() = runBlockingTest { - val encoded = createExtrinsicBuilder() + val extrinsic = createExtrinsicBuilder() .testSingleTransfer() - .build() + .buildExtrinsic() - assertEquals(SINGLE_TRANSFER_EXTRINSIC, encoded) + assertEquals(SINGLE_TRANSFER_EXTRINSIC, extrinsic.extrinsicHex) } @Test fun `should build extrinsic signature from call instance`() = runBlockingTest { - val actualSignature = createExtrinsicBuilder() + val extrinsic = createExtrinsicBuilder() .testSingleTransfer() - .buildSignature() + .buildExtrinsic() - assertEquals(EXTRINSIC_SIGNATURE, actualSignature) + assertEquals(EXTRINSIC_SIGNATURE, extrinsic.signatureHex) } @Test fun `should build extrinsic signature from raw call bytes`() = runBlockingTest { val extrinsic = createExtrinsicBuilder() - .buildSignature(TRANSFER_CALL_BYTES) + .buildExtrinsic(TRANSFER_CALL_BYTES) - assertEquals(EXTRINSIC_SIGNATURE, extrinsic) + assertEquals(EXTRINSIC_SIGNATURE, extrinsic.signatureHex) } @Test @@ -89,16 +88,16 @@ class ExtrinsicBuilderTest { val recipientAccountId = "340a806419d5e278172e45cb0e50da1b031795366c99ddfe0a680bd53b142c63".fromHex() - val encoded = createExtrinsicBuilder() + val extrinsic = createExtrinsicBuilder() .transfer( recipientAccountId = recipientAccountId, amount = wrongAMount ) - .reset() + .resetCalls() .testSingleTransfer() - .build() + .buildExtrinsic() - assertEquals(SINGLE_TRANSFER_EXTRINSIC, encoded) + assertEquals(SINGLE_TRANSFER_EXTRINSIC, extrinsic.extrinsicHex) } @Test @@ -115,9 +114,9 @@ class ExtrinsicBuilderTest { ) } - val encoded = builder.build() + val extrinsic = builder.buildExtrinsic() - assertEquals(extrinsicInHex, encoded) + assertEquals(extrinsicInHex, extrinsic.extrinsicHex) } @Test @@ -131,8 +130,8 @@ class ExtrinsicBuilderTest { ) } - val encoded = extrinsicBuilder.build(batchMode = BatchMode.BATCH_ALL) - val decoded = Extrinsic.fromHex(runtime, encoded) + val extrinsic = extrinsicBuilder.buildExtrinsic(batchMode = BatchMode.BATCH_ALL) + val decoded = Extrinsic.fromHex(runtime, extrinsic.extrinsicHex) assertEquals(decoded.call.function.name, "batch_all") } @@ -148,9 +147,9 @@ class ExtrinsicBuilderTest { ) } - val encoded = extrinsicBuilder.build(batchMode = BatchMode.BATCH_ALL) + val extrinsic = extrinsicBuilder.buildExtrinsic(batchMode = BatchMode.BATCH_ALL) - assertEquals(BIG_TRANSACTION, encoded) + assertEquals(BIG_TRANSACTION, extrinsic.extrinsicHex) } @Test @@ -186,9 +185,9 @@ class ExtrinsicBuilderTest { amount = BigInteger("10000000000") ) - val encoded = builder.build() - - assertEquals(extrinsicInHex, encoded) + val extrinsic = builder.buildExtrinsic() + + assertEquals(extrinsicInHex, extrinsic.extrinsicHex) } @Test @@ -227,9 +226,9 @@ class ExtrinsicBuilderTest { value = SignedExtensionValue(includedInExtrinsic = chargeAssetTxPaymentValue) ) - val encoded = builder.build() + val extrinsic = builder.buildExtrinsic() - assertEquals(extrinsicInHex, encoded) + assertEquals(extrinsicInHex, extrinsic.extrinsicHex) } @Test @@ -238,7 +237,7 @@ class ExtrinsicBuilderTest { createExtrinsicBuilder(runtime) .testSingleTransfer() - .build() + .buildExtrinsic() } private fun createExtrinsicBuilder(usedRuntime: RuntimeSnapshot = runtime) = ExtrinsicBuilder(