Open In App

Ethereum Development with Golang

Last Updated : 01 Jun, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Ethereum is a blockchain-based platform that enables developers to create decentralized applications (dApps) and smart contracts. Ethereum’s native cryptocurrency is Ether (ETH), which is used to pay transaction fees and incentivize miners to secure the network.

Go, also known as Golang, is a programming language developed by Google. It is a compiled language that is designed to be efficient, concise, and easy to use. Go is often used for building web applications, network servers, and other types of software that require high performance.

Getting Started with Go-Ethereum

Ethereum Go, also known as Geth, is the official Go implementation of the Ethereum protocol. Geth provides a command-line interface (CLI) for interacting with the Ethereum network, as well as an API for building decentralized applications. The relationship between Ethereum and Go is that Geth is one of the software clients that can connect to the Ethereum network. Developers can use Geth to interact with the Ethereum network and build decentralized applications using the Go programming language.

Applications of Ethereum Go include building decentralized applications, interacting with smart contracts, and deploying and managing Ethereum nodes. The Ethereum network has a wide range of use cases, including decentralized finance (DeFi), non-fungible tokens (NFTs), and supply chain management.

Prerequisites

1. Go programming language: Install Go by following the official installation guide for your operating system.

2. Go-Ethereum (Geth): To use Ethereum Go, first install Geth on your computer. You can download Geth from the official Ethereum website.

3. Infura Account: Sign up for an account on Infura to obtain an API key. Infura allows us to connect to Ethereum nodes without setting up our own infrastructure.

Connecting to an Ethereum Node using Infura and Go

Step 1:  After we have installed go-ethereum, create a new Go module for your project by running the following command:

go mod init <module-name>

Step 2: Import the required packages for interacting with Ethereum using Geth.

import (
   “github.com/ethereum/go-ethereum”
   “github.com/ethereum/go-ethereum/ethclient”
)

Step 3: Go to the Infuara website and create an account and then head to your Ethereum dashboard.

Ethereum Dashboard

 

Step 3: Click on create project button and add the name of the project. Copy the mainnet link of the Ethereum shown in the picture below. Proceed with the following code in the editor and use the link for a variable.

Create Project

 

Step 4: Instantiate a new Ethereum client by providing the Infura endpoint and your Infura API key. Replace YOUR_INFURA_API_KEY with your actual Infura API key.

Go




client, err := ethclient.Dial(endpoint)
if err != nil {
    log.Fatal(err)
}


Step 5: Once the connection is established, you can start interacting with the Ethereum node using the client object. For example, you can query the latest block number.

Go




blockNumber, err := client.BlockNumber(context.Background())
if err != nil {
    log.Fatal(err)
}
fmt.Println("Latest Block Number:", blockNumber)


Code:

Go




package main
  
import (
    "context"
    "fmt"
    "log"
  
    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/ethclient"
)
  
func main() {
    // Initialize the Go module with the specified module name
    err := goModInit("module-name")
    if err != nil {
        log.Fatal(err)
    }
  
    // Set the endpoint for the Ethereum client
  
    // Connect to the Ethereum client
    client, err := ethclient.Dial(endpoint)
    if err != nil {
        log.Fatal(err)
    }
  
    // Get the latest block number
    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatal(err)
    }
  
    // Print the latest block number
    fmt.Println("Latest Block Number:", blockNumber)
}
  
// goModInit initializes the Go module with the specified module name
func goModInit(moduleName string) error {
    // Command: go mod init <module-name>
    cmd := exec.Command("go", "mod", "init", moduleName)
  
    // Run the command and check for any errors
    err := cmd.Run()
    if err != nil {
        return err
    }
  
    return nil
}


Note:

To run this code, you need to replace “YOUR_INFURA_API_KEY” with your actual Infura API key.

Output: 

Once you have got the API key your output might look like this:

Output

 

Querying Ethereum Wallet Balances with Geth

Step 1: Import the required packages:

import (
   “context”
   “fmt”
   “log”

   “github.com/ethereum/go-ethereum”
   “github.com/ethereum/go-ethereum/common”
   “github.com/ethereum/go-ethereum/ethclient”
)

Step 2: Copy your address from Infura as shown in the above picture and then in the code define the Ethereum address for which you want to query the balance:

address := common.HexToAddress(“0xYOUR_ADDRESS”)

Note:

Replace 0xYOUR_ADDRESS with the actual Ethereum address.

Step 3: You can now query the balance of your Ethereum address using the below code snippet function where we are setting up the Ethereum client connection and then returning the balance of your account.

Go




balance, err := client.BalanceAt(context.Background(), address, nil)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Wallet Balance:", balance)


Code:

Go




package main
  
import (
    "context"
    "fmt"
    "log"
  
    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)
  
func main() {
    // Ethereum client connection setup
    client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_INFURA_API")
    if err != nil {
        log.Fatal(err)
    }
  
    // Ethereum address to check balance
    address := common.HexToAddress("0xYOUR_ADDRESS")
  
    // Retrieve the wallet balance
    balance, err := client.BalanceAt(context.Background(), address, nil)
    if err != nil {
        log.Fatal(err)
    }
  
    // Print the wallet balance
    fmt.Println("Wallet Balance:", balance)
}


