问题描述
我正在构建一个需要多个CorDapp的应用程序;我们称它们为 LibCorDapp 和 AppCorDapp ,其中 AppCorDapp 取决于 LibCorDapp (就像CorDapp可能取决于帐户一样或令牌SDK)。
LibCorDapp-合同
此CorDapp的目的是定义状态和契约的对象模型,这些对象模型可以直接使用,也可以从中衍生出来,以创建更明确的状态和契约类型。
build.gradle
cordapp {
targetPlatformVersion cordapp_platform_version
minimumPlatformVersion cordapp_platform_version
contract {
name cordapp_contract_name
vendor cordapp_vendor_name
licence cordapp_license
versionId cordapp_version_id
}
signing {
enabled = cordapp_signing_enabled
}
}
dependencies {
implementation "$kotlin_group:kotlin-stdlib-jdk8:$kotlin_version"
cordaCompile "$corda_group:corda-core:$corda_release_version"
testRuntimeOnly "$junit_group:junit-jupiter-engine:$junit_version"
testImplementation "$junit_group:junit-jupiter-api:$junit_version"
testImplementation "$kotlin_group:kotlin-test:$kotlin_version"
testImplementation "$corda_group:corda-node-driver:$corda_release_version"
}
示例状态
package com.example.libcordapp.contract
@BelongsToContract(ExampleContract::class)
open class ExampleState<T : Any>(
override val participants: List<AbstractParty> = emptyList(),val value: T
) : ContractState { ... }
合同示例
package com.example.libcordapp.contract
open class ExampleContract {
final override fun verify(tx: LedgerTransaction) { ... }
protected open fun onVerifyCreate(tx: LedgerTransaction,signers: Set<PublicKey>) = Unit
}
请注意ExampleState
和ExampleContract
之间的关系。它们都是open
,并且ExampleContract
包含一个可重写的函数,以允许派生类在创建时指定其他契约逻辑。
LibCorDapp-工作流程
此CorDapp的目的是定义允许创建,更新和使用示例状态的流程。这些流应该也应与源自ExampleState
和ExampleContract
的州和合同一起使用。
build.gradle
cordapp {
targetPlatformVersion cordapp_platform_version
minimumPlatformVersion cordapp_platform_version
workflow {
name cordapp_workflow_name
vendor cordapp_vendor_name
licence cordapp_license
versionId cordapp_version_id
}
signing {
enabled = cordapp_signing_enabled
}
}
dependencies {
implementation "$kotlin_group:kotlin-stdlib-jdk8:$kotlin_version"
cordaCompile "$corda_group:corda-core:$corda_release_version"
cordapp project(":libcordapp-contract")
testRuntimeOnly "$junit_group:junit-jupiter-engine:$junit_version"
testImplementation "$junit_group:junit-jupiter-api:$junit_version"
testImplementation "$kotlin_group:kotlin-test:$kotlin_version"
testImplementation "$corda_group:corda-node-driver:$corda_release_version"
}
示例流程
package com.example.libcordapp.workflow
class ExampleFlow(val state: ExampleState) : FlowLogic<SignedTransaction>() {
@Suspendable
override fun call(): SignedTransaction {
val tx = with(TransactionBuilder(notary)) {
addOutputState(state)
addCommand(ExampleContract.Issue,signers)
}
}
}
请注意,我尚未明确定义输出状态的合同ID,因为应该在运行时为每个合同/状态对确定合同ID。
AppCorDapp-合同
此CorDapp的目的是演示一个使用 LibCorDapp ,创建和测试派生状态和合同的应用程序的示例。
build.gradle
cordapp {
targetPlatformVersion cordapp_platform_version
minimumPlatformVersion cordapp_platform_version
contract {
name "Test CorDapp Contract"
vendor cordapp_vendor_name
licence cordapp_license
versionId cordapp_version_id
}
signing {
enabled = cordapp_signing_enabled
}
}
dependencies {
implementation "$kotlin_group:kotlin-stdlib-jdk8:$kotlin_version"
implementation "$corda_group:corda-core:$corda_release_version"
cordapp project(":libcordapp-contract")
testRuntimeOnly "$junit_group:junit-jupiter-engine:$junit_version"
testImplementation "$junit_group:junit-jupiter-api:$junit_version"
testImplementation "$kotlin_group:kotlin-test:$kotlin_version"
testImplementation "$corda_group:corda-node-driver:$corda_release_version"
}
问候状态
package com.example.appcordapp.contract
@BelongsToContract(GreetingContract::class)
class GreetingState(
participants: List<AbstractParty> = emptyList()
value: String = "Hello,World!"
) : ExampleState<String>(participants,value)
问候合同
package com.example.appcordapp.contract
class GreetingContract : ExampleContract {
override fun onVerifyCreate(tx: LedgerTransaction,signers: Set<PublicKey>) = requireThat { ... }
}
请注意,GreetingContract
扩展了ExampleContract
,而GreetingState
扩展了ExampleState
,并将GreetingContract
定义为相关合同,因此在创建{{1} }使用GreetingState
时,它应该拿起这份合同。
在 AppCorDapp-工作流模块中实际上没有定义任何流,因为我明确地想测试是否可以将ExampleFlow
与派生的状态/合同对一起使用。
测试与问题
对于我的测试,我定义了以下cordapps:
ExampleFlow
尝试使用cordappsForAllNodes = listof(
TestCordapp.findCordapp("com.example.libcordapp.contract"),TestCordapp.findCordapp("com.example.libcordapp.workflow"),TestCordapp.findCordapp("com.example.appcordapp.contract")
)
创建GreetingClaim
...
ExampleFlow
...我收到以下异常:
java.lang.IllegalArgumentException:类路径[/.../libcordapp-contract-0.1.jar、/.../libcordapp-workflow上有一个以上的CorDapp,其中包含com.example.appcordapp.contract包-0.1.jar]。指定对于CorDapp唯一的程序包名称。
我认为这要么是gra花一现,要么是与我使用派生状态和合同有关?
解决方法
阅读有关dependencies的官方文档,并阅读this answer;我建议您将cordapp project(":libcordapp-contract")
的{{1}}内的build.gradle
更改为AppCorDapp - Contract
。
在您当前的依赖项设置中(即使用cordaCompile project(":libcordapp-contract")
),cordapp
被包含在CorDapp的jar文件中,因此,在运行测试时,该软件包位于2个地方: libcordapp-contract
和LibCorDapp - Contract
CorDapps;如果将依赖关系更改为AppCorDapp - Contract
,则该软件包将仅包含在cordaCompile
CorDapp的jar文件中。