/sig

a Solana validator client implementation written in Zig

Primary LanguageZigApache License 2.0Apache-2.0


 ๐Ÿค–โšก  Sig - a Solana Zig validator client


Version Build status Zig License


Sig is a Solana validator client implemented in Zig. Read the introductory blog post for more about the goals of this project.

โš ๏ธ NOTE: This is a WIP, please open any issues for any bugs/improvements.

๐Ÿ“‹ Setup

Build Dependencies

Developer Tools

These tools are optional but recommended for a smooth development process.

Visual Studio Code

If you use VS Code, you should install the Zig Language extension. It can use your installed versions of Zig and ZLS, or it can download and manage its own internal versions.

You can use CodeLLDB to debug Zig code with lldb in VS Code's debugging GUI. If you'd like to automatically build the project before running the debugger, you'll need a zig build task.

tasks.json
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "zig build",
            "type": "shell",
            "command": "zig",
            "args": [
                "build",
                "--summary",
                "all"
            ],
            "options": {
                "cwd": "${workspaceRoot}"
            },
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared",
                "showReuseMessage": true,
                "clear": false
            },
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

To run the debugger, you need a run configuration. This launch.json includes an example for debugging gossip. Customize the args as desired.

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug Gossip Mainnet",
            "program": "${workspaceFolder}/zig-out/bin/sig",
            "args": ["gossip", "--entrypoint", "34.83.231.102:8001", "--entrypoint", "145.40.67.83:8001", "--entrypoint", "147.75.38.117:8001", "--entrypoint", "145.40.93.177:8001", "--entrypoint", "86.109.15.59:8001"],
            "cwd": "${workspaceFolder}",
            "preLaunchTask": "zig build"
        },
    ]
}

๐Ÿ”ง Build

zig build

๐Ÿš€ Run

Run Sig with zig or execute the binary you already built:

zig build run -- --help
./zig-out/bin/sig --help

These commands will be abbreviated as sig in the rest of this document.

๐Ÿ‘ค Identity

Sig stores its private key in ~/.sig/identity.key. On its first run, Sig will automatically generate a key if no key exists. To see the public key, use the identity subcommand.

sig identity

๐Ÿ“ž Gossip

To run Sig as a Solana gossip client, use the gossip subcommand. Specify entrypoints to connect to a cluster. Optionally use -p to specify a custom listening port (default is 8001). For more info about gossip, see the readme.

sig gossip -p <PORT> --entrypoint <IP>:<PORT>

The following IP addresses were resolved from domains found at https://docs.solana.com/clusters.

mainnet
sig gossip --entrypoint 34.83.231.102:8001 \
    --entrypoint 145.40.67.83:8001 \
    --entrypoint 147.75.38.117:8001 \
    --entrypoint 145.40.93.177:8001 \
    --entrypoint 86.109.15.59:8001
devnet
sig gossip --entrypoint 35.197.53.105:8001 \
    --entrypoint 147.75.55.147:8001 \
    --entrypoint 136.144.49.15:8001 \
    --entrypoint 145.40.71.85:8001 \
    --entrypoint 147.75.105.51:8001
testnet
sig gossip --entrypoint 35.203.170.30:8001 \
    --entrypoint 139.178.68.207:8001

Develop

See Setup to get your environment set up. See CONTRIBUTING.md for the code style guide.

๐Ÿงช Test

Run all tests.

zig build test

Include --summary all with any test command to see a summary of the test results.

Include a filter to limit which tests are run. Sig tests include their module name. For example, you can run all tests in gossip.crds_table like this:

zig build test --summary all -- gossip.crds_table

๐Ÿ“Š Benchmark

Run all benchmarks.

zig build benchmark

Run a benchmark group: socket_utils, gossip, or sync.

zig build benchmark -- gossip

๐Ÿ“ฆ Import Sig

Sig can be included as a dependency in your Zig project using build.zig.zon file (available for Zig >= 0.11). See the API documentation to learn more about how to use Sig as a library.

Steps - how to install Sig in your Zig project
  1. Declare Sig as a dependency in build.zig.zon:

    .{
        .name = "my-project",
        .version = "1.0.0",
        .dependencies = .{
    +       .sig = .{
    +           .url = "https://github.com/syndica/sig/archive/<COMMIT>.tar.gz",
    +       },
        },
    }
  2. Expose Sig as a module in build.zig:

    const std = @import("std");
    
    pub fn build(b: *std.Build) void {
        const target = b.standardTargetOptions(.{});
        const optimize = b.standardOptimizeOption(.{});
    
    +   const opts = .{ .target = target, .optimize = optimize };
    +   const sig_module = b.dependency("sig", opts).module("sig");
    
        const exe = b.addExecutable(.{
            .name = "test",
            .root_source_file = .{ .path = "src/main.zig" },
            .target = target,
            .optimize = optimize,
        });
    +   exe.addModule("sig", sig_module);
        exe.install();
    
        ...
    }
  3. Obtain Sig's package hash:

    $ zig build
    my-project/build.zig.zon:6:20: error: url field is missing corresponding hash field
            .url = "https://github.com/syndica/sig/archive/<COMMIT>.tar.gz",
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    note: expected .hash = "<HASH>",
    
  4. Update build.zig.zon with hash value:

    .{
        .name = "my-project",
        .version = "1.0.0",
        .dependencies = .{
            .sig = .{
                .url = "https://github.com/syndica/sig/archive/<COMMIT>.tar.gz",
    +           .hash = "<HASH>",
            },
        },
    }

๐Ÿค” Why Zig?

Zig's own definition: Zig is a general-purpose programming language and toolchain for maintaining robust, optimal and reusable software.

  1. Optimized performance: Zig provides control over how your program runs at a low level, similar to languages like C. It allows fine-grained control over aspects such as memory management and system calls, which can lead to improved performance.

  2. Safety focus: Zig has features built in to prevent common bugs and safety issues common in C. For example, it includes built-in testing and bounds checking, which can help avoid problems such as buffer overflows and undefined behavior.

  3. Readability and maintainability: Zig syntax is designed to be straightforward and clear. This can make the code easier to understand, more maintainable, and less prone to bugs.

  4. No hidden control flow: Zig doesn't allow hidden control-flow like exceptions in some other languages. This can make it easier to reason about what your program is doing.

  5. Integration with C: Zig has excellent interoperation with C. You can directly include C libraries and headers in a Zig program, which can save time when using existing C libraries.

  6. Custom allocators: Zig allows you to define custom memory allocation strategies for different parts of your program. This provides the flexibility to optimize memory usage for specific use-cases or workloads.

Note

  • Zig is still an evolving language.
  • Many of the low-level APIs have been stabilized but std.http.Client and std.json are still WIP targetting stable implementations by >=0.11.
  • Currently, std.http.Client leaks and is failing some tests, fix is in works.

๐Ÿงฉ Modules

  • Gossip - A gossip spy node, run by: sig gossip or zig build run -- gossip

  • Core - Core data structures shared across modules.

  • RPC Client (docs) - A fully featured HTTP RPC client with ability to query all on-chain data along with sending transactions.

๐Ÿ“š Learn More

Zig

Solana

Sig