我在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))
}
有人可以帮助我吗?
答案 0 :(得分:0)
通过以下方式执行干净构建来解决此问题:
@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
文件夹