You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Corda合约代码升级技术咨询:JAR生成与升级流调用问题

Contract Upgrade Issues & Solutions in Corda

Hey Ben, let's tackle your two questions about Corda contract upgrades step by step—this is a common pain point, so let's break it down clearly.

Background Recap

First, to align on the core issue you're facing: when updating contract code within the same CorDapp, the existing TransactionState objects have attachment constraints tied to the old contract JAR's hash. Replacing the JAR directly triggers a ContractConstraintRejection error because the old states reference the now-missing old attachment hash. Your documented upgrade steps are on the right track, so let's fix the gaps you're hitting.


Question 1: How to Generate a JAR with Only the Updated Contract, and Fix Unreachable APIs?

Generating a Contract-Only JAR

If you're using Corda's standard project structure (with separate contracts and workflows submodules), generating a contract-only JAR is straightforward:

  • Navigate to your project root in the terminal.
  • Run the Gradle command for the contracts module:
    # For macOS/Linux
    ./gradlew contracts:jar
    
    # For Windows
    gradlew.bat contracts:jar
    
  • The output JAR will be located at contracts/build/libs/[your-contract-module-name].jar—this file contains only your updated contract code, no workflow or API logic.

Why Your APIs Are Unreachable (and How to Fix It)

The key mistake here: a contract-only JAR doesn't include workflow code, and your upgrade authorization/initiation flows are part of the workflows module. When you deploy only the contract JAR, the node has no access to the flow logic needed to trigger upgrades, hence the missing APIs.

To resolve this:

  • Package both updated contracts and upgrade workflows together: If you want a single JAR for deployment, adjust your Gradle configuration to bundle the contracts and workflows modules into one. Alternatively, deploy both the contract JAR and the updated workflows JAR to every node.
  • Verify flow registration: After restarting nodes, connect via RPC and check if your upgrade flows are registered with:
    proxy.registeredFlows // Kotlin RPC call
    
  • Validate flow annotations: Ensure your upgrade flows have the correct Corda annotations:
    • @InitiatingFlow on the main upgrade/authorization flows
    • @InitiatedBy on any responder flows (if needed)

Question 2: RPC Calls for Upgrade Flows—IDE Scripts & Reference Examples

Are IDE Scripts Suitable for RPC Calls?

Absolutely! IDE scripts (like Kotlin/Groovy) are a perfect way to test and execute contract upgrade flows without building a full Web API layer. They let you directly connect to node RPC endpoints and trigger flows with minimal setup.

Reference Example: RPC Script for Authorization + Upgrade Flows

Here's a simplified Kotlin script you can run in your IDE to execute both the authorization flow and upgrade flow. Make sure you have the Corda RPC client dependencies configured in your project:

import net.corda.core.contracts.StateRef
import net.corda.core.crypto.SecureHash
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.client.rpc.CordaRPCClient
import net.corda.client.rpc.CordaRPCConnection

// Replace these values with your node's details
const val RPC_HOST = "localhost"
const val RPC_PORT = 10006
const val RPC_USER = "user1"
const val RPC_PASSWORD = "test"

// Replace with your old state's transaction hash and index, plus new contract class name
val STATE_REF = StateRef(SecureHash.parse("OLD_TRANSACTION_HASH_HERE"), 0)
val NEW_CONTRACT_CLASS_NAME = "com.yourpackage.NewContract"

fun main() {
    CordRPCClient(NetworkHostAndPort(RPC_HOST, RPC_PORT))
        .start(RPC_USER, RPC_PASSWORD)
        .use { connection ->
            val proxy = connection.proxy

            // Step 1: Run Authorization Flow (execute this on EVERY node holding the state)
            println("Starting authorization flow...")
            val authFuture = proxy.startFlowDynamic(
                net.corda.core.flows.AuthoriseContractUpgradeFlow::class.java,
                listOf(STATE_REF),
                NEW_CONTRACT_CLASS_NAME
            )
            authFuture.returnValue.getOrThrow()
            println("Authorization completed successfully.")

            // Step 2: Run Upgrade Flow (execute this ONLY ONCE from one node)
            println("Starting contract upgrade flow...")
            val upgradeFuture = proxy.startFlowDynamic(
                net.corda.core.flows.ContractUpgradeFlow::class.java,
                listOf(STATE_REF),
                NEW_CONTRACT_CLASS_NAME
            )
            upgradeFuture.returnValue.getOrThrow()
            println("Contract upgrade completed successfully!")
        }
}

Key Notes for This Script:

  • Authorization Flow: Must be run on every node that has a copy of the old state (all participants in the state's ledger).
  • Upgrade Flow: Only needs to be initiated once from any one node—Corda will propagate the upgrade across the network.
  • Dependencies: Ensure your IDE project includes the Corda RPC client library (add corda-rpc to your Gradle/Maven dependencies).
  • StateRef: You can retrieve the StateRef for your old states using RPC calls like proxy.vaultQueryBy<YourOldState>().states to list all relevant states.

内容的提问来源于stack exchange,提问作者Ben Tan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:39:13