Skip to content

Commit 12162c3

Browse files
committed
HTLC Support added for Corda
Signed-off-by: sandeep.nishad1 <[email protected]>
1 parent c9ab3fb commit 12162c3

File tree

94 files changed

+2970
-106
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2970
-106
lines changed

.github/workflows/asset-exchange.yml

Lines changed: 211 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
1717
jobs:
1818

19-
asset-exchange:
19+
asset-exchange-fabric:
2020
# The type of runner that the job will run on
2121
runs-on: ubuntu-latest
2222

@@ -65,7 +65,7 @@ jobs:
6565
cat .env
6666
working-directory: samples/fabric/fabric-cli
6767

68-
- name: Fabric CLI Configure ALL
68+
- name: Fabric CLI Init
6969
run: ./scripts/initAsset.sh
7070
working-directory: samples/fabric/fabric-cli
7171

@@ -89,7 +89,7 @@ jobs:
8989
fi
9090
working-directory: samples/fabric/fabric-cli
9191

92-
asset-exchange-local:
92+
asset-exchange-fabric-local:
9393
# The type of runner that the job will run on
9494
runs-on: ubuntu-latest
9595

@@ -162,7 +162,7 @@ jobs:
162162
cat .env
163163
working-directory: samples/fabric/fabric-cli
164164

165-
- name: Fabric CLI Configure ALL
165+
- name: Fabric CLI Init
166166
run: ./scripts/initAsset.sh
167167
working-directory: samples/fabric/fabric-cli
168168