Output: Once you have entered your address and infura API in the above code your output might look like this:

Note:

The wallet balance is in wei the smallest unit of Ether.

Output

 

Creating an Ethereum Wallet with Go-Ethereum

Step 1: We begin by importing all the important packages:

import (
   “context”
   “fmt”

“log”

      “github.com/ethereum/go-ethereum”
      “github.com/ethereum/go-ethereum/accounts”
      “github.com/ethereum/go-ethereum/common”
      “github.com/ethereum/go-ethereum/crypto”
      “github.com/ethereum/go-ethereum/ethclient”
  )

Step 2: Generate a new Ethereum account by creating a new private key and deriving the corresponding public key and address. In this code, we generate a new private key using crypto.GenerateKey() function. If there’s an error, the program exits with a fatal error log message.

Go




privateKey, err := crypto.GenerateKey()
if err != nil {
    log.Fatal(err)
}
  
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
    log.Fatal("Error casting public key to ECDSA")
}
  
address := crypto.PubkeyToAddress(*publicKeyECDSA)


Step 3: Print the newly created Ethereum address:

fmt.Println(“New Wallet Address:”, address.Hex())

Code:

Go




package main
  
import (
    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
  
    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/accounts"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
)
  
func main() {
    // Generate a new private key
    privateKey, err := crypto.GenerateKey()
    if err != nil {
        log.Fatal(err)
    }
  
    // Obtain the public key from the generated private key
    publicKey := privateKey.Public()
    publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    if !ok {
        log.Fatal("Error casting public key to ECDSA")
    }
  
    // Derive the Ethereum address from the public key
    address := crypto.PubkeyToAddress(*publicKeyECDSA)
    fmt.Println("New Wallet Address:", address.Hex())
  
    // Other Ethereum-related operations can be performed here
  
    // Example: Connect to an Ethereum client (such as Infura)
    // Replace "<YOUR_INFURA_API_KEY>" with your actual Infura API key
    infuraAPIKey := "<YOUR_INFURA_API_KEY>"
    client, err := ethclient.Dial("https://mainnet.infura.io/v3/" + infuraAPIKey)
    if err != nil {
        log.Fatal(err)
    }
  
    // Other Ethereum operations using the client can be performed here
}


Output: Once you have entered your address and infura API in the above code your output might look like this:

Output

 

Making Ethereum Transactions in Go using Go-Ethereum

Step 1: Import the following required packages to do this.

import (
“context”
“log”

“github.com/ethereum/go-ethereum/ethclient”
)

Step 2: We will create a new transaction by specifying the recipient address, value, gas price, gas limit, and nonce in the go code. Also, replace YOUR_PRIVATE_KEY with the private key of the account making the transaction and 0xRECIPIENT_ADDRESS with the recipient’s Ethereum address.

Go




privateKey, err := crypto.HexToECDSA("YOUR_PRIVATE_KEY")
if err != nil {
    log.Fatal(err)
}
  
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
    log.Fatal("Error casting public key to ECDSA")
}
  
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
toAddress := common.HexToAddress("0xRECIPIENT_ADDRESS")
  
value := big.NewInt(1000000000000000000) // 1 ETH in Wei
gasLimit := uint64(21000)
gasPrice := big.NewInt(30000000000) // 30 Gwei
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
    log.Fatal(err)
}
  
tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)


Step 3: Sign the transaction using the private key by replacing chainID with the appropriate chain ID and send it to the Ethereum network.

Go




//Sing the transaction
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
if err != nil {
    log.Fatal(err)
}
  
//Send it to the ethereum network
err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
    log.Fatal(err)
}


Code:

C++




package main
  
import (
    "context"
    "fmt"
    "io/ioutil"
    "log"
    "math/big"
  
    "github.com/ethereum/go-ethereum/accounts/keystore"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/ethclient"
)
  
var (
)
  
func main() {
    // ks := keystore.NewKeyStore("./wallet", keystore.StandardScryptN, keystore.StandardScryptP)
    // _, err := ks.NewAccount("password")
    // if err != nil {
    //     log.Fatal(err)
    // }
    // _, err = ks.NewAccount("password")
    // if err != nil {
    //     log.Fatal(err)
    // }
    // "1f7ecea2fa83cc4a7de969f11d16a40edf9023d7"
    // "1e41ca1ccfc06597525c966a986b35a09e22358d"
  
    client, err := ethclient.Dial(url)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
    a1 := common.HexToAddress("c393967d7b4b7fd02e697d13085d645c9412af11")
    a2 := common.HexToAddress("1e41ca1ccfc06597525c966a986b35a09e22358d")
  
    b1, err := client.BalanceAt(context.Background(), a1, nil)
    if err != nil {
        log.Fatal(err)
    }
  
    b2, err := client.BalanceAt(context.Background(), a2, nil)
    if err != nil {
        log.Fatal(err)
    }
  
    fmt.Println("Balance 1:", b1)
    fmt.Println("Balance 2:", b2)
    nonce, err := client.PendingNonceAt(context.Background(), a1)
    if err != nil {
        log.Fatal(err)
    }
    // 1 ether = 1000000000000000000 wei
    amount := big.NewInt(100000000000000000)
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    tx := types.NewTransaction(nonce, a2, amount, 21000, gasPrice, nil)
    chainID, err := client.NetworkID(context.Background())
    if err != nil {
        log.Fatal(err)
    }
  
    b, err := ioutil.ReadFile("wallet/UTC--2021-05-24T16-47-26.459903259Z--c393967d7b4b7fd02e697d13085d645c9412af11")
    if err != nil {
        log.Fatal(err)
    }
  
    key, err := keystore.DecryptKey(b, "password")
    if err != nil {
        log.Fatal(err)
    }
  
    tx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
    if err != nil {
        log.Fatal(err)
    }
  
    err = client.SendTransaction(context.Background(), tx)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("tx sent: %s", tx.Hash().Hex())
}


