流程执行期间... corda异常的合同约束失败

时间:2018-03-28 12:07:00

标签: corda

我在corda中实现一个简单的用例有些麻烦。我想实施免费转账。生命周期保持在corda。

首先,我创建一个仅在nodeA上保存的绑定状态,该状态可以正常工作)。之后我想创建一个代表FOP提议的新状态,接收者(nodeB)可以接受。我们的想法是,在创建fop提案时将使用债券。在接收者接受提议(另一个需要实施的流程)之后,将创建一个新的绑定状态,接收者是所有者。

创建FOP提案的流程(应该保存在nodeA和nodeB上的状态)是:

object IssueFopFlow {

@InitiatingFlow
@StartableByRPC
class Initiator(private val sender: AbstractParty,
                private val receiver: AbstractParty,
                private val amount: Int,
                private val bondLinearId: UniqueIdentifier) : MyBaseFlow() {

    companion object {
        object INITIALISING : ProgressTracker.Step("Performing initial steps.")
        object BUILDING : ProgressTracker.Step("Building and verifying transaction.")
        object SIGNING : ProgressTracker.Step("Signing transaction.")
        object COLLECTING : ProgressTracker.Step("Collecting counterparty signature.") {
            override fun childProgressTracker() = CollectSignaturesFlow.tracker()
        }

        object FINALISING : ProgressTracker.Step("Finalising transaction.") {
            override fun childProgressTracker() = FinalityFlow.tracker()
        }

        fun tracker() = ProgressTracker(INITIALISING, BUILDING, SIGNING, COLLECTING, FINALISING)
    }

    override val progressTracker: ProgressTracker = tracker()

    @Suspendable
    override fun call(): SignedTransaction {
        // Step 1. Initialisation.
        progressTracker.currentStep = INITIALISING
        val bondForFop = getBondByLinearId(bondLinearId)
        val inputBond = bondForFop.state.data

        // check that the bond owner is calling this flow
        check(inputBond.owner == ourIdentity) {
            throw FlowException("Issue fop transfer must be initiated by the bond owner.")
        }

        // check the amount
        check(inputBond.amount >= amount) {
            throw FlowException("Not enough of the bond ${inputBond.isin}. Quantity: ${inputBond.amount}. Amount to transfer: ${amount}")
        }

        // create fop transfer state
        val fopTransfer = FopState(sender, receiver, amount, inputBond.isin)
        val ourSigningKey = fopTransfer.sender.owningKey

        // Step 2. Building.
        progressTracker.currentStep = BUILDING
        val utx = TransactionBuilder(firstNotary)
                .addInputState(bondForFop)
                .addOutputState(fopTransfer, FOP_CONTRACT_ID)
                .addCommand(FopContract.Commands.Issue(), listOf(sender.owningKey, receiver.owningKey))
                .setTimeWindow(serviceHub.clock.instant(), 30.seconds)

        // create new bond state
        if (amount < inputBond.amount) {
            val (command, newState) = inputBond.reduce(amount)
            utx
                    .addOutputState(newState, BOND_CONTRACT_ID)
                    .addCommand(command, newState.owner.owningKey)
        }

        utx.verify(serviceHub)

        // Step 3. Sign the transaction.
        progressTracker.currentStep = SIGNING
        val ptx = serviceHub.signInitialTransaction(utx, ourSigningKey)

        // Step 4. Get the counter-party signature.
        progressTracker.currentStep = COLLECTING
        val senderFlow = initiateFlow(ourIdentity)
        val stx = subFlow(
                CollectSignaturesFlow(
                        ptx,
                        setOf(senderFlow),
                        listOf(sender.owningKey, receiver.owningKey),
                        COLLECTING.childProgressTracker()
                )
        )

        // Step 5. Finalise the transaction.
        progressTracker.currentStep = FINALISING
        return subFlow(FinalityFlow(stx, FINALISING.childProgressTracker()))
    }
}

@InitiatedBy(Initiator::class)
class Responder(private val otherFlow: FlowSession) : FlowLogic<SignedTransaction>() {
    @Suspendable
    override fun call(): SignedTransaction {
        subFlow(IdentitySyncFlow.Receive(otherFlow))
        val stx = subFlow(SignTxFlowNoChecking(otherFlow))
        return waitForLedgerCommit(stx.id)
    }
}

}

