HOME | DEUTSCH | IMPRESSUM | KIT

bachelor thesis (finished): Java to Solidity

TL;DR: Smart Contracts are written often in non standard languages, why not write them in Java, the language that most people know?

What are Smart Contracts?

To quote ethereum.org:

A "smart contract" is simply a program that runs on the Ethereum blockchain. It's a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain.

Smart contracts are a type of Ethereum account. This means they have a balance and they can send transactions over the network. However they're not controlled by a user, instead they are deployed to the network and run as programmed. User accounts can then interact with a smart contract by submitting transactions that execute a function defined on the smart contract. Smart contracts can define rules, like a regular contract, and automatically enforce them via the code.

These programs run on the Ethereum Virtual Machine (EVM). A popular language for the EVM is Solidity. The following is an example for a small contract the implements a crypto currency:

pragma solidity >=0.7.0 <0.9.0;

contract Coin {

    // The keyword "public" makes variables
    // accessible from other contracts
    address public minter;
    mapping (address => uint) public balances;

    // Events allow clients to react to specific
    // contract changes you declare
    event Sent(address from, address to, uint amount);

    // Constructor code is only run when the contract
    // is created
    constructor() {
        minter = msg.sender;
    }

    // Sends an amount of newly created coins to an address
    // Can only be called by the contract creator
    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        require(amount < 1e60);
        balances[receiver] += amount;
    }

    // Sends an amount of existing coins
    // from any caller to an address
    function send(address receiver, uint amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance.");
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

The Problem

There is a rich ecosystem and lots of research around smart contracts, especially based on ethereum with lots of code written in solidity. The problem is that solidity is a new language with limited support for IDEs and analysis tools. What if we could just write smart contracts in a language that we already know, e.g. Java?

There are of course libraries out there that allow you to write smart contracts in languages like Java, interfacing as clients with the blockchain. But this is not really a solution: They are harder to integrate into the already existing universe of tooling around "normal" smart contracts.

The Solution

A solution to this problem is to create a compiler from a subset of a language like Java to Solidity (or the underlying bytecode). An example of such an approach is Vyper which uses a subset of Python.

The Aim

The aim with this thesis is to develop a transformation from Java (bytecode) to Solidity. The Java code itself should be semantically equivalent to the produced Solidity code (proofing some kind of soundness of the transformation would be the icing on the cake) and most contracts written in Solidity should be expressible in Java.

A Glimpse

The written Java code would probably depend on a runtime library, to provide annotations and support for the data types not supported directly in Java.

The library could for example include classes for unsigned integers of different widths, as Solidity supports them and Java does not.

The contract from above could be written in a hypothetical subset of Java as follows:

import edu.kit.sicni.*;

public class Coin extends Contract {

    public Address minter;
    public Map<Address, UInt> balances;

    // Events allow clients to react to specific
    // contract changes you declare
    @Event
    void Sent(Address from, Address to, UInt amount) {}

    // Constructor code is only run when the contract
    // is created
    Coin() {
        minter = msg.sender; // msg being a global variable
    }

    // Sends an amount of newly created coins to an address
    // Can only be called by the contract creator
    public void mint(Address receiver, UInt amount) {
        assert(msg.sender == minter);
        assert(amount.lower("1e60"));
        balances.put(receiver, balances.get(receiver) + amount);
    }

    // Sends an amount of existing coins
    // from any caller to an address
    public void send(Address receiver, UInt amount) {
        assert(amount.lowerEquals(balances.get(msg.sender)),
            "Insufficient balance.");
        balances.put(receiver, balances.get(sender) - amount);
        balances.put(receiver, balances.get(receiver) + amount);
        emit(Sent(msg.sender, receiver, amount));
    }
}

This could of course profit from being compatible with Kotlin or Scala which both allow operator overloading.

Challenges

This all might sound straight forward, but there are major challenges:

  • Understanding Solidity and the sorrounding ecosystem

  • Solidity and Java have different error handling semantics and more

  • Formalization and simplicity of the transformation are important

    • at least if it should be usable

      -> the simpler the better

Resources

Some useful resources are given in the following:

The Java bytecode processing is an important part, the following tools might be helpful

  • OPAL: a new bytecode analysis and processing framework written in Scala

  • Soot: an older framework for the same purpose written in Java

  • ASM: the underlying bytecode library



Advisors

Former Staff Member
M.Sc. Johannes Bechberger

Students

Students
Engelhard Heß