@@ -185,3 +185,210 @@ jobs:
185185
exit 1
186186
fi
187187
working-directory: samples/fabric/fabric-cli
188+
189+
asset-exchange-corda:
190+
# The type of runner that the job will run on
191+
runs-on: ubuntu-latest
192+
193+
# Steps represent a sequence of tasks that will be executed as part of the job
194+
steps:
195+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
196+
- uses: actions/checkout@v2
197+
198+
- name: Set up JDK 8
199+
uses: actions/setup-java@v2
200+
with:
201+
java-version: '8'
202+
distribution: 'adopt'
203+
204+
# CORDA NETWORK
205+
- name: Generate github.properties (on pull_request)
206+
if: ${{ github.event_name == 'pull_request' }}
207+
run: |
208+
echo "Using ${GITHUB_ACTOR} user."
209+
echo "username=${GITHUB_ACTOR}" >> github.properties
210+
echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties
211+
echo "url=https://maven.pkg.github.com/${GITHUB_ACTOR}/weaver-dlt-interoperability" >> github.properties
212+
213+
echo "Using ${GITHUB_ACTOR} user."
214+
echo "username=${GITHUB_ACTOR}" >> github.main.properties
215+
echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.main.properties
216+
echo "url=https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability" >> github.main.properties
217+
218+
./scripts/get-cordapps.sh || mv github.main.properties github.properties
219+
220+
cat github.properties
221+
working-directory: tests/network-setups/corda
222+
223+
- name: Generate github.properties (else)
224+
if: ${{ github.event_name != 'pull_request' }}
225+
run: |
226+
echo "Using ${GITHUB_ACTOR} user."
227+
echo "username=${GITHUB_ACTOR}" >> github.properties
228+
echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties
229+
echo "url=https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability" >> github.properties
230+
cat github.properties
231+
working-directory: tests/network-setups/corda
232+
233+
# CORDA NETWORK
234+
- name: Start Corda Network
235+
run: |
236+
make start
237+
sleep 60
238+
docker logs corda_partya_1
239+
docker logs corda_partyb_1
240+
working-directory: tests/network-setups/corda
241+
242+
# FABRIC CLI
243+
- name: Setup Corda CLI init
244+
run: ./scripts/initAsset.sh
245+
working-directory: samples/corda/corda-simple-application
246+
247+
- name: Asset Exchange Corda CLI Tests
248+
run: |
249+
COUNT=0
250+
TOTAL=5
251+
252+
# Lock 50 tokens
253+
CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset -f -h64 ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= -t 180 -r "O=PartyA,L=London,C=GB" -p t1:50 &> tmp.out
254+
tail -n 2 tmp.out | grep "HTLC Lock State created with contract ID Right" && COUNT=$(( COUNT + 1 )) && echo "PASS"
255+
cat tmp.out
256+
257+
CID=$(tail -n 2 tmp.out | grep "HTLC Lock State created with contract ID Right" | sed -e 's/.*Right(b=\(.*\))\./\1/')
258+
259+
# Is Asset locked
260+
CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked -cid $CID &> tmp.out
261+
tail -n 2 tmp.out | grep "Is Asset Locked Response: true" && COUNT=$(( COUNT + 1 )) && echo "PASS"
262+
cat tmp.out
263+
264+
# Claim asset
265+
CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset -cid $CID -s secrettext &> tmp.out
266+
tail -n 2 tmp.out | grep "Asset Claim Response: Right" && COUNT=$(( COUNT + 1 )) && echo "PASS"
267+
cat tmp.out
268+
269+
# Timeout
270+
CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset -f -h64 ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= -t 5 -r "O=PartyB,L=London,C=GB" -p t1:50 &> tmp.out
271+
CID=$(tail -n 2 tmp.out | grep "HTLC Lock State created with contract ID Right" | sed -e 's/.*Right(b=\(.*\))\./\1/')
272+
sleep 5
273+
cat tmp.out
274+
275+
## Is asset lock false
276+
CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked -cid $CID &> tmp.out
277+
tail -n 2 tmp.out | grep "Is Asset Locked Response: false" && COUNT=$(( COUNT + 1 )) && echo "PASS"
278+
cat tmp.out
279+
280+
## Unlock asset
281+
CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset -cid $CID &> tmp.out
282+
tail -n 2 tmp.out | grep "Asset Unlock Response: Right" && COUNT=$(( COUNT + 1 )) && echo "PASS"
283+
cat tmp.out
284+
285+
# RESULT
286+
echo "Passed $COUNT/$TOTAL Tests."
287+
288+
if [ $COUNT == $TOTAL ]; then
289+
exit 0
290+
else
291+
exit 1
292+
fi
293+
working-directory: samples/corda/corda-simple-application
294+
295+
asset-exchange-corda-local:
296+
# The type of runner that the job will run on
297+
runs-on: ubuntu-latest
298+
299+
# Steps represent a sequence of tasks that will be executed as part of the job
300+
steps:
301+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
302+
- uses: actions/checkout@v2
303+
304+
- name: Set up JDK 8
305+
uses: actions/setup-java@v2
306+
with:
307+
java-version: '8'
308+
distribution: 'adopt'
309+
310+
- name: Use Protoc 3.15
311+
run: |
312+
curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip
313+
unzip protoc-3.15.6-linux-x86_64.zip -d protoc
314+
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
315+
go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc
316+
317+
- name: Build Java Protos
318+
run: make build
319+
working-directory: common/protos-java-kt
320+
321+
# Build Dependencies
322+
- name: Build Corda Interop App
323+
run: make build-local
324+
working-directory: core/network/corda-interop-app
325+
326+
- name: Build Corda Interop SDK
327+
run: make build
328+
working-directory: sdks/corda
329+
330+
- name: Build Corda SimpleApplication
331+
run: make build-local
332+
working-directory: samples/corda/corda-simple-application
333+
334+
# CORDA NETWORK
335+
- name: Start Corda Network
336+
run: |
337+
make start-local
338+
sleep 60
339+
docker logs corda_partya_1
340+
docker logs corda_partyb_1
341+
working-directory: tests/network-setups/corda
342+
343+
# FABRIC CLI
344+
- name: Setup Corda CLI init
345+
run: ./scripts/initAsset.sh
346+
working-directory: samples/corda/corda-simple-application
347+
348+
- name: Asset Exchange Corda CLI Tests
349+
run: |
350+
COUNT=0
351+
TOTAL=5
352+
353+
# Lock 50 tokens
354+
CORDA_PORT=10009 ./clients/build/install/clients/bin/clients lock-asset -f -h64 ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= -t 180 -r "O=PartyA,L=London,C=GB" -p t1:50 &> tmp.out
355+
tail -n 2 tmp.out | grep "HTLC Lock State created with contract ID Right" && COUNT=$(( COUNT + 1 )) && echo "PASS"
356+
cat tmp.out
357+
358+
CID=$(tail -n 2 tmp.out | grep "HTLC Lock State created with contract ID Right" | sed -e 's/.*Right(b=\(.*\))\./\1/')
359+
360+
# Is Asset locked
361+
CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked -cid $CID &> tmp.out
362+
tail -n 2 tmp.out | grep "Is Asset Locked Response: true" && COUNT=$(( COUNT + 1 )) && echo "PASS"
363+
cat tmp.out
364+
365+
# Claim asset
366+
CORDA_PORT=10006 ./clients/build/install/clients/bin/clients claim-asset -cid $CID -s secrettext &> tmp.out
367+
tail -n 2 tmp.out | grep "Asset Claim Response: Right" && COUNT=$(( COUNT + 1 )) && echo "PASS"
368+
cat tmp.out
369+
370+
# Timeout
371+
CORDA_PORT=10006 ./clients/build/install/clients/bin/clients lock-asset -f -h64 ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs= -t 5 -r "O=PartyB,L=London,C=GB" -p t1:50 &> tmp.out
372+
CID=$(tail -n 2 tmp.out | grep "HTLC Lock State created with contract ID Right" | sed -e 's/.*Right(b=\(.*\))\./\1/')
373+
sleep 5
374+
cat tmp.out
375+
376+
## Is asset lock false
377+
CORDA_PORT=10009 ./clients/build/install/clients/bin/clients is-asset-locked -cid $CID &> tmp.out
378+
tail -n 2 tmp.out | grep "Is Asset Locked Response: false" && COUNT=$(( COUNT + 1 )) && echo "PASS"
379+
cat tmp.out
380+
381+
## Unlock asset
382+
CORDA_PORT=10006 ./clients/build/install/clients/bin/clients unlock-asset -cid $CID &> tmp.out
383+
tail -n 2 tmp.out | grep "Asset Unlock Response: Right" && COUNT=$(( COUNT + 1 )) && echo "PASS"
384+
cat tmp.out
385+
386+
# RESULT
387+
echo "Passed $COUNT/$TOTAL Tests."
388+
389+
if [ $COUNT == $TOTAL ]; then
390+
exit 0
391+
else
392+
exit 1
393+
fi
394+
working-directory: samples/corda/corda-simple-application
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
name=Interop Protos
22
group=com.weaver
3-
version=1.2.4-alpha.1
3+
version=1.2.4-alpha.3
44
kotlin.incremental=false

