Lesson 1 of 4

Set Up the gOuroboros Starter Kit

Before you can write Go code that talks to a Cardano node, you need a working example to stand on. The gOuroboros Starter Kit gives you exactly that: a single Go module containing seven small programs, each demonstrating one Ouroboros mini-protocol against a real node. In this lesson, you clone it, wire it up to your Dolos instance, and confirm one of the programs runs end-to-end.

Once this is working, the rest of Module 101 is just picking the right program for the question you want to answer.


What the Starter Kit Gives You

The repository is a normal Go module with one binary per cmd/ subdirectory. Each one is a single main.go you can read top-to-bottom in a few minutes:

Command

Ouroboros mini-protocol

What it answers

chain-tip

ChainSync (NtC)

Where is the chain right now?

chain-sync

ChainSync + BlockFetch

Stream blocks forward from a point

block-fetch

BlockFetch (NtN)

Give me this specific block

tx-monitor

LocalTxMonitor (NtC)

What's in the mempool?

tx-submission

LocalTxSubmission (NtC)

Submit this signed transaction

state-query

LocalStateQuery (NtC)

Query current ledger state

ping

Handshake

How long does a round-trip take?

peer-sharing

PeerSharing (NtN)

What peers does this node know?

All of them import github.com/blinklabs-io/gouroboros. You will use four of these in Module 101 (chain-tip, chain-sync, block-fetch, tx-monitor) and a fifth in Module 102 (tx-submission).


What You're Connecting To

The starter-kit needs a Cardano node to talk to. You have three options, each speaking the same Ouroboros protocol family:

Option

What it is

When to use it

Dolos (Rust)

Lightweight data node by TxPipe — maintains a local chain copy and serves Ouroboros over a Unix socket

The course default, set up in 099 — fastest path to a working local node

Dingo (Go)

All-Go Cardano data node by Blink Labs, built on top of gOuroboros itself

When you want a pure-Go stack; note it is still under active development, with Plutus V1/V2 validation not yet complete

Public relay (TCP)

Any community-run Cardano relay on the internet

When you want to skip local infrastructure entirely — works for NtN programs like block-fetch and peer-sharing

This lesson targets Dolos because it's already in your stack from 099. Everything below works the same way if you swap in Dingo (same Ouroboros socket, same protocols) — just point CARDANO_NODE_SOCKET_PATH at Dingo's socket instead. The public-relay path shows up naturally in 101.2 when we reach block-fetch.