我目前的问题是,我得到一个例外:

net.corda.core.contracts.TransactionVerificationException$ContractConstraintRejection: Contract constraints failed for com.models.BondContract, transaction: 44A52F07B9579C5106321361A6154C1EE5EF5670FA94CEFF24AB487F0B20D733
at net.corda.core.transactions.LedgerTransaction.verifyConstraints(LedgerTransaction.kt:91) ~[corda-core-2.0.0.jar:?]
at net.corda.core.transactions.LedgerTransaction.verify(LedgerTransaction.kt:67) ~[corda-core-2.0.0.jar:?]
at net.corda.core.transactions.TransactionBuilder.verify(TransactionBuilder.kt:113) ~[corda-core-2.0.0.jar:?]
at com.flow.IssueFopFlow$Initiator.call(IssueFopFlow.kt:78) ~[cordapp-0.1.jar:?]
at com.flow.IssueFopFlow$Initiator.call(IssueFopFlow.kt:19) ~[cordapp-0.1.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-2.0.0.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:41) [corda-node-2.0.0.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_162]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_162]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_162]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_162]

我不明白为什么。 BondContract的验证实施应该没问题(仅从我的观点来看:D)。 这也是债券合约的代码。

open class BondContract : Contract {

override fun verify(tx: LedgerTransaction) {
    val command = tx.commands.requireSingleCommand<Commands>()
    val setOfSigners = command.signers.toSet()
    when (command.value) {
        is Commands.Issue -> verifyIssue(tx, setOfSigners)
        is Commands.Reduce -> verifyReduce(tx, setOfSigners)
        else -> throw IllegalArgumentException("Unrecognised command.")
    }
}

private fun keysFromParticipants(bond: BondState): Set<PublicKey> {
    return bond.participants.map {
        it.owningKey
    }.toSet()
}

private fun verifyIssue(tx: LedgerTransaction, signers: Set<PublicKey>) = requireThat {
    "No inputs should be consumed when issuing an obligation." using (tx.inputStates.isEmpty())
    "Only one bond state should be created when issuing an obligation." using (tx.outputStates.size == 1)

    val bond = tx.outputsOfType<BondState>().single()
    "A newly issued bond must have a positive amount." using (bond.amount > 0)
    "Issuer may sign bond issue transaction." using
            (signers == keysFromParticipants(bond))
}

private fun verifyReduce(tx: LedgerTransaction, signers: Set<PublicKey>) = requireThat {
     val bond = tx.outputsOfType<BondState>().single()
    "A bond must have a positive amount." using (bond.amount > 0)
}

interface Commands : CommandData {
    class Move : TypeOnlyCommandData(), Commands
    class Issue : TypeOnlyCommandData(), Commands
    class Reduce : TypeOnlyCommandData(), Commands
}
}

// *********
// * State *
// *********
data class BondState(val isin: String,
                 val amount: Int,
                 override val owner: AbstractParty,
                 override val linearId: UniqueIdentifier = UniqueIdentifier()) : LinearState, QueryableState, OwnableState {

override val participants: List<AbstractParty> get() = listOf(owner)

override fun generateMappedObject(schema: MappedSchema): PersistentState {
    return when (schema) {
        is BondSchemaV1 -> BondSchemaV1.PersistentBond(
                this.owner.toString(),
                this.isin,
                this.amount,
                this.linearId.id
        )
        else -> throw IllegalArgumentException("Unrecognised schema $schema")
    }
}

override fun supportedSchemas(): Iterable<MappedSchema> = listOf(BondSchemaV1)

override fun withNewOwner(newOwner: AbstractParty) = CommandAndState(BondContract.Commands.Move(), copy(owner = newOwner))

fun reduce(amountToReduce: Int) =  CommandAndState(BondContract.Commands.Reduce(), copy(amount = amount - amountToReduce))
}

有人可以帮助我吗?

1 个答案:

答案 0 :(得分:0)

通过以下方式执行干净构建来解决此问题:

  • 使用Gradle @Autowired private JwtAccessTokenConverter accessTokenConverter; ... TokenEnhancer tokenEnhancer = accessTokenConverter; // Added this TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); enhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer)); // and add the enhancer here 标记(例如clean
  • 手动删除gradlew clean deployNodes文件夹