Tutorial: No ticket scalping CorDapp

Overview

Ticket scalping for popular events has been a problem even in the pre-Internet era; however, with the digital technology becoming ubiquitous, scalping looked like a solved problem for a brief moment—it made sense too, the tickets became digital and available through websites, and all one had to do was enter their credit card details online and click Buy.

This brief period of fair distribution lasted mostly during the dawn of the Internet. What happened later and is still happening today is that the ticket scalping returned at a much grander scale—something that the pre-Internet speculators could only dream of.

Today ticket scalping is run through automated scalping bots, there are even claims of insider scalping, and some well-known media like Pitchfork just putting it bluntly that scalping won't go away.

What this tutorial offers is a very basic CorDapp on the Corda blockchain platform to give an idea and a steer in the direction of how the scalping problem can be solved.

In this tutorial you will:

  1. Build a CorDapp.
  2. Upload the CorDapp to your Corda nodes.
  3. Connect to the nodes in shell and run the CorDapp.
  4. Build and run a webserver that connects to your Corda node and interacts with the CorDapp.

📘

Get the CorDapp without building

If you want to just try out the CorDapp, you can download the latest contract and workflow versions and skip this tutorial to the Install the CorDapp section.

This tutorial will guide you through building and deploying a CorDapp that immutably registers ticket distribution with ticket distributors.

The ticket registration is done by running noScalpDapp on Corda nodes.

What noScalpDapp does is it lets the nodes running it send each other mutually signed transactions with the event name and the number of tickets distributed. All verified by a notary.

In this framework, one node equals one ticket distributor. A distributor can be anything you want and geographically located wherever. Since one distributor equals one node, it can be a node that only you own or it can be a community-owned node. The idea is that the initial ticket distributor—as there is always one originating source—must provably distribute the tickets to a number of nodes; these nodes can, in turn, redistribute the tickets to other nodes.

Prerequisites

  1. Clone the CorDapp repository to your machine.
  2. Set up your CorDapp development environment. See Corda docs: Set-up instructions.

noScalpDapp

Each CorDapp has the following components:

noScalpDapp is no exception and has the components written in Kotlin:

  • noScalpFlow.kt — the CorDapp flow that starts sessions between the nodes and builds and verifies the ticket distribution transactions.
  • noScalpContract.kt — the CorDapp contract for the ticket distribution transaction
  • noScalpState.kt — the CorDapp state that creates an on-ledger fact that can be retrieved by the nodes participating in the transaction.

The code in noScalpFlow, noScalpContract, and noScalpState has comments explaining the what and how, so do check them.

Prepare a Corda network

Create a consortium project

See Create a project.

Deploy a Corda network

See Deploy a consortium network.

Add a second node to your Corda network

For this tutorial, you need at least two nodes.

See Add a node to a network.

Get your Corda node access and credentials

See View node access details.

Build and install noScalpDapp

Build the JAR files

The build.gradle script in root comes with the JAR instructions to build the CorDapp:

./gradlew jar

This will build the CorDapp and place the contract and flow JAR files in:

  • Contract: /contracts/build/libs/
  • Workflow: /workflows/build/libs

Install the CorDapp

See Installing a CorDapp.

Install the CorDapp on at least two nodes.

Interact with the CorDapp through shell

See Interaction tools.

To check if noScalpDapp has loaded successfully, run in the shell:

flow list

The output should be:

com.noScalpDapp.flows.noScalpFlow$Initiator

Run a ticket distribution:

start noScalpFlow eventName: "NAME", ticketQuantity: QUANTITY, toDistributor: "LEGAL_NAME"

where

  • NAME — any event name that you are distributing the tickets to.
  • QUANTITY — the number of tickets you are distributing.
  • LEGAL_NAME — the legal name of the node you are distributing the tickets to. This cannot be the same node you are currently connected to. To get the node's legal name, see View node access details.

The following example distributes 6000 tickets to the TOOL band show in Singapore to node ND-123-456-789:

>>> start noScalpFlow eventName: "TOOL Singapore show", ticketQuantity: 6000, toDistributor: "OU=Organization-ND-123-456-789, O=Organization, L=Singapore, C=SG"

✓ Starting
 ✓ Generating transaction based on the distribution parameters.
 ✓ Verifying the distribution constraints.
 ✓ Signing transaction with our private key.
 ✓ Gathering the other distributor's signature.
     ✓ Collecting signatures from counterparties.
     ✓ Verifying collected signatures.
 ✓ Obtaining notary signature and recording the distribution transaction.
          Requesting signature by notary service
              Requesting signature by Notary service
              Validating response from Notary service
     ✓ Broadcasting transaction to participants
▶︎ Done
Flow completed with result: SignedTransaction(id=AF8EE5E63678B00161EB0124AB46AFE1579584AAE558F5E8F1AA00A764597D8B)

Check the registered transaction on the node where you ran the transaction and on the node that received the transaction.

To check the transaction:

run vaultQuery contractStateType: com.noScalpDapp.states.noScalpState

This will print the registered transaction details.

Example:

>>> run vaultQuery contractStateType: com.noScalpDapp.states.noScalpState
states:
- state:
    data: !<com.noScalpDapp.states.noScalpState>
      ticket: 6000
      event: "TOOL Singapore show"
      fromDistributor: "OU=Organization-ND-987-654-321, O=Organization, L=Singapore,\
        \ C=SG"
      toDistributor: "OU=Organization-ND-123-456-789, O=Organization, L=Singapore,\
        \ C=SG"
    contract: "com.noScalpDapp.contracts.noScalpContract"
    notary: "OU=Organization-ND-916-874-734, O=Organization, L=Singapore, C=SG"
    encumbrance: null
    constraint: !<net.corda.core.contracts.SignatureAttachmentConstraint>
      key: "aSq9DsNNvGhYxYyqA9wd2eduEAZ5AXWgJTbTEw3G5d2maAq8vtLE4kZHgCs5jcB1N31cx1hpsLeqG2ngSysVHqcXhbNts6SkRWDaV7xNcr6MtcbufGUchxredBb6"
  ref:
    txhash: "AF8EE5E63678B00161EB0124AB46AFE1579584AAE558F5E8F1AA00A764597D8B"
    index: 0
totalStatesAvailable: -1
stateTypes: "UNCONSUMED"
otherResults: []

Note that the transaction details output shows the confusing totalStatesAvailable: -1. This is a known Corda issue.

Build and run the noScalpDapp webserver and client

Before you start

Once you have your Corda network with noScalpDapp running, you can start a webserver to interact with the nodes.

The webserver is a Spring Boot implementation.

For a general webserver implementation, see Interaction tools: Using Spring Boot webserver.

For this tutorial, the webserver implementation is in the clients directory of the CorDapp repository that you cloned at the start of the tutorial.

Components:

Configure the webserver

To be able to connect to your Corda node, you must configure the webserver with the connection details.

The webserver connection details are in clients/build.gradle under task runDistributor:

args '--server.port=SERVER_PORT', '--config.rpc.host=CORDA_RPC_HOSTNAME', '--config.rpc.port=CORDA_RPC_PORT', '--config.rpc.username=CORDA_RPC_USER', '--config.rpc.password=CORDA_RPC_PASSWORD'

where

  • SERVER_PORT — your Spring Boot server instance port
  • CORDA_RPC_HOSTNAME — your Corda node RPC hostname
  • CORDA_RPC_PORT — your Corda node RPC port
  • CORDA_RPC_USER — your Corda node RPC username
  • CORDA_RPC_PASSWORD — your Corda node RPC password

See also View node access details.

Example:

task runDistributor(type: JavaExec, dependsOn: jar) {
    classpath = sourceSets.main.runtimeClasspath
    main = 'com.noScalpDapp.server.ServerKt'
    args '--server.port=50005', '--config.rpc.host=nd-123-456-789.rg-123-456.p2pify.com', '--config.rpc.port=10201', '--config.rpc.username=username', '--config.rpc.password=password'
}

This will configure the webserver to run at localhost:50005 and connect it to node ND-123-456-789.

Build and run the webserver

In the project root, run:

./gradlew runDistributor

This will engage the runDistributor task specified in clients/build.gradle, start the server, and connect the server to to your node.

🚧

Webserver task progress

The task progress for the webserver start printed in the output will never reach 100% completion. You can access the webserver at around 95%.

Interact with the node through webserver

Interact via user interface or via API endpoints.

User interface

Connect to localhost:50005 in your browser. This will show the legal name of the node you are connected to and the Distribute tickets button.

  1. Click Distribute tickets.
  2. In the To distrubutor field, choose the node to distribute the tickets to. This will pick up all your peer nodes in your Corda network. Make sure that the node you select is also running the noScalpDapp.
  3. Provide Ticket quantity and Event name.
  4. Click Create distribution.

This will create and run the transaction.

Refresh the page to see your distribution under Registered distributions.

API endpoints

The GET requests are defined via @GetMapping in MainController.kt.

The POST requests are defined via @PostMapping in MainController.kt.

A GET request example to see the legal name of the node the webserver is connected to:

$ curl url http://localhost:50005/api/noScalpDapp/me
{
  "me" : "OU=Organization-ND-123-456-789, O=Organization, L=Singapore, C=SG"
}

Conclusion

This tutorial guided you through the basics of buildling and running a CorDapp.

You connected to one of your nodes through shell. You ran a transaction between two nodes running the same CorDapp represented by a contract and a workflow JAR files uploaded on both nodes.

You also built and ran a Spring Boot webserver. You interacted with the CorDapp through the webserver user interface and API.

About the author

Ake

🛠️ Developer Experience Director @ Chainstack
💸 Talk to me all things Web3 infrastructure and I'll save you the costs
Ake | Warpcast Ake | GitHub Ake | Twitter Ake | LinkedIN