Prerequisites

  • Go 1.24+ installed (go version to check)
  • Git
  • A running Dolos instance on preprod (see 099 — Setting Up Dolos). If you're running Dingo instead, the same instructions apply — substitute its socket path.
  • Your socket path and network_magic from dolos.toml (or Dingo's equivalent config)

Step 1: Clone the Repository

git clone https://github.com/blinklabs-io/gouroboros-starter-kit
cd gouroboros-starter-kit
go mod download

Look at the layout:

cmd/
  block-fetch/main.go
  chain-sync/main.go
  chain-tip/main.go
  peer-sharing/main.go
  ping/main.go
  state-query/main.go
  tx-monitor/main.go
  tx-submission/main.go
go.mod
go.sum

Each directory is a self-contained program. You run any of them with go run ./cmd/<name>.


Step 2: Understand How the Programs Read Configuration

All NtC programs in the kit read the node connection from environment variables using github.com/kelseyhightower/envconfig. The pattern is the same across commands — here's the relevant block from cmd/chain-tip/main.go:

type Config struct {
    Magic      uint32
    SocketPath string `split_words:"true"`
    Address    string
}

func main() {
    cfg := Config{
        Magic:      764824073,          // mainnet
        SocketPath: "/ipc/node.socket",
    }
    if err := envconfig.Process("cardano_node", &cfg); err != nil {
        panic(err)
    }
    // ...
}

envconfig.Process("cardano_node", &cfg) reads environment variables prefixed with CARDANO_NODE_. So:

  • CARDANO_NODE_MAGIC=1cfg.Magic = 1
  • CARDANO_NODE_SOCKET_PATH=/path/to/dolos.socketcfg.SocketPath
  • CARDANO_NODE_ADDRESS=host:portcfg.Address (used for NtN)

That means you never need to edit source files. You export two variables and the whole kit points at your Dolos instance.


Step 3: Point the Kit at Dolos

Find your values in dolos.toml:

[serve.ouroboros]
listen_path = "dolos.socket"

[upstream]
network_magic = 1

Then in the terminal where you'll run the starter-kit:

export CARDANO_NODE_SOCKET_PATH=/absolute/path/to/your/dolos/dolos.socket
export CARDANO_NODE_MAGIC=1

Verify the socket file actually exists (Dolos must be running — dolos daemon in a separate terminal):

ls -l "$CARDANO_NODE_SOCKET_PATH"

You should see a srw- permission string indicating a Unix socket.


Step 4: Run chain-tip

The simplest program. It opens a connection, asks the node for the current chain tip, prints it, and exits.

go run ./cmd/chain-tip

Expected output:

Chain Tip:
Slot: 56123456  Block Hash: e3f1a2...

If you see numbers that keep matching whatever Cardanoscan preprod shows, your Dolos + gOuroboros loop is working end-to-end.


What Just Happened (Under the Hood)

  your Go program                    Dolos                    Cardano network
  ─────────────────                  ─────                    ────────────────
  ouroboros.NewConnection
        │
        │  Dial("unix", socketPath)
        ├─────────────────────────────>│
        │       handshake (NtC)        │     (already connected via NtN)
        │<─────────────────────────────┤
        │                              │
        │  ChainSync.GetCurrentTip()   │
        ├─────────────────────────────>│
        │                              │  local query, no network hop
        │<─────── Point{slot, hash} ───┤
        │
        fmt.Printf(...)

Two things worth noticing:

  • NtC vs NtN. chain-tip uses Node-to-Client over a Unix socket (Dolos is the "node" here). Other programs like block-fetch and peer-sharing use Node-to-Node over TCP and connect to a public relay directly. Both modes are gOuroboros features.
  • Nothing is long-running. chain-tip prints once and exits. chain-sync streams. Each program picks the right lifetime for its mini-protocol.

Common Issues

dial unix ...: connect: no such file or directory

Dolos isn't running, or CARDANO_NODE_SOCKET_PATH is wrong. ls the path literally to confirm.

handshake failed: refused, reason: ...

Usually a network-magic mismatch. Check CARDANO_NODE_MAGIC=1 (for preprod) matches [upstream] network_magic in dolos.toml.

go: cannot find main module

You ran go run from the wrong directory. All go run ./cmd/<name> invocations assume you're at the root of the starter-kit repo (the directory containing go.mod).

Tip prints but is hours behind

Dolos is still syncing. Run dolos daemon in the foreground and watch its log — the slot number should advance quickly until it reaches the live chain.


You'll Know You're Successful When

  • go run ./cmd/chain-tip prints a recent slot and block hash
  • The slot number matches the current preprod tip (within a few blocks) on Cardanoscan
  • You can re-run the command and see the slot advance

Practice Tasks

  • Run chain-tip three times with a few seconds between each. Note how the slot advances — this is the chain in motion.
  • Try overriding one variable on a single command: CARDANO_NODE_MAGIC=2 go run ./cmd/chain-tip. Observe the handshake error. This is the guardrail working.
  • Read cmd/chain-tip/main.go top-to-bottom (~100 lines). Identify the two mini-protocol calls: NewConnection and GetCurrentTip.

What's Next

  • 101.2 — fetch a specific historical block with block-fetch
  • 101.3 — check node sync progress with chain-tip and chain-sync -tip
  • 101.4 — inspect the mempool with tx-monitor

Each of the remaining Module 101 lessons uses the same starter-kit you just set up. No more cloning needed.