Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(weaver): added multiple participants support for data sharing in… #2453

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test_weaver-asset-transfer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ concurrency:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
asset-transfer-fabric:
asset-transfer:
if: ${{ false }}
# The type of runner that the job will run on
runs-on: ubuntu-latest
Expand Down Expand Up @@ -657,7 +657,7 @@ jobs:
if: failure()
run: docker logs driver-corda-Corda_Network2

asset-transfer-fabric-local:
asset-transfer-local:
# if: ${{ false }}
# The type of runner that the job will run on
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package org.hyperledger.cacti.weaver.imodule.corda.contracts
import org.hyperledger.cacti.weaver.imodule.corda.states.AssetPledgeState
import org.hyperledger.cacti.weaver.imodule.corda.states.AssetClaimStatusState
import org.hyperledger.cacti.weaver.imodule.corda.states.NetworkIdState
import org.hyperledger.cacti.weaver.imodule.corda.states.ExternalState
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.Contract
import net.corda.core.contracts.requireSingleCommand
Expand All @@ -17,6 +18,7 @@ import net.corda.core.contracts.StaticPointer
import net.corda.core.transactions.LedgerTransaction
import java.time.Instant
import java.util.*
import co.paralleluniverse.fibers.Suspendable

/**
* AssetTransferContract defines the rules for managing a [AssetPledgeState].
Expand All @@ -37,14 +39,13 @@ class AssetTransferContract : Contract {
when (command.value) {
is Commands.Pledge -> requireThat {
"There should be one input state." using (tx.inputs.size == 1)
"There should be one output state." using (tx.outputs.size == 1)
"The output state should be of type AssetPledgeState." using (tx.outputs[0].data is AssetPledgeState)
"There should be one output AssetPledgeState." using (tx.outputsOfType<AssetPledgeState>().size == 1)

// Get the Asset Pledge State
val pledgeState = tx.outputs[0].data as AssetPledgeState
val pledgeState = tx.outputsOfType<AssetPledgeState>()[0]

// Check if output belong to this contract
"Output state should belong to this contract" using (tx.outputs[0].contract.equals(ID))
// "Output state should belong to this contract" using (tx.outputsOfType<AssetPledgeState>().contract().equals(ID))

// Check if timeout is beyond current time
val expiryTime = Instant.ofEpochSecond(pledgeState.expiryTimeSecs)
Expand All @@ -69,20 +70,21 @@ class AssetTransferContract : Contract {
"AssetPledgeState.localNetwokId must match with the networkId of current network." using (pledgeState.localNetworkId.equals(validNetworkIdState.networkId))
}
is Commands.ClaimRemoteAsset -> requireThat {
"There should be no input state." using (tx.inputs.size == 0)
"There should be one input External state." using (tx.inputsOfType<ExternalState>().size == 1)
"There should be two output states." using (tx.outputs.size == 2)
"One of the output states should be of type AssetClaimStatusState." using (tx.outputsOfType<AssetClaimStatusState>().size == 1)

// Check if output state [AssetClaimStatusState] belongs to this contract
"Output state should belong to this contract" using (tx.outputs[1].contract.equals(ID))
//"Output state should belong to this contract" using (claimStateAndRefs[0].contract.equals(ID))

// Get the input asset pledge state
val claimState = tx.outputs[1].data as AssetClaimStatusState
// Get the output asset claim state
val claimState = tx.outputsOfType<AssetClaimStatusState>()[0]

val inReferences = tx.referenceInputRefsOfType<NetworkIdState>()
"There should be a single reference input network id." using (inReferences.size == 1)
val validNetworkIdState = inReferences.get(0).state.data

// Claim State checks
"AssetClaimStatusState.localNetwokID must match with the networkId of current network." using (claimState.localNetworkID.equals(validNetworkIdState.networkId))

// Check if timeWindow <= expiryTime
Expand All @@ -100,12 +102,12 @@ class AssetTransferContract : Contract {
"The required signers of the transaction must include the recipient." using (command.signers.containsAll(requiredSigners))
}
is Commands.ReclaimPledgedAsset -> requireThat {
"There should be one input state." using (tx.inputs.size == 1)
"The input state should be of type AssetPledgeState." using (tx.inputs[0].state.data is AssetPledgeState)
"There should be one input AssetPledgeState." using (tx.inputsOfType<AssetPledgeState>().size == 1)
"There should be one input ExternalState." using (tx.inputsOfType<ExternalState>().size == 1)
"There should be one output state." using (tx.outputs.size == 1)

// Get the input asset pledge state
val pledgeState = tx.inputs[0].state.data as AssetPledgeState
val pledgeState = tx.inputsOfType<AssetPledgeState>()[0]

// Check if timeWindow > expiryTime
val fromTime = tx.timeWindow!!.fromTime!!
Expand Down Expand Up @@ -140,4 +142,4 @@ class AssetTransferContract : Contract {
class ReclaimPledgedAsset : Commands
class ClaimRemoteAsset : Commands
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,30 @@ class ExternalStateContract : Contract {
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<Commands>()
when(command.value) {
is Commands.Issue -> requireThat {
is Commands.Create -> requireThat {
"There should be no input states" using (tx.inputs.isEmpty())
"There should be one output state" using (tx.outputs.size == 1)
"The output state should be of type ExternalState" using (tx.outputs[0].data is ExternalState)
val participantKeys = tx.outputs[0].data.participants.map { it.owningKey }
"The required signers of the transaction must include all participants" using (command.signers.containsAll(participantKeys))
}
is Commands.Consume -> requireThat {
"There should be one ExternalState input states" using (tx.inputsOfType<ExternalState>().size == 1)
"There should be no ExternalState output states" using (tx.outputsOfType<ExternalState>().size == 0)
val participantKeys = tx.inputsOfType<ExternalState>()[0].participants.map { it.owningKey }
"The required signers of the transaction must include all participants" using (command.signers.containsAll(participantKeys))
}
}
}

/**
* Commands are used to indicate the intent of a transaction.
* Commands for [ExternalStateContract] are:
* - Issue
* - Create
* - Consume
*/
interface Commands : CommandData {
class Issue : Commands
class Create : Commands
class Consume : Commands
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ data class AssetPledgeState(
override val participants: List<AbstractParty> get() = listOf(locker)
}

/*
* Since there is a limit on the number of parameters to the workflow
* This data class is used as parameter.
*/
@CordaSerializable
data class AssetPledgeParameters(
var assetType: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import java.util.Base64

@CordaSerializable
enum class ResponderRole {
LOCKER, RECIPIENT, ISSUER, OBSERVER
LOCKER, RECIPIENT, SIGNER, OBSERVER
}

/**
Expand Down Expand Up @@ -121,7 +121,7 @@ object LockAssetHTLC {
/// Add issuer session if recipient or locker (i.e. me) is not issuer
if (!recipient.equals(issuer) && !ourIdentity.equals(issuer)) {
val issuerSession = initiateFlow(issuer)
issuerSession.send(ResponderRole.ISSUER)
issuerSession.send(ResponderRole.SIGNER)
sessions += issuerSession
}
val fullySignedTx = subFlow(CollectSignaturesFlow(partSignedTx, sessions))
Expand Down Expand Up @@ -150,7 +150,7 @@ object LockAssetHTLC {
@Suspendable
override fun call(): SignedTransaction {
val role = session.receive<ResponderRole>().unwrap { it }
if (role == ResponderRole.ISSUER) {
if (role == ResponderRole.SIGNER) {
val signTransactionFlow = object : SignTransactionFlow(session) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
Expand Down Expand Up @@ -407,7 +407,7 @@ object ClaimAssetHTLC {
var sessions = listOf<FlowSession>()
if (!assetExchangeHTLCState.recipient.equals(issuer)) {
val issuerSession = initiateFlow(issuer)
issuerSession.send(ResponderRole.ISSUER)
issuerSession.send(ResponderRole.SIGNER)
sessions += issuerSession
}
val fullySignedTx = subFlow(CollectSignaturesFlow(partSignedTx, sessions))
Expand Down Expand Up @@ -437,7 +437,7 @@ object ClaimAssetHTLC {
@Suspendable
override fun call(): SignedTransaction {
val role = session.receive<ResponderRole>().unwrap { it }
if (role == ResponderRole.ISSUER) {
if (role == ResponderRole.SIGNER) {
val signTransactionFlow = object : SignTransactionFlow(session) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
Expand Down Expand Up @@ -542,7 +542,7 @@ object UnlockAssetHTLC {

if (!ourIdentity.equals(issuer)) {
val issuerSession = initiateFlow(issuer)
issuerSession.send(ResponderRole.ISSUER)
issuerSession.send(ResponderRole.SIGNER)
sessions += issuerSession
}
if (!ourIdentity.equals(assetExchangeHTLCState.locker)) {
Expand Down Expand Up @@ -576,7 +576,7 @@ object UnlockAssetHTLC {
@Suspendable
override fun call(): SignedTransaction {
val role = session.receive<ResponderRole>().unwrap { it }
if (role == ResponderRole.ISSUER) {
if (role == ResponderRole.SIGNER) {
val signTransactionFlow = object : SignTransactionFlow(session) {
override fun checkTransaction(stx: SignedTransaction) = requireThat {
}
Expand Down
Loading