Get started with Corda in 3 easy steps
CorDapps (applications built on Corda) define the flows, agreements, and updates that Corda node owners can use. Think of them as the lines which connect all the dots on Corda. Run your CorDapp in Java or Kotlin in minutes, learn best practices, and find samples ranging from simple transactions to advanced enterprise-level auction markets powered by blockchain.
Install the required software for CorDapp development: Java 8 JDK, IntelliJ IDEA, Git, and Gradle.
We have a repository that contains multiple sample apps to help you get started. Run the following command to clone the CorDapp Samples repository:
git clone http://github.com/corda/samples-java
git clone http://github.com/corda/samples-kotlin
Read through the Corda Key Concepts to understand how Corda works.
CorDapp template
Get your projects started fast – choose and edit customizable CorDapp templates.
Open source CorDapps
Use existing CorDapps for key functions such as settling payments and exploring nodes.
Access CorDappsExplore Corda
R3 offers developers the infrastructure and ease to implement custom and secure blockchain applications.
Get CordaRepresent your assets with Corda states
States let you transact digitally with nearly any asset by transforming it into an object on the ledger.
Here is an example of how you would represent a CarState in Corda:
@BelongsToContract(CarContract.class)
public class CarState implements ContractState {
private Party owningBank;
private Party holdingDealer;
private Party manufacturer;
private String vin;
private String licensePlateNumber;
private String make;
private String model;
private String dealershipLocation;
private final List participants = new ArrayList();
// our state takes all these parameters as input to the constructor
public CarState(Party owningBank, Party holdingDealer, Party manufacturer . . .) {
this.owningBank = owningBank;
this.holdingDealer = holdingDealer;
this.manufacturer = manufacturer;
// etc.
this.participants.add(owningBank);
this.participants.add(holdingDealer);
this.participants.add(manufacturer);
}
}
@BelongsToContract(CarContract::class)
class CarState(private val owningBank: Party,
private val holdingDealer: Party,
private val manufacturer: Party,
private val vin: String,
private val licensePlateNumber: String,
private val make: String,
private val model: String,
private val dealershipLocation: String) : ContractState {
private override val participants: MutableList = ArrayList()
// our state takes all these parameters as input to the constructor
init {
participants.add(owningBank)
participants.add(holdingDealer)
participants.add(manufacturer)
}
}
public class CarContract implements Contract {
public static String ID = "Sample.CarContract";
@Override
public void verify(LedgerTransaction tx) throws IllegalArgumentException {
CommandWithParties command = requireSingleCommand(tx.getCommands(), CarContract.Commands.class);
List inputs = tx.getInputStates();
List outputs = tx.getOutputStates();
if (command.getValue() instanceof CarContract.Commands.Issue) {
requireThat(req -> {
req.using("Transaction must have no input states.", inputs.isEmpty());
req.using("Transaction must have exactly one output.", outputs.size() == 1);
req.using("Output must be a CarState.", outputs.get(0) instanceof CarState);
// retrieve the CarState for the transaction
CarState output = (CarState) outputs.get(0);
req.using("The license plate number must be seven characters long.", outputState.getLicensePlateNumber().length() == 7);
req.using("Manufacturer must be required singer.", command.getSigners().contains(output.getManufacturer().getOwningKey()));
return null;
});
} else {
throw new IllegalArgumentException("Unrecognized command");
}
}
class CarContract : Contract {
@Throws(IllegalArgumentException::class)
override fun verify(tx: LedgerTransaction) {
val (signers, _, value) = tx.commands.requireSingleCommand(Commands::class.java)
val inputs = tx.inputStates
val outputs = tx.outputStates
if (value is Commands.Issue) {
requireThat {
"Transaction must have no input states.".using(inputs.isEmpty())
"Transaction must have exactly one output.".using(outputs.size == 1)
"Output must be a CarState.".using(outputs[0] is CarState)
// retrieve the CarState for the transaction
val outputState = outputs[0] as CarState
"The license plate number must be seven characters long.".using(outputState.getLicensePlateNumber().length() === 7)
"Manufacturer must be required singer.".using(signers.contains(outputState.getManufacturer().getOwningKey()))
}
} else {
throw IllegalArgumentException("Unrecognized command")
}
}
interface Commands : CommandData {
class Issue : Commands
}
companion object {
var ID = "Sample.CarContract"
}
}
Verify transactions with Corda Contracts
Contracts let you determine the validity of any transaction. They represent agreements between parties about what transactions the parties can perform with a given asset. You can attach real legal documents to transactions on Corda.
Example of a CarStateContract to the left.
Get it done with Corda flows
Flows are what make CorDapps work. When a Flow is triggered, it enables parties to coordinate actions without a centralized controller. This means CorDapps built for issuing loans, reserving concert tickets, or checking for newsletter subscriptions can do so reliably. Flows let Corda nodes interact with any external application via RPC call.
Here’s an example of how you can code CreateCarStateFlow:
// constructor for providing the information to the corda flow to then create the car
public CarIssueFlowInitiator(Party owningBank, Party holdingDealer, Party manufacturer, . . .) {
this.owningBank = owningBank;
this.holdingDealer = holdingDealer;
this.manufacturer = manufacturer;
// etc.
}
// . . .
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
// find a notary for the transaction
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// get a reference to the manufacturer node, the only node that can issue new cars
Party manufacturer = getOurIdentity();
// create our car state
CarState carState = new CarState(owningBank, holdingDealer, manufacturer);
// build the transaction
TransactionBuilder transactionBuilder = new TransactionBuilder(notary);
// we're manufacturing a new car
CommandData commandData = new CarContract.Commands.Issue();
// add the command and add the expected output of the transaction
transactionBuilder.addCommand(commandData, manufacturer.getOwningKey(), holdingDealer.getOwningKey());
transactionBuilder.addOutputState(carState, CarContract.ID);
// verify the transaction
transactionBuilder.verify(getServiceHub());
// initiate the flow and transaction
FlowSession session = initiateFlow(holdingDealer);
// use corda to collect signatures from all the required signers
SignedTransaction signedTransaction = getServiceHub().signInitialTransaction(transactionBuilder);
SignedTransaction fullySignedTransaction = subFlow(new CollectSignaturesFlow(signedTransaction, singletonList(session)));
return subFlow(new FinalityFlow(fullySignedTransaction, singletonList(session)));
}
class CarIssueFlow {
@InitiatingFlow
@StartableByRPC
class Initiator(var owningBank: Party, var holdingDealer: Party) : FlowLogic() {
@Suspendable
@Throws(FlowException::class)
override fun call(): SignedTransaction {
// find a notary for the transaction
val notary = serviceHub.networkMapCache.notaryIdentities[0]
// get a reference to the manufacturer node, the only node that can issue new cars
val manufacturer = ourIdentity
// create our car state
val carState = CarState(owningBank, holdingDealer, manufacturer)
// build the transaction
val transactionBuilder = TransactionBuilder(notary)
// we're manufacturing a new car
val commandData: CommandData = CarContract.Commands.Issue()
// add the command and add the expected output of the transaction
transactionBuilder.addCommand(commandData, manufacturer.owningKey, holdingDealer.owningKey)
transactionBuilder.addOutputState(carState, CarContract.ID)
// verify the transaction
transactionBuilder.verify(serviceHub)
// initiate the flow and transaction
val session = initiateFlow(holdingDealer)
// use corda to collect signatures from all the required signers
val signedTransaction = serviceHub.signInitialTransaction(transactionBuilder)
val fullySignedTransaction = subFlow(CollectSignaturesFlow(signedTransaction, listOf(session)))
return subFlow(FinalityFlow(fullySignedTransaction, listOf(session)))
}
}
}
Feature comparison
Corda and Corda Enterprise have the same core elements. Corda Enterprise optimizes for business with additional connectivity features.
Here’s how they compare:
Corda functionality
Feature | Community Edition (open source) |
Enterprise Edition (licensed) |
---|---|---|
Corda ledger |
done | done |
Flow framework |
done | done |
Immutable states |
done | done |
Vault |
done | done |
Smart contracts |
done | done |
Atormic transactions (with input, output, and reference states) |
done | done |
Multiple accounts |
done | done |
Supported development languages |
Java, Kotlin |
Java, Kotlin |
Standard Corda APIs |
done | done |
Compatible with any Corda network (including the Corda Network) |
done | done |
Node
Feature | Community Edition (open source) |
Enterprise Edition (licensed) |
---|---|---|
Single node |
done | done |
Multiple nodes for high availability/disaster recovery |
close | done |
Connectivity
Feature | Community Edition (open source) |
Enterprise Edition (licensed) |
---|---|---|
In-process Artemis MQ |
done | done |
External Artemis MQ |
close | done |
Corda firewall |
close | done |
Multi-node use of a shared external Artemis MQ and a shared Corda firewall |
close | done |
Key storage
Feature | Community Edition (open source) |
Enterprise Edition (licensed) |
---|---|---|
Java keystore file |
done | done |
HSM support |
close | done |
Vault databases
Feature | Community Edition (open source) |
Enterprise Edition (licensed) |
---|---|---|
H2 (development use only) |
done | done |
Postgres |
done | done |
SQL server |
Experimental only |
done |
Oracle |
close | done |
Support
Feature | Community Edition (open source) |
Enterprise Edition (licensed) |
---|---|---|
Support |
Eligible for additional Support Services |
24/7 Support included in license |
Corda developer highlights
Latest Blog Posts
Upcoming event
There are no upcoming events at this time. Check back soon.
Featured video
Kotlin Meetup • May 15, 2023 • 28:32 • By Dan Newton
Should you use Kotlin for your APIs?
In this recording, Dan Newton, Staff Software Engineer at R3, is answering the question if you should you use Kotlin for your APIs when targeting JVM applications. Learn about the advantages of Kotlin over Java for APIs and its limitations as well as why R3 cares about the answer.