Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Blockchain technology in FinTech

Exactpro
November 08, 2018

Blockchain technology in FinTech

Data Fest Tbilisi 2018,
8 November, 2018

Anton Sitnikov, Chief Software Architect, Exactpro

Exactpro website: https://exactpro.com/
Follow us:
FB https://www.facebook.com/exactpro/
Twitter https://twitter.com/exactpro
LinkedIn https://www.linkedin.com/company/exactpro-systems-llc
Instagram https://www.instagram.com/exactpro/
Vimeo https://vimeo.com/exactpro
Youtube https://youtube.com/exactprosystems

Exactpro

November 08, 2018
Tweet

More Decks by Exactpro

Other Decks in Technology

Transcript

  1. 2 Build Software to Test Software exactpro.com EXACTPRO Exactpro •

    A specialist firm focused on functional and non functional testing of exchanges, clearing houses, depositories and other market infrastructures • Incorporated in 2009 with 10 people, our company has experienced significant growth as satisfied clients require more services; now employing 550 specialists. • Part of London Stock Exchange Group (LSEG) from May 2015 till January 2018. Exactpro management buyout from LSEG in January 2018. Headquartered in UK, with operations in US, Georgia and Russia. • We provide software testing services for mission critical technology that underpins global financial markets. Our clients are regulated by FCA, Bank of England and their counterparts from other countries.
  2. 7 Build Software to Test Software exactpro.com Corda • A

    Corda network is an authenticated peer-to-peer network of nodes, where each node is a JVM run-time environment hosting Corda services and executing applications known as CorDapps. • All communication between nodes is direct, with TLS-encrypted messages sent over AMQP/1.0. This means that data is shared only on a need-to-know basis; in Corda, there are no global broadcasts. • Corda networks are semi-private. Each network has a doorman service that enforces rules regarding the information that nodes must provide and the know-your-customer processes that they must complete before being admitted to the network.
  3. 9 Build Software to Test Software exactpro.com Network and Indentity

    • Identities are attested to by X.509 certificate • Well known identities are published in the network map • Confidential identities are only shared on a need to know basis
  4. 10 Build Software to Test Software exactpro.com State CASH CONTRACT

    REF PARTICIPANTS Alice Bob CASH STATE PROPERTIES OWNER: AMOUNT: CURRENCY: Alice 10 USD
  5. 11 Build Software to Test Software exactpro.com State sequence NO

    CASH USD 100 USD 50 2017-02-01 timeline 2017-02-24 HISTORIC
  6. 12 Build Software to Test Software exactpro.com Vault B HEAD

    C HEAD A HEAD S HEAD B1 A3 S2 B0 A2 S1 A1 S0 A0 HISTORIC CONSUMED HISTORICAL STATES UNCONSUMED HISTORIC HISTORIC HISTORIC HISTORIC HISTORIC HISTORIC HISTORIC HISTORIC
  7. 13 Build Software to Test Software exactpro.com Contract Contract checks

    transaction validity CASH 0 CASH CONTRACT CASH 1 BOND 1 BOND 2 BOND CONTRACT REFERENCES VALIDATES REFERENCES REFERENCES REFERENCES VALIDATES
  8. 14 Build Software to Test Software exactpro.com Command BOND 1

    OWNER: Alice VALUE: 100 USD COUPON PAID: NO BOND 2 OWNER: Alice VALUE: 100 USD COUPON PAID: YES CASH 1 OWNER: Bob AMOUNT: 5 USD CASH 2 OWNER: Alice AMOUNT: 5 USD HISTORIC HISTORIC COUPONE (ALICE 5%) PAY (BOB 5 USD) INPUT STATES COMMANDS OUTPUT STATES SIG Alice SIG Bob
  9. 15 Build Software to Test Software exactpro.com Transaction • Is

    identified by a hash • Is atomic • Can have multiple input states • Can have multiple output states • Should have at least one command CASH 0 CASH 1 BOND 1 BOND 2 TRANSACTION
  10. 16 Build Software to Test Software exactpro.com Transaction chain TxHash:

    f70f5… Index: 0 New State 1 TxHash: 8031d… Index: 1 New State 2 TRANSACTION Hash = 95fd065cb0... TxHash: 95fd0… Index: 0 New State 1 TxHash: 0dbfc… Index: 1 New State 2 TRANSACTION Hash = 1ba0ce7a71... TxHash: 56005… Index: 0 New State 1 TxHash: 047dd… Index: 1 New State 2 TRANSACTION Hash = 0dbfcf6665...
  11. 17 Build Software to Test Software exactpro.com Committing transaction SIG

    Alice SIG Bob BOND 1 OWNER: Alice VALUE: 5 USD COUPON PAID: NO BOND 2 OWNER: Alice VALUE: 5 USD COUPON PAID: YES CASH 1 OWNER: Bob AMOUNT: 5 USD CASH 2 OWNER: Alice AMOUNT: 5 USD HISTORIC HISTORIC
  12. 18 Build Software to Test Software exactpro.com Transaction validity •

    Transaction validity: For both the proposed transaction, and every transaction in the chain of transactions that created the current proposed transaction’s inputs: ▪ The transaction is digitally signed by all the required parties ▪ The transaction is contractually valid • Transaction uniqueness: There exists no other committed transaction that has consumed any of the inputs to our proposed transaction
  13. 19 Build Software to Test Software exactpro.com Flow INITIATOR (ALICE)

    GET DATA FROM INTERNAL SYSTEM CREATE TX SIGN TX RESPONDER (BOB) INSPECT AND VERIFY TX SIGN TX COMMIT TX END INSPECT AND VERIFY TX COMMIT TX END SEND (TX+SIG) SEND (TX+SIG) FLOW SUSPENDED AND CHECKPOINTED
  14. 20 Build Software to Test Software exactpro.com Notary • Notaries

    provide uniqueness consensus which prevents “double-spends” • Notaries may optionally also validate transactions • A network can have several notaries, each running a different consensus algorithm
  15. 25 Build Software to Test Software exactpro.com Class State data

    class State( val tradeId: String, val symbol: String, val side: Side, val price: Double, val size: Double, val buyerOrSeller: Party, val ccp: Party, val cleared: Boolean) : ContractState, QueryableState { 014 015 016 017 018 019 020 021 022 main/.../contract/TradeContract.kt
  16. 26 Build Software to Test Software exactpro.com Interface ContractState @CordaSerializable

    interface ContractState { val participants: List<AbstractParty> } 014 015 026 027 Corda override val participants: List<Party> = listOfNotNull(buyerOrSeller, ccp) 024 main/.../contract/TradeContract.kt
  17. 27 Build Software to Test Software exactpro.com Object TradeSchemaV1 object

    TradeSchema object TradeSchemaV1 : MappedSchema(schemaFamily = TradeSchema.javaClass, version = 1, mappedTypes = listOf(PersistentTradeState::class.java)) { @Entity @Table(name = "trade_states") class PersistentTradeState( @Column(name = "trade_id") var tradeId: String, @Column(name = "symbol") var symbol: String, @Column(name = "side") var side: Side, @Column(name = "price") var price: Double, @Column(name = "size") var size: Double, @Column(name = "cleared") var cleared: Boolean ) : PersistentState() { 011 012 013 014 015 016 017 018 019 020 022 023 025 026 028 029 031 032 040 041 042 main/.../schema/TradeSchema.kt
  18. 28 Build Software to Test Software exactpro.com Interface QueryableState interface

    QueryableState : ContractState { fun supportedSchemas(): Iterable<MappedSchema> fun generateMappedObject(schema: MappedSchema): PersistentState } 018 022 023 027 028 Corda
  19. 29 Build Software to Test Software exactpro.com Class State override

    fun supportedSchemas(): Iterable<MappedSchema> = listOf(TradeSchemaV1) override fun generateMappedObject(schema: MappedSchema): PersistentState { return when (schema) { is TradeSchemaV1 -> TradeSchemaV1.PersistentTradeState( tradeId = this.tradeId, symbol = this.symbol, side = this.side, price = this.price, size = this.size, buyerOrSeller = this.buyerOrSeller, ccp = this.ccp, cleared = this.cleared ) else -> throw IllegalArgumentException("Unrecognised schema $schema") } } 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 main/.../contract/TradeContract.kt
  20. 30 Build Software to Test Software exactpro.com Interface Contract @CordaSerializable

    interface Contract { @Throws(IllegalArgumentException::class) fun verify(tx: LedgerTransaction) } 232 233 240 241 242 Corda
  21. 31 Build Software to Test Software exactpro.com Class TradeContract class

    TradeContract : Contract { companion object { val ID = "com.exactpro.example.contract.TradeContract" } sealed class Commands : TypeOnlyCommandData() { class RegisterTrade : Commands() class ClearTrade : Commands() } } 012 013 046 047 048 049 085 086 087 088 089 main/.../contract/TradeContract.kt
  22. 32 Build Software to Test Software exactpro.com Class TradeContract override

    fun verify(tx: LedgerTransaction) { val command = tx.commands.requireSingleCommand<Commands>() when (command.value) { is Commands.RegisterTrade -> requireThat { "there is no input states" using (tx.inputStates.isEmpty()) val output = tx.outputs.single().data "This must be an TradeState state" using (output is TradeContract.State) val tradeOutput = output as TradeContract.State "trade is not cleared" using (!tradeOutput.cleared) "size is positive" using (tradeOutput.size > 0) "price is positive" using (tradeOutput.price > 0) } is Commands.ClearTrade -> requireThat { 052 053 054 055 056 057 058 059 060 061 062 063 064 main/.../contract/TradeContract.kt
  23. 33 Build Software to Test Software exactpro.com Class RegisterTradeFlow @InitiatingFlow

    @StartableByRPC class RegisterTradeFlow(val fixMessage: FixMessage, val ccp: Party) : FlowLogic<SignedTransaction>() { @Suspendable override fun call(): SignedTransaction { 014 015 016 017 018 048 049 main/.../flow/RegisterTradeFlow.kt
  24. 34 Build Software to Test Software exactpro.com Fun RegisterTradeFlow::call progressTracker.currentStep

    = GENERATING_TRANSACTION val notary = serviceHub.networkMapCache.notaryIdentities.first() val tradeState = TradeContract.State( tradeId = fixMessage.tradeId, symbol = fixMessage.symbol, side = fixMessage.side, price = fixMessage.price, size = fixMessage.size, buyerOrSeller = serviceHub.myInfo.legalIdentities.first(), ccp = ccp, cleared = false) val txCommand = Command( TradeContract.Commands.RegisterTrade(), listOf(ourIdentity.owningKey, ccp.owningKey)) val txBuilder = TransactionBuilder(notary) .addOutputState(tradeState, TradeContract.ID) .addCommand(txCommand) 052 053 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 main/.../flow/RegisterTradeFlow.kt
  25. 35 Build Software to Test Software exactpro.com Class RegisterTradeFlow companion

    object { object GENERATING_TRANSACTION : ProgressTracker.Step("Generating transaction.") object VERIFYING_TRANSACTION : ProgressTracker.Step("Verifying contract constraints.") object SIGNING_TRANSACTION : ProgressTracker.Step("Signing transaction with our private key.") object GATHERING_SIGS : ProgressTracker.Step("Getting the CCP signature.") { override fun childProgressTracker() = CollectSignaturesFlow.tracker() } object FINALISING_TRANSACTION : ProgressTracker.Step("Obtaining notary signature and recording transaction.") { override fun childProgressTracker() = FinalityFlow.tracker() } 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 main/.../flow/RegisterTradeFlow.kt
  26. 36 Build Software to Test Software exactpro.com Class RegisterTradeFlow companion

    object { fun tracker() = ProgressTracker( GENERATING_TRANSACTION, VERIFYING_TRANSACTION, SIGNING_TRANSACTION, GATHERING_SIGS, FINALISING_TRANSACTION ) } 019 037 038 039 040 041 042 043 044 main/.../flow/RegisterTradeFlow.kt
  27. 37 Build Software to Test Software exactpro.com Fun RegisterTradeFlow::call progressTracker.currentStep

    = VERIFYING_TRANSACTION txBuilder.verify(serviceHub) progressTracker.currentStep = SIGNING_TRANSACTION val ptx = serviceHub.signInitialTransaction(txBuilder) progressTracker.currentStep = GATHERING_SIGS val ccpSession = initiateFlow(ccp) val stx = subFlow(CollectSignaturesFlow( ptx, listOf(ccpSession), GATHERING_SIGS.childProgressTracker())) progressTracker.currentStep = FINALISING_TRANSACTION return subFlow(FinalityFlow(stx, FINALISING_TRANSACTION.childProgressTracker())) } 076 077 078 081 082 083 086 087 088 089 090 093 094 095 main/.../flow/RegisterTradeFlow.kt
  28. 38 Build Software to Test Software exactpro.com Class AcceptTradeFlow @InitiatedBy(RegisterTradeFlow::class)

    class AcceptTradeFlow(val otherPartyFlow: FlowSession) : FlowLogic<SignedTransaction>() { @Suspendable override fun call(): SignedTransaction { val signTransactionFlow = object : SignTransactionFlow(otherPartyFlow) { override fun checkTransaction(stx: SignedTransaction) = requireThat { val output = stx.tx.outputs.single().data "This must be an TradeState transaction." using (output is TradeContract.State) } } return subFlow(signTransactionFlow) } } 098 099 100 101 102 103 104 105 106 107 108 109 110 main/.../flow/RegisterTradeFlow.kt
  29. 39 Build Software to Test Software exactpro.com Class RegisterTradeFlowTests class

    RegisterTradeFlowTests { @Before fun start() { val cordappPackages = listOf( "com.exactpro.example.contract", "com.exactpro.example.flow", "com.exactpro.example.schema") mockNet = MockNetwork( servicePeerAllocationStrategy = ServicePeerAllocationStrategy.RoundRobin(), cordappPackages = cordappPackages) partyANode = mockNet.createPartyNode(PARTY_A_NAME) partyA = partyANode.info.identityFromX500Name(PARTY_A_NAME) ccpNode = mockNet.createPartyNode(CCP_NAME) ccp = ccpNode.info.identityFromX500Name(CCP_NAME) notary = mockNet.defaultNotaryIdentity } @After fun cleanUp() { mockNet.stopNodes() } 016 017 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 test/.../flow/RegisterTradeFlowTests.kt
  30. 40 Build Software to Test Software exactpro.com Class RegisterTradeFlowTests class

    RegisterTradeFlowTests { @Test fun `register a trade`() { val fixMessage = FixMessage( tradeId = "1", symbol = "MSFT", side = Side.BUY, price = 2.0, size = 100.0) val future = partyANode.startFlow(RegisterTradeFlow(fixMessage, ccp)) mockNet.runNetwork() val tx = future.getOrThrow() } } 016 017 045 046 047 048 049 050 051 052 053 054 055 056 057 test/.../flow/RegisterTradeFlowTests.kt
  31. 41 Build Software to Test Software exactpro.com Class ClearTradeFlow @InitiatingFlow

    @StartableByRPC class ClearTradeFlow(val tradeId: String, val ccp: Party) : FlowLogic<Void?>() { @Suspendable override fun call(): Void? { val ccpSession = initiateFlow(ccp) ccpSession.send(ClearTradeRequest(tradeId)) return null } @CordaSerializable class ClearTradeRequest(val tradeId: String) } 018 019 020 021 022 023 024 025 026 027 028 029 030 031 main/.../flow/ClearTradeFlow.kt
  32. 42 Build Software to Test Software exactpro.com Class ClearTradeHandler @InitiatedBy(ClearTradeFlow::class)

    class ClearTradeHandler(val otherPartyFlow: FlowSession) : FlowLogic<Void?>() { @Suspendable override fun call(): Void? { val tradeId = otherPartyFlow.receive<ClearTradeFlow.ClearTradeRequest>() .unwrap { data -> data }.tradeId val expression = builder { TradeSchemaV1.PersistentTradeState::tradeId.equal(tradeId) TradeSchemaV1.PersistentTradeState::cleared.equal(false) } val queryCriteria = QueryCriteria.VaultCustomQueryCriteria(expression) val tradeStateAndRefs = serviceHub.vaultService.queryBy<TradeContract.State>(queryCriteria).states if (tradeStateAndRefs.size == 2) { 033 034 035 054 055 056 057 058 059 060 061 062 063 064 065 066 main/.../flow/ClearTradeFlow.kt
  33. 43 Build Software to Test Software exactpro.com Fun ClearTradeHandler::call() progressTracker.currentStep

    = GENERATING_TRANSACTION val notary = serviceHub.networkMapCache.notaryIdentities.first() val txCommand = Command( TradeContract.Commands.ClearTrade(), listOf(ourIdentity.owningKey)) val clearedA = tradeStateAndRefs[0].state.data.copy(cleared = true) val clearedB = tradeStateAndRefs[1].state.data.copy(cleared = true) val txBuilder = TransactionBuilder(notary) .addInputState(tradeStateAndRefs[0]) .addInputState(tradeStateAndRefs[1]) .addOutputState(clearedA, TradeContract.ID) .addOutputState(clearedB, TradeContract.ID) .addCommand(txCommand) 070 071 073 074 075 076 077 078 079 080 081 082 083 084 main/.../flow/ClearTradeFlow.kt
  34. 44 Build Software to Test Software exactpro.com Fun ClearTradeHandler::call() progressTracker.currentStep

    = VERIFYING_TRANSACTION txBuilder.verify(serviceHub) progressTracker.currentStep = SIGNING_TRANSACTION val ptx = serviceHub.signInitialTransaction(txBuilder) progressTracker.currentStep = FINALISING_TRANSACTION subFlow(FinalityFlow(ptx, FINALISING_TRANSACTION.childProgressTracker())) } return null } 088 089 090 093 094 095 098 099 100 101 102 main/.../flow/ClearTradeFlow.kt
  35. 45 Build Software to Test Software exactpro.com Class TradeContract override

    fun verify(tx: LedgerTransaction) { val command = tx.commands.requireSingleCommand<Commands>() when (command.value) { is Commands.ClearTrade -> requireThat { "there are 2 input states" using (tx.inputStates.size == 2) "there are 2 output states" using (tx.outputStates.size == 2) val inputA = tx.inputs[0].state.data as TradeContract.State val inputB = tx.inputs[1].state.data as TradeContract.State "input[0] is not cleared" using (!inputA.cleared) "input[1] is not cleared" using (!inputB.cleared) "inputs have same tradeId" using (inputA.tradeId == inputB.tradeId) "inputs have different sides" using (inputA.side != inputB.side) val outputA = tx.outputs[0].data as TradeContract.State val outputB = tx.outputs[1].data as TradeContract.State "output[0] is cleared" using (outputA.cleared) "output[1] is cleared" using (outputB.cleared) "outputs have same tradeId" using (outputA.tradeId == outputB.tradeId) "outputs have different sides" using (outputA.side != outputB.side) } 052 053 054 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 main/.../contract/TradeContract.kt
  36. 46 Build Software to Test Software exactpro.com Class ClearTradeFlowTests class

    ClearTradeFlowTests { @Test fun `clear a trade`() { val fixMessageA = FixMessage( // side = Side.BUY, val futureA = partyANode.startFlow(RegisterTradeFlow(fixMessageA, ccp)) val fixMessageB = FixMessage( // side = Side.SELL val futureB = partyBNode.startFlow(RegisterTradeFlow(fixMessageB, ccp)) mockNet.runNetwork() futureA.getOrThrow() futureB.getOrThrow() val future = partyANode.startFlow(ClearTradeFlow("1", ccp)) mockNet.runNetwork() future.getOrThrow() } 021 022 050 051 052 058 059 060 066 067 068 069 070 071 072 073 074 075 076 test/.../flow/ClearTradeFlowTests.kt
  37. 47 Build Software to Test Software exactpro.com Further reading •

    Oracles • Information hiding (Merkle trees) • Anonymous identity • Corda applications