{{announcement.body}}
{{announcement.title}}

Picking an Enterprise Blockchain Protocol to Develop On Part 1: Corda, Kotlin and Java

DZone 's Guide to

Picking an Enterprise Blockchain Protocol to Develop On Part 1: Corda, Kotlin and Java

The first in a series that demo a Hello, Block! to help developers pick an enterprise blockchain protocol to develop in the programming language they prefer.

Free Resource

Introduction

This article introduces a multipart series aimed at developers and not-yet-developers looking to try their hand out at and get a taste of the enterprise blockchain world.

The series is designed to make the developers understand and run a simple “Hello, Block!” smart contract on an enterprise blockchain network in the programming language they are most comfortable with.

The “Hello, Block!” is done in five different programming languages covering five different blockchain protocols.

Programming languages:

  • Kotlin
  • Java
  • JavaScript
  • Go
  • Python

Protocols:

  • Corda
  • Hyperledger Fabric
  • Quorum
  • Ethereum
  • MultiChain

A section on each of the protocols gives a simplified architecture overview to let you quickly get a cursory understanding of the protocol mechanics. The overview is schematic and is done in the same style for all protocols so that you can switch between the posts and compare them.

Quick Blockchain Industry Facts

Bottom line—if you are thinking of getting into the blockchain as a developer, today and for the foreseeable future is still the best time to do so.

Corda, Kotlin & Java

Picking Corda as a Kotlin developer or as a Java developer.

Architecture

On Corda, a smart contract is called a CorDapp. Each CorDapp consists of a contract and a flow. The contract establishes the transaction validity, and the flow automates the logic of the exchange between the involved nodes.

A CorDapp must be installed on each of the nodes involved in an exchange. Unlike in public blockchain protocols, the smart contracts are not propagated to all nodes in the network.

Each exchange is notarized by a separate node called the notary.

Ecosystem

Corda is mainly driven by R3 developers—R3 is the company behind Corda.

Prerequisites

  1. A Chainstack account—to make it easy to quickly deploy a Corda network.
  2. Two Corda nodes. See Deploy a consortium network and Add a node to a network.

Corda “Hello, Block!” in Kotlin

Contract


package com.helloBlock.contracts



import net.corda.core.contracts.*

import net.corda.core.contracts.Requirements.using

import net.corda.core.transactions.LedgerTransaction

import com.helloBlock.states.helloBlockState



// ************

// * Contract *

// ************

// Contract and state.

class helloBlockContract: Contract {

    companion object {

        // Used to identify our contract when building a transaction.

        const val ID = "com.helloBlock.contracts.helloBlockContract"

    }



    // Contract code.

    override fun verify(tx: LedgerTransaction) {

        val command = tx.commands.requireSingleCommand<Commands.Send>()

        val helloBlock = tx.outputsOfType<helloBlockState>().single()

        "Sender must sign the message." using (helloBlock.origin.owningKey == command.signers.single())

    }



    // Used to indicate the transaction's intent.

    interface Commands : CommandData {

        class Send : Commands

    }

}
view raw CordaHelloBlockContractKotlin hosted with ❤ by  GitHub

State


package com.helloBlock.states



import com.helloBlock.contracts.helloBlockContract

import net.corda.core.contracts.BelongsToContract

import net.corda.core.contracts.ContractState

import net.corda.core.identity.Party



// *********

// * State *

// *********

@BelongsToContract(helloBlockContract::class)

data class helloBlockState(val origin: Party,

                   val target: Party,

                   val helloBlock: String = "Hello, Block!") : ContractState {

    override val participants get() = listOf(target)

}
view raw CordaHelloBlockStateKotlin hosted with ❤ by  GitHub

Flow


package com.helloBlock.flows



import com.helloBlock.contracts.helloBlockContract

import com.helloBlock.states.helloBlockState

import co.paralleluniverse.fibers.Suspendable

import net.corda.core.contracts.Command

import net.corda.core.contracts.StateAndContract

import net.corda.core.flows.*

import net.corda.core.identity.Party

import net.corda.core.transactions.SignedTransaction

import net.corda.core.transactions.TransactionBuilder

import net.corda.core.utilities.ProgressTracker



// *********

// * Flows *

// *********

@InitiatingFlow

@StartableByRPC

class helloBlockFlow(val target: Party) : FlowLogic<SignedTransaction>() {



    override val progressTracker: ProgressTracker = tracker()



    companion object {

        object GENERATING_TRANSACTION : ProgressTracker.Step("Generating a 'Hello, Block! transaction'")

        object SIGNING_TRANSACTION : ProgressTracker.Step("Signing the 'Hello, Block! transaction'")

        object VERIFYING_TRANSACTION : ProgressTracker.Step("Verifying the 'Hello, Block! transaction'")

        object FINALIZING_TRANSACTION : ProgressTracker.Step("Finalizing the 'Hello, Block! transaction'") {

            override fun childProgressTracker() = FinalityFlow.tracker()

        }



        fun tracker() = ProgressTracker(

                GENERATING_TRANSACTION,

                VERIFYING_TRANSACTION,

                SIGNING_TRANSACTION,

                FINALIZING_TRANSACTION

        )

    }



