Corda合约代码升级技术咨询:JAR生成与升级流调用问题
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
contractsandworkflowsmodules 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:
@InitiatingFlowon the main upgrade/authorization flows@InitiatedByon 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-rpcto your Gradle/Maven dependencies). - StateRef: You can retrieve the
StateReffor your old states using RPC calls likeproxy.vaultQueryBy<YourOldState>().statesto list all relevant states.
内容的提问来源于stack exchange,提问作者Ben Tan

