Corda-有一个以上包含该软件包的CorDapp

问题描述

我正在构建一个需要多个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
}

请注意ExampleStateExampleContract间的关系。它们都是open,并且ExampleContract包含一个可重写的函数,以允许派生类在创建时指定其他契约逻辑。

LibCorDapp-工作流程

此CorDapp的目的是定义允许创建,更新和使用示例状态的流程。这些流应该也应与源自ExampleStateExampleContract的州和合同一起使用。

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与派生的状态/合同对一起使用。

em>

测试与问题

对于我的测试,我定义了以下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-contractLibCorDapp - Contract CorDapps;如果将依赖关系更改为AppCorDapp - Contract,则该软件包将仅包含在cordaCompile CorDapp的jar文件中。