    @Suspendable

    override fun call(): SignedTransaction {

        progressTracker.currentStep = GENERATING_TRANSACTION



        val me = serviceHub.myInfo.legalIdentities.first()

        val notary = serviceHub.networkMapCache.notaryIdentities.single()

        val command = Command(helloBlockContract.Commands.Send(), listOf(me.owningKey))

        val state = helloBlockState(me, target)

        val stateAndContract = StateAndContract(state, helloBlockContract.ID)

        val utx = TransactionBuilder(notary = notary).withItems(stateAndContract, command)



        progressTracker.currentStep = SIGNING_TRANSACTION

        val stx = serviceHub.signInitialTransaction(utx)



        progressTracker.currentStep = VERIFYING_TRANSACTION

        stx.verify(serviceHub)



        progressTracker.currentStep = FINALIZING_TRANSACTION

        val targetSession = initiateFlow(target)

        return subFlow(FinalityFlow(stx, listOf(targetSession), FINALIZING_TRANSACTION.childProgressTracker()))

    }

}



@InitiatedBy(helloBlockFlow::class)

class helloBlockFlowResponder(val counterpartySession: FlowSession) : FlowLogic<SignedTransaction>() {

    @Suspendable

    override fun call(): SignedTransaction {

        return subFlow(ReceiveFinalityFlow(counterpartySession))

    }

}
view raw CordaHelloBlockFlowKotlin hosted with ❤ by  GitHub

Source on GitHub.

You can clone the “Hello, Block!” repository to see the full code and experiment with it.

Corda “Hello, Block!” in Java

Contract


package com.helloBlock.contracts;



import net.corda.core.contracts.CommandData;

import net.corda.core.contracts.CommandWithParties;

import net.corda.core.contracts.Contract;

import net.corda.core.contracts.TypeOnlyCommandData;

import net.corda.core.transactions.LedgerTransaction;

import com.helloBlock.states.helloBlockState;

import org.jetbrains.annotations.NotNull;



import static net.corda.core.contracts.ContractsDSL.requireSingleCommand;

import static net.corda.core.contracts.ContractsDSL.requireThat;



// ************

// * Contract *

// ************

// Contract and state.

public class helloBlockContract implements Contract {

    // Used to identify our contract when building a transaction.

    public static final String ID = "com.helloBlock.contracts.helloBlockContract";



    // Contract code.

    @Override

    public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException {

        final CommandWithParties<Commands.Send> command = requireSingleCommand(tx.getCommands(), Commands.Send.class);

        requireThat(require -> {

        final helloBlockState helloBlock = tx.outputsOfType(helloBlockState.class).get(0);

        require.using("Sender must sign the message.", helloBlock.getOrigin().getOwningKey().equals(command.getSigners().get(0)));

        return null;

        });

    }



    // Used to indicate the transaction's intent.

    public interface Commands extends CommandData {

        class Send extends TypeOnlyCommandData {}

    }

}
view raw CordaHelloBlockContractJava hosted with ❤ by  GitHub

State


package com.helloBlock.states;



import com.helloBlock.contracts.helloBlockContract;

import com.google.common.collect.ImmutableList;

import net.corda.core.contracts.BelongsToContract;

import net.corda.core.contracts.ContractState;

import net.corda.core.identity.AbstractParty;

import net.corda.core.serialization.ConstructorForDeserialization;

import net.corda.core.serialization.CordaSerializable;

import java.util.List;



@CordaSerializable

@BelongsToContract(helloBlockContract.class)

public class helloBlockState implements ContractState {

    public AbstractParty origin;

    public AbstractParty target;

    public String helloBlock;



    public AbstractParty getOrigin() {

        return origin;

    }



    public AbstractParty getTarget() {

        return target;

    }



    public String getHelloBlock() { return helloBlock; }



    @ConstructorForDeserialization

    public helloBlockState(AbstractParty origin, AbstractParty target, String helloBlock){

        this.origin = origin;

        this.target = target;

        this.helloBlock = helloBlock;

    }



    public helloBlockState(AbstractParty origin, AbstractParty target){

        this(origin,target,"Hello, Block!");

    }



    @Override

    public String toString(){

        return origin.nameOrNull() + "helloBlock";

    }



    @Override

    public List<AbstractParty> getParticipants() {

        return  ImmutableList.of(target);

    }



}
view raw CordaHelloBlockStateJava hosted with ❤ by  GitHub

Flow

Flow


package com.helloBlock.flows;



import com.helloBlock.contracts.helloBlockContract;

import com.helloBlock.states.helloBlockState;

import co.paralleluniverse.fibers.Suspendable;

import com.google.common.collect.ImmutableList;

import com.google.common.collect.ImmutableSet;

import net.corda.core.contracts.Command;

import net.corda.core.contracts.StateAndContract;

import net.corda.core.flows.*;

import net.corda.core.identity.Party;

import net.corda.core.node.ServiceHub;

import net.corda.core.transactions.SignedTransaction;

import net.corda.core.transactions.TransactionBuilder;

import net.corda.core.utilities.ProgressTracker;

import net.corda.core.utilities.ProgressTracker.Step;



import java.security.SignatureException;



// *********

// * Flows *

// *********

@InitiatingFlow

@StartableByRPC

public class helloBlockFlow extends FlowLogic<SignedTransaction> {

    private final Step GENERATING_TRANSACTION = new Step("Generating a 'Hello, Block! transaction");

    private final Step SIGNING_TRANSACTION = new Step("Signing the 'Hello, Block! transaction");

    private final Step VERIFYING_TRANSACTION = new Step("Verifying the 'Hello, Block! transaction");

    private final Step FINALIZING_TRANSACTION = new Step("Finalizing the 'Hello, Block! transaction") {

        @Override

        public ProgressTracker childProgressTracker() {

            return FinalityFlow.Companion.tracker();

        }

    };

    private final Party target;

    private final ProgressTracker progressTracker = new ProgressTracker(

            GENERATING_TRANSACTION,

            SIGNING_TRANSACTION,

            VERIFYING_TRANSACTION,

            FINALIZING_TRANSACTION

    );



    public helloBlockFlow(Party target){

        this.target = target;

    }



    @Suspendable

    @Override

    public SignedTransaction call() throws FlowException {



        progressTracker.setCurrentStep(GENERATING_TRANSACTION);

        ServiceHub serviceHub = getServiceHub();

        Party me = serviceHub.getMyInfo().getLegalIdentities().get(0);

        Party notary = serviceHub.getNetworkMapCache().getNotaryIdentities().get(0);

        Command command = new Command<>( new helloBlockContract.Commands.Send(),

                ImmutableList.of(me.getOwningKey()));

        helloBlockState state = new helloBlockState(me,target,"helloBlock");

        StateAndContract stateAndContract = new StateAndContract(state, helloBlockContract.ID);

        TransactionBuilder utx = new TransactionBuilder(notary).withItems(stateAndContract,command);



        progressTracker.setCurrentStep(SIGNING_TRANSACTION);

        SignedTransaction stx = serviceHub.signInitialTransaction(utx);



        progressTracker.setCurrentStep(VERIFYING_TRANSACTION);

        try {

            stx.verify(serviceHub);

        } catch (SignatureException e) {

            throw new FlowException();

        }



        progressTracker.setCurrentStep(FINALIZING_TRANSACTION);

        FlowSession targetSession = initiateFlow(target);

        return subFlow(new FinalityFlow(stx, ImmutableSet.of(targetSession), FINALIZING_TRANSACTION.childProgressTracker()));



    }

}
view raw CordaHelloBlockFlowJava hosted with ❤ by  GitHub

Flow responder


package com.helloBlock.flows;



import co.paralleluniverse.fibers.Suspendable;

import net.corda.core.flows.*;

import net.corda.core.transactions.SignedTransaction;



@InitiatedBy(helloBlockFlow.class)

public class helloBlockFlowResponder extends FlowLogic<SignedTransaction> {

    private FlowSession counterpartySession;



    helloBlockFlowResponder(FlowSession counterpartySession){

        this.counterpartySession = counterpartySession;

    }



    @Suspendable

    @Override

    public SignedTransaction call() throws FlowException {

        return subFlow(new ReceiveFinalityFlow(this.counterpartySession));

    }

}


view raw CordaHelloBlockFlowResponderJava hosted with ❤ by  GitHub

Source on GitHub.

You can clone the “Hello, Block!” repository to see the full code and experiment with it.

Build the Contract and the Flow

To build the contract and the flow, run ./gradlew build in the root of the cloned repository.

This will build the contract and the flow JAR files:

/contract/build/libs/contracts-0.1.jar
/workflows/build/libs/workflows-0.1.jar

Install the Contract and the Flow

Install both the contract and the flow on each of the two nodes you deployed. See Installing a CorDapp.

Connect to One of the Nodes

To be able to interact with the CorDapps, you must have the contract and the flow JAR files both locally on your machine and on the node you are connecting to.

Copy the previously built contract and flow JAR files to a directory on your machine.

Connect to one of your nodes while providing the directory with the JAR files on your local machine. For detailed instructions, see Corda interaction tools.

Interact with “Hello, Block!”

In the shell, run:

start helloBlockFlow target: "LEGAL_NAME"

where

  • LEGAL_NAME — the legal name of your second Corda to which you are sending a “Hello, Block!” transaction. To get the node’s legal name, see View node access and credentials.

Example:

start helloBlockFlow target: "OU=RG-254-409-ND-141-587-071, O=RG-254-409, L=Portland, C=US, ST=Oregon"

Output:

 ✓ Starting 
          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=F2B267806C09BDEEB0E1E815AC1502EFFCD8C4F19F5701CFE9BECC46871AE47C)

Congratulations! What you have just done is: a) deployed a two-node private Corda network; b) built a smart contract in the programming language you are comfortable with; c) interacted with it on your Corda network.

And it wasn’t even complicated.

Stay tuned for more enterprise blockchain protocols and programming languages coming out soon.

Topics:
blockchain, develop, hello world, tutorial

Published at DZone with permission of Ake (aka Evgeny) Gaviar (ake Konstantinov) . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}