Output: After you have added your Infura API key to the above code and the correct addresses of the sender and receiver.

Output

 

Querying the Number of Transactions in a Block

Step 1: Import the following required packages to do this.

import (
“context”
“log”

“github.com/ethereum/go-ethereum/ethclient”
)

Step 2: Set up and create a client with the following GO code. 

Go




package main
  
import (
    "context"
    "log"
  
    "github.com/ethereum/go-ethereum/ethclient"
)
  
  
func main() {
    client, err := ethclient.DialContext(context.Background(), )
    }


Step 3: Proceed with the following code in the editor and use the link for a variable.

Go




package main
  
import (
    "context"
    "log"
  
    "github.com/ethereum/go-ethereum/ethclient"
)
  
  
func main() {
    client, err := ethclient.DialContext(context.Background(), infuraURL)
    if err != nil {
        log.Fatalf("Error in creating an ether client: %v", err)
    }
    defer client.Close()


Step 4: After creating the client let’s use it to get the Ethereum block number. Note that if you don’t mention the block number you will automatically be given the last mined block’s number.

Go




package main
  
import (
    "context"
    "log"
  
    "github.com/ethereum/go-ethereum/ethclient"
)
  
  
func main() {
    client, err := ethclient.DialContext(context.Background(), infuraURL)
    if err != nil {
        log.Fatalf("Error in creating an ether client: %v", err)
    }
    defer client.Close()
    block,err:= client.BlockByNumber(context.Background(),nil)
      
    if err != nil {
    log.Fatalf("Error to get a block: %v", err)
    }
      
    fmt.Println(block.Number())


Step 5: Run the code on the terminal

Output:

Output

 

In my and your case, it could differ depending on the current block being used in the network. Running the code at different intervals will generate different block numbers.

Querying Details of Transactions in a Block

Step 1: Import the following required packages to do this.

import (
“context”
“log”

“github.com/ethereum/go-ethereum/ethclient”
)

Step 2: Connect to the Ethereum node and specify the block number for which you want to query the transaction details.

blockNumber := uint64(1234567) // Replace with the desired block number

Step 3: Retrieve the block containing the transactions and iterate over the transactions in the block and print their details. We will look at the details like the transaction hash, from to addresses, gas price, nonce, etc.

Go




block, err := client.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber)))
if err != nil {
    log.Fatal(err)
}
  
for _, tx := range block.Transactions() {
    fmt.Println("Transaction Hash:", tx.Hash().Hex())
    fmt.Println("From:", tx.From().Hex())
    fmt.Println("To:", tx.To().Hex())
    fmt.Println("Value:", tx.Value().String())
    fmt.Println("Gas Limit:", tx.Gas())
    fmt.Println("Gas Price:", tx.GasPrice().String())
    fmt.Println("Nonce:", tx.Nonce())
    fmt.Println("Data:", tx.Data())
    fmt.Println("-----------------------------------")
}


Code:

Go




package main
  
import (
    "context"
    "fmt"
    "log"
    "math/big"
  
    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/ethclient"
)
  
func main() {
    // Ethereum node endpoint
  
    // Create an Ethereum client instance
    client, err := ethclient.Dial(nodeURL)
    if err != nil {
        log.Fatal(err)
    }
  
    // Specify the block number to retrieve
    blockNumber := uint64(1234567)
  
    // Retrieve the block using the block number
    block, err := client.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber)))
    if err != nil {
        log.Fatal(err)
    }
  
    // Iterate over the transactions in the block
    for _, tx := range block.Transactions() {
        fmt.Println("Transaction Hash:", tx.Hash().Hex())
        fmt.Println("From:", tx.From().Hex())
        fmt.Println("To:", tx.To().Hex())
        fmt.Println("Value:", tx.Value().String())
        fmt.Println("Gas Limit:", tx.Gas())
        fmt.Println("Gas Price:", tx.GasPrice().String())
        fmt.Println("Nonce:", tx.Nonce())
        fmt.Println("Data:", tx.Data())
        fmt.Println("-----------------------------------")
    }
}


Output: After you have added the Infura API key in the code you will get a similar output.

Output

 



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads