Skip to content

GoLedgerDev/goledger-challenge-besu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoLedger Challenge - Besu Edition

In this challenge you will interact with a Hyperledger Besu node. The goal is to create a simple application that interacts with a Besu node to transact on a smart contract, read the value of a contract variable, and sync that value to an external database.

We recommend a UNIX-like machine (Linux/macOS).

Prerequisites

  • Docker
  • Go
  • Foundry (forge, cast)
  • Java JDK — required to run the local Besu binary
    • macOS: Java 21+ (brew install openjdk@21)
    • Linux/Unix: Java 17+
  • jq
  • wget (macOS fallback: curl)
  • Fork the repository: https://github.com/goledgerdev/goledger-challenge-besu
    • Fork it, do NOT clone it, since you will need to send us your forked repository
    • If you cannot fork it, create a private repository and give access to samuelvenzi

Repository structure

.
├── app/                # Your solution goes here
├── besu/               # Scripts and config to run the local Besu network
├── SimpleStorage/      # Foundry project: contract source, tests, and deploy script
├── Makefile            # Convenience targets
└── README.md

Set up the environment

The Makefile provides a single command to start the 4-node Besu network and deploy the SimpleStorage contract to it:

make devnet-deploy

The deployed contract address is printed to stdout at the end. You will need it in your application.

Other available targets:

Target Description
make devnet Start the Besu network only
make deploy Deploy the contract to a running network
make stop-devnet Stop and clean up the network

You can check the logs of a running node with:

docker logs -f besu.node-1

The contract ABI is generated by Foundry at SimpleStorage/out/SimpleStorage.sol/SimpleStorage.json after running forge build (or make deploy, which triggers a build automatically).

The challenge

Your task is to create a simple application that interacts with a Besu blockchain network and an SQL database. The application must be written in Go and expose its functionality as either a REST API or a gRPC service.

Requirements

  1. Programming Language:

    • The application must be written in Go.
  2. API Type:

    • Choose either REST or gRPC for the service interface.
    • If implementing gRPC, enable reflection so we can test it using tools like Postman.
  3. Database Integration:

    • Use an SQL database (e.g., PostgreSQL or MySQL).
    • Store the value of the smart contract variable in the database.
  4. Endpoints:

    • The application should provide the following functionality via appropriately named endpoints or methods:

      1. SET:

        • Set a new value for the smart contract variable.
        • The application should send this value to the deployed smart contract on the Besu network.
      2. GET:

        • Retrieve the current value of the smart contract variable from the blockchain.
      3. SYNC:

        • Synchronize the value of the smart contract variable from the blockchain to the SQL database.
      4. CHECK:

        • Compare the value stored in the database with the current value of the smart contract variable.
        • Return true if they are the same, otherwise return false.
    • Endpoint Naming:

      • You may name the endpoints/methods as you see fit, provided their functionality meets the requirements outlined above.
    • General Notes:

      • Ensure the application handles blockchain interactions (reads/writes) correctly.
      • Add appropriate error handling for all interactions (blockchain, database, and API).

Deliverables

  1. Source Code:
    • The source code of the application should be hosted on a public GitHub repository forked from this one.
    • Include a README file with instructions on how to run the application.
  2. Documentation:
    • Provide a brief explanation of the application's architecture and how it interacts with the Besu network and the SQL database.
    • Include any additional information you think is relevant.
    • This can be done in the README file or as a separate Markdown file.

Remember to commit your changes to your forked repository. Commits will be used during the evaluation process.

Interaction with the Besu network

To interact with the Besu network, you can use the Go Ethereum client. Below we provide two functions — one for writing data (ExecContract) and one for reading data (CallContract). Feel free to include and adapt them in your application.

The contract ABI can be found at SimpleStorage/out/SimpleStorage.sol/SimpleStorage.json after building the Foundry project.

package main

import (
	"context"
	"fmt"
	"log"
	"log/slog"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
)

func ExecContract() {
	abi, err := abi.JSON(strings.NewReader("REPLACE: abi JSON as string goes here")) // found under SimpleStorage/out/SimpleStorage.sol/SimpleStorage.json
	if err != nil {
		log.Fatal(err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	client, err := ethclient.DialContext(ctx, "REPLACE: network URL") // e.g., http://localhost:8545
	if err != nil {
		log.Fatalf("error dialing node: %v", err)
	}

	slog.Info("querying chain id")

	chainId, err := client.ChainID(ctx)
	if err != nil {
		log.Fatalf("error querying chain id: %v", err)
	}
	defer client.Close()

	contractAddress := common.HexToAddress("REPLACE: contract address") // printed by make devnet-deploy

	boundContract := bind.NewBoundContract(
		contractAddress,
		abi,
		client,
		client,
		client,
	)

	priv, err := crypto.HexToECDSA("REPLACE: private key") // pre-funded key in SimpleStorage/.env.example
	if err != nil {
		log.Fatalf("error loading private key: %v", err)
	}

	auth, err := bind.NewKeyedTransactorWithChainID(priv, chainId)
	if err != nil {
		log.Fatalf("error creating transactor: %v", err)
	}

	tx, err := boundContract.Transact(auth, "REPLACE: method name")
	if err != nil {
		log.Fatalf("error transacting: %v", err)
	}

	fmt.Println("waiting until transaction is mined",
		"tx", tx.Hash().Hex(),
	)

	receipt, err := bind.WaitMined(
		context.Background(),
		client,
		tx,
	)
	if err != nil {
		log.Fatalf("error waiting for transaction to be mined: %v", err)
	}

	fmt.Printf("transaction mined: %v\n", receipt)
}

You can also use the following code to call view functions on the contract:

package main

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
)

func CallContract() {
	var result interface{}

	abi, err := abi.JSON(strings.NewReader("REPLACE: abi JSON as string goes here")) // found under SimpleStorage/out/SimpleStorage.sol/SimpleStorage.json
	if err != nil {
		log.Fatalf("error parsing abi: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	client, err := ethclient.DialContext(ctx, "REPLACE: network URL") // e.g., http://localhost:8545
	if err != nil {
		log.Fatalf("error connecting to eth client: %v", err)
	}
	defer client.Close()

	contractAddress := common.HexToAddress("REPLACE: contract address") // printed by make devnet-deploy
	caller := bind.CallOpts{
		Pending: false,
		Context: ctx,
	}

	boundContract := bind.NewBoundContract(
		contractAddress,
		abi,
		client,
		client,
		client,
	)

	var output []interface{}
	err = boundContract.Call(&caller, &output, "REPLACE: method name")
	if err != nil {
		log.Fatalf("error calling contract: %v", err)
	}
	result = output

	fmt.Println("Successfully called contract!", result)
}

To complete the challenge, you must send us the link to your repository with the alterations you made.

About

Technical test for GoLedger recruitment.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages