diff --git a/build.gradle.kts b/build.gradle.kts index 18fd739..dff683f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,7 +22,7 @@ allprojects { } group = "org.onflow.flow" - val defaultVersion = "0.0.19" + val defaultVersion = "0.0.20" version = System.getenv("GITHUB_REF")?.split('/')?.last() ?: defaultVersion } diff --git a/flow/src/commonMain/kotlin/org/onflow/flow/infrastructure/ApiBase.kt b/flow/src/commonMain/kotlin/org/onflow/flow/infrastructure/ApiBase.kt index 6d1822a..613d5cd 100644 --- a/flow/src/commonMain/kotlin/org/onflow/flow/infrastructure/ApiBase.kt +++ b/flow/src/commonMain/kotlin/org/onflow/flow/infrastructure/ApiBase.kt @@ -2,7 +2,6 @@ package org.onflow.flow.infrastructure import io.ktor.client.HttpClient import io.ktor.client.plugins.HttpRequestRetry -import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.logging.DEFAULT import io.ktor.client.plugins.logging.Logger @@ -15,29 +14,9 @@ open class ApiBase { companion object { val client = HttpClient { - install(HttpTimeout) { - requestTimeoutMillis = 45000L // Increased to 45 seconds - connectTimeoutMillis = 20000L // Increased to 20 seconds - socketTimeoutMillis = 45000L // Increased to 45 seconds - } - install(HttpRequestRetry) { retryOnServerErrors(maxRetries = 5) - retryOnException(maxRetries = 3) { _, cause -> - // Retry on connection-related exceptions - cause.message?.contains("Connection reset by peer", ignoreCase = true) == true || - cause.message?.contains("IOException", ignoreCase = true) == true || - cause.message?.contains("ConnectException", ignoreCase = true) == true || - cause.message?.contains("SocketTimeoutException", ignoreCase = true) == true || - cause.message?.contains("Channel was closed", ignoreCase = true) == true || - cause.message?.contains("ClosedReceiveChannelException", ignoreCase = true) == true || - cause.message?.contains("ClosedSendChannelException", ignoreCase = true) == true || - cause.message?.contains("TLS", ignoreCase = true) == true || - // Check class names for Kotlin exceptions - cause.javaClass.simpleName.contains("ClosedReceiveChannelException", ignoreCase = true) || - cause.javaClass.simpleName.contains("ClosedSendChannelException", ignoreCase = true) - } - exponentialDelay(base = 2.0, maxDelayMs = 10000L) + exponentialDelay() } install(Logging) { @@ -55,4 +34,4 @@ open class ApiBase { } } -} +} \ No newline at end of file diff --git a/flow/src/commonTest/kotlin/org/onflow/flow/FlowTransactionTests.kt b/flow/src/commonTest/kotlin/org/onflow/flow/FlowTransactionTests.kt index d5b1dc2..ac69d12 100644 --- a/flow/src/commonTest/kotlin/org/onflow/flow/FlowTransactionTests.kt +++ b/flow/src/commonTest/kotlin/org/onflow/flow/FlowTransactionTests.kt @@ -498,160 +498,6 @@ class FlowTransactionTests { println("✅ Signature debug test completed") } - /** - * Debug test to verify multi-signer signing process - */ - @OptIn(ExperimentalStdlibApi::class) - @Test - fun testMultiSignerDebug() = runBlocking { - // ===== SETUP ===== - val proposerAddress = "c6de0d94160377cd" - val proposerPrivateKey = "c9c0f04adddf7674d265c395de300a65a777d3ec412bba5bfdfd12cffbbb78d9" - val payerAddress = "10711015c370a95c" - val payerPrivateKey = "38ebd09b83e221e406b176044a65350333b3a5280ed3f67227bd80d55ac91a0f" - - // Get on-chain account information - val proposerAccount = api.getAccount(proposerAddress) - val payerAccount = api.getAccount(payerAddress) - val proposerKey = proposerAccount.keys!!.first { it.index.toInt() == 0 } - val payerKey = payerAccount.keys!!.first { it.index.toInt() == 0 } - - // Create signers with on-chain algorithms - val proposerSigner = Crypto.getSigner( - Crypto.decodePrivateKey(proposerPrivateKey, proposerKey.signingAlgorithm), - proposerKey.hashingAlgorithm - ).apply { - address = proposerAddress - keyIndex = 0 - } - - val payerSigner = Crypto.getSigner( - Crypto.decodePrivateKey(payerPrivateKey, payerKey.signingAlgorithm), - payerKey.hashingAlgorithm - ).apply { - address = payerAddress - keyIndex = 0 - } - - val latestBlock = api.getBlockHeader() - - // ===== TRANSACTION BUILDING ===== - val transaction = TransactionBuilder( - script = """ - transaction { - prepare(signer: auth(Storage) &Account) { - log("Multi-signer debug test") - } - } - """.trimIndent() - ) - .withProposalKey(proposerAddress, 0, proposerKey.sequenceNumber.toBigInteger()) - .withPayer(payerAddress) - .withAuthorizers(listOf(proposerAddress)) - .withReferenceBlockId(latestBlock.id) - .build() - - println("MULTI-SIGNER DEBUG:") - println("Initial transaction payload signatures: ${transaction.payloadSignatures.size}") - println("Initial transaction envelope signatures: ${transaction.envelopeSignatures.size}") - - // Step 1: Test payload signing manually (corrected approach) - val payloadMessageToSign = transaction.payloadMessage() - val proposerPayloadSig = proposerSigner.sign(payloadMessageToSign) // Fix: Use corrected approach - - println("Payload message to sign: ${payloadMessageToSign.toHexString()}") - println("Proposer payload signature: ${proposerPayloadSig.toHexString()}") - - // Add the payload signature - val txWithPayloadSig = transaction.copy( - payloadSignatures = listOf( - TransactionSignature( - address = proposerAddress, - keyIndex = 0, - signature = proposerPayloadSig.toHexString() - ) - ) - ) - - println("Transaction after adding payload sig - payloadSignatures: ${txWithPayloadSig.payloadSignatures.size}") - - // Step 2: Test envelope signing manually (corrected approach) - val envelopeMessageToSign = txWithPayloadSig.envelopeMessage() - val payerEnvelopeSig = payerSigner.sign(envelopeMessageToSign) // Fix: Use corrected approach - - println("Envelope message to sign: ${envelopeMessageToSign.toHexString()}") - println("Payer envelope signature: ${payerEnvelopeSig.toHexString()}") - - // Test automatic signing vs manual signing - val autoSignedTransaction = transaction.sign(listOf(proposerSigner, payerSigner)) - - println("Auto-signed transaction - payloadSignatures: ${autoSignedTransaction.payloadSignatures.size}") - println("Auto-signed transaction - envelopeSignatures: ${autoSignedTransaction.envelopeSignatures.size}") - - if (autoSignedTransaction.payloadSignatures.isNotEmpty()) { - println("Auto payload signature: ${autoSignedTransaction.payloadSignatures[0].signature}") - } - if (autoSignedTransaction.envelopeSignatures.isNotEmpty()) { - println("Auto envelope signature: ${autoSignedTransaction.envelopeSignatures[0].signature}") - } - - // Compare signatures - val manualPayloadSig = proposerPayloadSig.toHexString() - val autoPayloadSig = if (autoSignedTransaction.payloadSignatures.isNotEmpty()) - autoSignedTransaction.payloadSignatures[0].signature else "NONE" - - val manualEnvelopeSig = payerEnvelopeSig.toHexString() - val autoEnvelopeSig = if (autoSignedTransaction.envelopeSignatures.isNotEmpty()) - autoSignedTransaction.envelopeSignatures[0].signature else "NONE" - - println("Manual vs Auto payload signature match: ${manualPayloadSig == autoPayloadSig}") - println("Manual vs Auto envelope signature match: ${manualEnvelopeSig == autoEnvelopeSig}") - - // The key test: Do both payload messages for signing match? - val manualPayloadMessage = transaction.payloadMessage() - val autoPayloadMessage = transaction.payloadMessage() // These should be identical - - println("Manual vs Auto payload message match: ${manualPayloadMessage.contentEquals(autoPayloadMessage)}") - - // CRITICAL TEST: Try submitting the manual transaction - println("Testing manual transaction submission...") - val manualTransaction = txWithPayloadSig.copy( - envelopeSignatures = listOf( - TransactionSignature( - address = payerAddress, - keyIndex = 0, - signature = payerEnvelopeSig.toHexString() - ) - ) - ) - - try { - val manualResult = api.sendTransaction(manualTransaction) - println("Manual transaction submitted successfully: ${manualResult.id}") - - api.waitForSeal(manualResult.id!!) - println("Manual transaction sealed successfully!") - - } catch (e: Exception) { - println("Manual transaction failed: ${e.message}") - } - - // TEST: Try submitting the automatic transaction - println("Testing automatic transaction submission...") - try { - val autoResult = api.sendTransaction(autoSignedTransaction) - println("Auto transaction submitted successfully: ${autoResult.id}") - - api.waitForSeal(autoResult.id!!) - println("Auto transaction sealed successfully!") - - } catch (e: Exception) { - println("Auto transaction failed: ${e.message}") - } - - println("✅ Multi-signer debug test completed") - } - /** * Test UFix64 scientific notation handling in real transactions * This test verifies that values like 1.0E-8 are properly encoded and don't cause transaction failures