core/drivers/corda-driver/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ buildscript {
99
ext.corda_version = "4.8"
1010
ext.corda_core_version = "4.8"
1111
ext.arrow_version = "0.10.4"
12-
ext.weaver_version = "1.2.4-alpha.1"
12+
ext.weaver_version = "1.2.4-alpha.+"
1313

1414
repositories {
1515
mavenCentral()
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
name=Interoperability CorDapp
22
group=com.weaver.corda.app.interop
3-
version=1.2.4-alpha.1
3+
version=1.2.4-alpha.3
44
kotlin.incremental=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright IBM Corp. All Rights Reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package com.weaver.corda.app.interop.contracts
8+
9+
import com.weaver.corda.app.interop.states.AssetExchangeHTLCState
10+
import com.weaver.corda.app.interop.states.AssetClaimHTLCData
11+
import net.corda.core.contracts.CommandData
12+
import net.corda.core.contracts.Contract
13+
import net.corda.core.contracts.requireSingleCommand
14+
import net.corda.core.contracts.requireThat
15+
import net.corda.core.contracts.StaticPointer
16+
import net.corda.core.transactions.LedgerTransaction
17+
import net.corda.core.crypto.sha256
18+
import java.time.Instant
19+
import java.util.*
20+
21+
/**
22+
* AssetExchangeHTLCStateContract defines the rules for managing a [AssetExchangeHTLCState].
23+
*
24+
*/
25+
class AssetExchangeHTLCStateContract : Contract {
26+
companion object {
27+
// Used to identify our contract when building a transaction.
28+
const val ID = "com.weaver.corda.app.interop.contracts.AssetExchangeHTLCStateContract"
29+
}
30+
31+
/**
32+
* A transaction is valid if the verify() function of the contract of all the transaction's
33+
* input and output states does not throw an exception.
34+
*/
35+
override fun verify(tx: LedgerTransaction) {
36+
val command = tx.commands.requireSingleCommand<Commands>()
37+
when (command.value) {
38+
is Commands.Lock -> requireThat {
39+
"There should be one input state." using (tx.inputs.size == 1)
40+
"There should be one output state." using (tx.outputs.size == 1)
41+
"The output state should be of type AssetExchangeHTLCState." using (tx.outputs[0].data is AssetExchangeHTLCState)
42+
43+
// Get the HTLC State
44+
val htlcState = tx.outputs[0].data as AssetExchangeHTLCState
45+
46+
// Check if timeout is beyond current time
47+
"Timeout after current time" using (htlcState.lockInfo.expiryTime > Instant.now())
48+
49+
// Check if owner is locker
50+
val inputState = tx.inputs[0].state.data
51+
"Locker must be the owner of asset" using inputState.participants.containsAll(listOf(htlcState.locker))
52+
53+
// Check if asset consumed in input is same as in HTLC State
54+
val assetPointer = StaticPointer(tx.inputs[0].ref, tx.inputs[0].state.data.javaClass)
55+
"Asset State match with input state" using (assetPointer.equals(htlcState.assetStatePointer))
56+
57+
// Check if both locker and recipient are signers
58+
val participantKeys = htlcState.participants.map { it.owningKey }
59+
"The required signers of the transaction must include locker and recipient." using (command.signers.containsAll(participantKeys))
60+
}
61+
is Commands.Claim -> requireThat {
62+
"There should be one input state." using (tx.inputs.size == 1)
63+
"The input state should be of type AssetExchangeHTLCState." using (tx.inputs[0].state.data is AssetExchangeHTLCState)
64+
"There should be one output state." using (tx.outputs.size == 1)
65+
66+
// Get the Claim Command
67+
val claimCmd = tx.commandsOfType<Commands.Claim>().single()
68+
69+
// Get the input HTLC state
70+
val htlcState = tx.inputs[0].state.data as AssetExchangeHTLCState
71+
72+
// Check if timeWindow <= expiryTime
73+
val untilTime = tx.timeWindow!!.untilTime!!
74+
"Time Window for claim shoule be before expiry time." using (untilTime.isBefore(htlcState.lockInfo.expiryTime) || untilTime.equals(htlcState.lockInfo.expiryTime))
75+
76+
// Verify if (hash, preimage) pair matches
77+
val computedHash = claimCmd.value.assetClaimHTLC.hashPreimage.sha256().bytes
78+
val expectedHash = htlcState.lockInfo.hash.bytes
79+
"Hash match with pre-image." using (Arrays.equals(computedHash, expectedHash))
80+
81+
// Check if owner is recipient
82+
val outputState = tx.outputs[0].data
83+
"Recipient must be the owner of asset" using outputState.participants.containsAll(listOf(htlcState.recipient))
84+
85+
// Verify if recipient is signer
86+
val participantKeys = listOf(htlcState.recipient.owningKey)
87+
"The required signers of the transaction must include recipient." using (command.signers.containsAll(participantKeys))
88+
}
89+
is Commands.Unlock -> requireThat {
90+
"There should be one input state." using (tx.inputs.size == 1)
91+
"The input state should be of type AssetExchangeHTLCState." using (tx.inputs[0].state.data is AssetExchangeHTLCState)
92+
"There should be one output state." using (tx.outputs.size == 1)
93+
94+
// Get the input HTLC state
95+
val htlcState = tx.inputs[0].state.data as AssetExchangeHTLCState
96+
97+
// Check if timeWindow > expiryTime
98+
val fromTime = tx.timeWindow!!.fromTime!!
99+
"TimeWindow for unlock should be after expiry time." using (fromTime.isAfter(htlcState.lockInfo.expiryTime))
100+
101+
// Check if owner is locker
102+
val outputState = tx.outputs[0].data
103+
"Locker must be the owner of asset" using outputState.participants.containsAll(listOf(htlcState.locker))
104+
105+
// Verify if locker is signer
106+
val participantKeys = listOf(htlcState.locker.owningKey)
107+
"The required signers of the transaction must include locker." using (command.signers.containsAll(participantKeys))
108+
}
109+
}
110+
}
111+
112+
/**
113+
* Commands are used to indicate the intent of a transaction.
114+
* Commands for [AssetExchangeHTLCStateContract] are:
115+
* - Lock
116+
* - Unlock
117+
* - Claim (preImage)
118+
*/
119+
interface Commands : CommandData {
120+
class Lock : Commands
121+
class Unlock : Commands
122+
class Claim(val assetClaimHTLC: AssetClaimHTLCData) : Commands
123+
}
124+
}

0 commit comments

Comments
 (0)