Skip to content

Latest commit

Β 

History

316 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ•ΉΒ Β arcade

A P2P-first Bitcoin transaction broadcast client for Teranode with Arc-compatible API


Release Go Version License


CI / CD Β Β  Build Last Commit Β Β Β Β  Quality Β Β  Coverage
Security Β Β  Scorecard Security Β Β Β Β  Community Β Β  Contributors Ask DeepWiki


Project Navigation

πŸ“¦Β Installation πŸš€Β QuickΒ Start πŸ“šΒ Documentation
🐳 DockerΒ Guide ☸️ DeploymentΒ Guide πŸ—οΈΒ Architecture
πŸ§ͺΒ ExamplesΒ &Β Tests ⚑ Benchmarks πŸ› οΈΒ CodeΒ Standards
πŸ€–Β AIΒ Usage πŸ“šΒ Resources 🀝 Contributing
πŸ‘₯Β Maintainers πŸ“Β License

πŸ“¦ Installation

arcade requires a supported release of Go.

go get -u github.com/bsv-blockchain/arcade

πŸš€ Quick Start

Looking for per-network setup (mainnet / testnet / teratestnet / regtest)? See docs/getting-started.md.

Prerequisites

  • Go 1.27+ (see go.mod for exact version)
  • SQLite (included with most systems)
  • Teranode broadcast URL (e.g., https://arc.taal.com)

Build from Source

git clone https://github.com/bsv-blockchain/arcade.git
cd arcade
go build -o arcade cmd/arcade/main.go

Configuration

Create config.yaml with your Teranode broadcast URL:

# Minimal working configuration with no dependencies
mode: all
network: main
storage_path: ~/.arcade

callback_url: "https://myhostname.com"

kafka:
  backend: memory
  consumer_group: arcade

store:
  backend: pebble
  pebble:
    path: ~/.arcade/pebble
    memtable_size_mb: 64
    l0_compaction_threshold: 4
    sync_writes: false

merkle_service:
  url: "https://merkle-service-us-1.bsvb.tech"

p2p:
  datahub_discovery: true

chaintracks_server:
  enabled: true

See config.example.yaml for all available options.

Run

arcade --config config.yaml

You should see output indicating the server is running on port 8080.


πŸ“š Documentation

Overview

Arcade is a lightweight transaction broadcast service that:

  • Registers transactions with Merkle Service
  • Provides Arc-compatible HTTP API for easy migration
  • Supports pluggable storage and event backends (in-memory)
  • Tracks transaction status through the complete lifecycle
  • Delivers notifications via webhooks and Server-Sent Events (SSE)

What is Teranode? Teranode is the next-generation BSV node implementation designed for enterprise-scale transaction processing. Arcade acts as a bridge between your application and the Teranode network, handling transaction submission and status tracking.


Features

  • Arc-Compatible API - Drop-in replacement for Arc clients
  • Chain Tracking - Blockchain header management with merkle proof validation
  • Flexible Storage - Storage interface for different scaling needs
  • Event Streaming - In-memory pub/sub for event distribution
  • Webhook Delivery - Async notifications with retry logic
  • [TODO] SSE Streaming - Real-time status updates with automatic catchup on reconnect
  • Transaction Validation - Local validation before network submission
  • Status Tracking - Complete audit trail of transaction lifecycle
  • Extensible - All packages public, easy to customize
  • API Reference – Dive into the godocs at pkg.go.dev/github.com/bsv-blockchain/arcade

API Usage

Submit Transaction (POST /tx)

curl -X POST http://localhost:3011/tx \
  -H "Content-Type: text/plain" \
  -H "X-CallbackUrl: https://myapp.com/webhook" \
  --data "<hex-encoded-transaction>"

Get Transaction Status (GET /tx/{txid})

curl http://localhost:3011/tx/{txid}

Health Check (GET /health)

curl http://localhost:3011/health

API Docs (GET /docs)

Interactive API documentation (Scalar UI) available at http://localhost:3011/docs

Transaction Status Flow

Client β†’ Arcade
   ↓
RECEIVED (validated locally)
   ↓
SENT_TO_NETWORK (submitted to Teranode via HTTP)
   ↓
ACCEPTED_BY_NETWORK (acknowledged by Teranode)
   ↓
SEEN_ON_NETWORK (heard in subtree gossip - in mempool)
   ↓
MINED (heard in block gossip - included in block)

Or rejected:

REJECTED (from rejected-tx gossip)
DOUBLE_SPEND_ATTEMPTED (from rejected-tx gossip with specific reason)

Differences from Arc

  • Simpler Deployment - Single binary with SQLite, no PostgreSQL/NATS required
  • P2P-First - Direct gossip listening instead of node callbacks
  • Teranode-Only - Designed for Teranode, no legacy node support
  • Extensible - All packages public for customization
Configuration Reference

Required Fields

Field Description Default
teranode.broadcast_urls Teranode broadcast service URLs (array) Required

Optional Fields

Field Description Default
mode Operating mode: embedded, remote embedded
url Arcade server URL (required for remote mode) -
network Bitcoin network: main, test, stn main
storage_path Data directory for persistent files ~/.arcade
log_level Log level: debug, info, warn, error info
server.address HTTP server listen address :3011
server.read_timeout HTTP read timeout 30s
server.write_timeout HTTP write timeout 30s
server.shutdown_timeout Graceful shutdown timeout 10s
database.type Storage backend: sqlite sqlite
database.sqlite_path SQLite database file path ~/.arcade/arcade.db
events.type Event backend: memory memory
events.buffer_size Event channel buffer size 1000
teranode.datahub_urls DataHub URLs for fetching block data (array) -
teranode.auth_token Authentication token for Teranode API -
teranode.timeout HTTP request timeout 30s
validator.max_tx_size_policy Maximum transaction size (bytes); 0 tracks the network 0 (β†’ 10485760)
validator.max_script_size_policy Maximum script size (bytes); 0 tracks the network 0 (β†’ 500000)
validator.max_tx_sigops_counts_policy Maximum signature operations (0 = unlimited) 0
validator.min_fee_per_kb Minimum fee per KB (satoshis); 0 tracks the network 0 (β†’ 100)
webhook.max_retries Max webhook retry attempts 10
auth.enabled Enable Bearer token authentication false
auth.token Bearer token (required if auth enabled) -

Planned but not yet implemented:

  • database.type: postgres - PostgreSQL storage backend
  • events.type: redis - Redis event backend for distributed deployments
HTTP Headers

Arcade supports Arc-compatible headers:

  • X-CallbackUrl - Webhook URL for async status updates
  • X-CallbackToken - Token for webhook auth and SSE stream filtering
  • X-FullStatusUpdates - Include all intermediate statuses (default: final only)
  • X-SkipFeeValidation - Skip fee validation
  • X-SkipScriptValidation - Skip script validation
Webhook Notifications

When you provide X-CallbackUrl, Arcade will POST status updates:

{
  "timestamp": "2024-03-26T16:02:29.655390092Z",
  "txid": "...",
  "txStatus": "SEEN_ON_NETWORK",
  "blockHash": "...",
  "blockHeight": 123456,
  "merklePath": "..."
}

Features:

  • Automatic retries with linear backoff (1min, 2min, 3min, etc.)
  • Configurable max retries via webhook.max_retries
  • Every POST carries User-Agent: arcade-webhook/<version> β€” allowlist the arcade-webhook/ prefix at your edge so bot/WAF rules don't silently reject deliveries
  • Delivery self-diagnosis: GET /tx/{txid}?callbackToken=<token> returns a callbacks array with attempts, lastAttemptAt, and lastResult ("delivered" or the last failure, e.g. "status 403") for your submissions β€” if attempts climbs while your endpoint sees nothing, something in front of it is rejecting the POSTs
SSE Streaming

Arcade provides real-time transaction status updates via SSE, offering an alternative to webhook callbacks.

How It Works

  1. Submit Transaction with Callback Token:

    curl -X POST http://localhost:3011/tx \
      -H "Content-Type: text/plain" \
      -H "X-CallbackToken: my-token-123" \
      --data "<hex-encoded-transaction>"
  2. Connect SSE Client:

    const eventSource = new EventSource('http://localhost:3011/events?callbackToken=my-token-123');
    
    eventSource.addEventListener('status', (e) => {
      const update = JSON.parse(e.data);
      console.log(`${update.txid}: ${update.status}`);
    });
  3. Receive Real-Time Updates:

    id: 1699632123456789000
    event: status
    data: {"txid":"abc123...","status":"SENT_TO_NETWORK","timestamp":"2024-11-10T12:00:00Z"}
    

Catchup on Reconnect

When the SSE connection drops, the browser's EventSource automatically reconnects and sends the Last-Event-ID header. Arcade replays all missed events since that timestamp.

No client code needed - this is handled automatically by the EventSource API.

Event ID Format

Event IDs are nanosecond timestamps (time.UnixNano()), ensuring:

  • Chronological ordering
  • Virtually collision-free IDs
  • Easy catchup queries by time

Use Cases

  • Webhooks: Server-to-server notifications with retry logic
  • SSE: Real-time browser updates with automatic reconnection
  • Both: Use the same X-CallbackToken for webhooks AND SSE streaming

Filtering

Each SSE connection only receives events for transactions submitted with the matching callback token. This allows:

  • Multiple users/sessions with isolated event streams
  • Scoped access without complex authentication
  • Simple token-based routing

See examples/sse_client.html and examples/sse_client.go for complete examples.

Remote Client

For applications that need Arcade functionality without running a full server, use the REST client:

import "github.com/bsv-blockchain/arcade/client"

c := client.New("http://arcade-server:3011")
defer c.Close() // Always close when done to clean up SSE connections

// Submit a single transaction
status, err := c.SubmitTransaction(ctx, rawTxBytes, nil)

// Submit multiple transactions
statuses, err := c.SubmitTransactions(ctx, [][]byte{rawTx1, rawTx2}, nil)

// Get transaction status
status, err := c.GetStatus(ctx, "txid...")

// Get policy configuration
policy, err := c.GetPolicy(ctx)

// Subscribe to status updates for a callback token
statusChan, err := c.Subscribe(ctx, "my-callback-token")
for status := range statusChan {
    fmt.Printf("Status: %s %s\n", status.TxID, status.Status)
}
Extending Arcade

All packages are public and designed for extension:

Custom Storage Backend

import "github.com/bsv-blockchain/arcade/store"

type MyStore struct {}

func (s *MyStore) GetOrInsertStatus(ctx context.Context, status *models.TransactionStatus) (*models.TransactionStatus, bool, error) {
    // Your implementation - returns (existing status, was inserted, error)
    // If transaction already exists, return existing status with inserted=false
}

// Implement other store.Store methods...

Custom Event Handler

import "github.com/bsv-blockchain/arcade/events"

type MyHandler struct {
    publisher events.Publisher
}

func (h *MyHandler) Start(ctx context.Context) error {
    ch, _ := h.publisher.Subscribe(ctx)
    for update := range ch {
        // Handle status update
    }
}
Troubleshooting

Server fails to start with "no teranodes configured"

  • Ensure teranode.broadcast_urls is set in your config file with at least one valid URL

Transactions stuck in SENT_TO_NETWORK

  • Check your Teranode broadcast URL is reachable
  • Verify network connectivity and firewall rules

SQLite errors

  • Ensure storage_path directory exists and is writable
  • Check disk space availability

πŸ—οΈ Architecture

Key Components

  • Arcade (arcade.go) - Core P2P listener that subscribes to block, subtree, and rejected-tx gossip topics
  • Store (store/) - SQLite storage for transaction statuses and webhook tracking
  • TxTracker (store/tracker.go) - In-memory index of transactions being monitored
  • Event Publisher (events/) - In-memory pub/sub for distributing status updates
  • Webhook Handler (handlers/webhook.go) - Delivers status updates with retry logic
  • HTTP Routes (routes/fiber/) - Arc-compatible REST API including SSE streaming

Chain Tracking

Arcade uses go-chaintracks for blockchain header tracking and merkle proof validation. Headers are loaded from embedded checkpoint files on startup and updated via P2P block announcements.

For detailed architecture documentation, see doc.md.


πŸ§ͺ Examples & Tests

All unit tests and examples run via GitHub Actions and use Go version 1.27.x. View the configuration file.

Run all tests (fast):

magex test

Run all tests with race detector (slower):

magex test:race

See examples/ for SSE client examples and the combined server example.


⚑ Benchmarks

Run the Go benchmarks:

magex bench

Note: Comprehensive benchmarks for P2P operations (peer discovery, message throughput, connection establishment) are planned for future releases. The current focus is on correctness and stability of the networking implementation.


πŸ› οΈ Code Standards

Read more about this Go project's code standards.


πŸ€– AI Usage & Assistant Guidelines

Read the AI Usage & Assistant Guidelines for details on how AI is used in this project and how to interact with AI assistants.


πŸ“š Resources


🀝 Contributing

View the contributing guidelines and please follow the code of conduct.

How can I help?

All kinds of contributions are welcome πŸ™Œ! The most basic way to show your support is to star 🌟 the project, or to raise issues πŸ’¬.

Stars


πŸ‘₯ Maintainers

Siggi Galt MrZ
Siggi Dylan MrZ

πŸ“ License

License

About

Next generation BSV Blockchain Transaction Broadcaster for Teranode - Codename Arcade

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages