Troubleshooting the booking system

Corda Sep 30 2022 By: Lin Chen
Comments

0 Comments

Views

197 Views

Troubleshooting the booking system
Lin Chen
Lin Chen Developer Evangelist Intern
Share this post:
Copied

This is the final blog of the ticket booking system I’ve designed. I want to review the whole process: design business logic, build CorDapp, build RPC, build front-end web pages, and code add-ons. This blog will mostly focus on the most time-consuming issues I met in the development process and how I solve these issues. It is not tech-oriented, but more like a method of finding resources to solve problems.

Overall, there are three main issues covering coding and configuration parts: write flow conversations, front-end display, and configuration issues. Most of them have been talked about in previous sessions, so it’s more like a review of the whole developing process 😃

Writing flow conversations

The most important step is to know how to debug and read error messages: here’s the file I usually go to check errors.

Check error files

Let me then review how to initiate flows:

Firstly, we need to indicate the flow that can generate conversations with other flows by the annotation @InitiatingFlow. Then we use function initiateFlow(partyName) to start a communication with its counterparties. After that, we can use subflow() function to make a transaction. There are some defined flows in the library to apply directly, some of which return a completed transaction, and some just work as a wrapper to make things easier. IssueTokens()/ CreateEvolvableTokens() belong to the first type, because they also contain a responder flow signing the whole contract. For the second flow, the most common flow is the SendStateAndRefFlow(), which is used to send a list of input StateAndRef to its counterparties that wish to verify the input’s integrity by resolving and checking the dependencies as well. So in its responder flow, it invokes the ReceiveStateAndRefFlow() at the right point in the conversation to receive the input state and ref and perform the resolution back-and-forth required to check the dependencies. Apart from above mentioned two types, we can also use the session.send() to send other self-defined information., the other parties receive that piece of information using receive() function.

For building the content of the transaction, we can use TransactionBuilder(notary name) to specify a notary. For that contract, we use addOutputState(), addCommand(), addInputState() to add specified constraints.

To sign the transaction, we can just use serviceHub.signInitialTransaction() to get a partially SignedTransaction with that node’s signature attached. After that, we get a fully SignedTransaction with all the counterparties’ names on it by CollectSignaturesFlow() function.

Show ‘expire’ image on the expired tickets

This is mostly a javascript thing. To achieve this, we first need to get the date information of the specific ticket by the function $http. get(url).get(). Then we need to tackle that response, actually what we get here is a whole booked ticket list. So we need to use angular.forEach to search the loop.

The current date’s format is gotten by the getFullYear(), getMonth() and such functions, then we use the ‘isExpired’ variable to control the display of the image. The HTML file uses ng-show to control the expire sign image.

Configuration issues

As for the configuration part, I think there are several points that need attention:

  • Configure java:

Make sure the version of JavaSDK is version 8 and the IntelliJ IDEA versions should be 2017.x2018.x2019.x, or 2020.x; and Kotlin plugin version 1.2.71.

All the configuration processes can follow the video.

  • Configure RPC port:

For this task, we only need to be more careful and make sure we have modified all the necessary files. Here I will list all the file names that need to change, though I have already listed them in the Build RPC section.

project’s build.gradle:

rpcUsers = [[ user: “user1”, “password”: “test”, “permissions”: [“ALL”]]]

Configure RPC user for each Corda node:


node {
	name "0=Agency,L=London,C=GB"
	p2pPort 10008
	rpcSettings {
		address("localhost:10009")
		adminAddress("localhost:10049")
	}
	rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
}

application.yaml

Specify the host address of the Agency:

Agency: host: localhost:10009

AppConfig.kt


@Configuration
open class AppConfig : WebMvcConfigurer{
	@Value(value "/$Agency.host")
	lateinit var AgencyProxy: String

	@Bean(destroyMethod = "")
	open fun AgencyProxy(): CordaRPCOps {
		val agencyClient = CordaRPCClient(NetworkHostAndPort.parse(AgencyProxy))
		return agnecyClient.start(username: "user1", password: "test").proxy
	}
}

Those are the issues I think are the hardest to solve or the easiest to forget in the development process. If you are trapped in the same dilemma, hope this blog can help you out.

Lin Chen
Lin Chen Lin Chen is a Developer Evangelist Intern at R3, an enterprise blockchain software firm working with a global ecosystem of more than 350 participants across multiple industries from both the private and public sectors to develop on Corda, its open-source blockchain platform, and Corda Enterprise, a commercial version of Corda for enterprise usage.

Leave a Reply

Subscribe to our newsletter to stay up to date on the latest developer news, tools, and articles.