Andrew Miller 2bc57c073d go: keepalive, exponential backoff, chain_id metadata, durability guarantees
Three related fixes that turn the go template into a client that
survives the full matrix of server restart, client restart, network
blip, half-open TCP, and long outages (hours → months) — without the
user writing a line of reconnect logic in process.go.

1. gRPC keepalive: Time=10s, Timeout=3s, PermitWithoutStream=true.
   Half-open TCP (silent server restart, resumed laptop, NAT drop)
   is detected within ~13s. Previously the OS TCP keepalive took
   ~2h to notice, leaving the client as a ghost stream while prime
   logged "no active gRPC connection" for every skipped transaction.

2. Exponential backoff with jitter on reconnect. Effective delay =
   min(max_backoff_seconds, reconnect_delay_seconds * 2^attempts)
   + random(0, reconnect_delay_seconds). The attempts counter resets
   after any session that runs healthy for 60+ seconds. Jitter
   desynchronises clients so a server restart doesn't trigger a
   thundering herd. New max_backoff_seconds config field, default 120.

3. Unified error signalling: the sender goroutine now tears down the
   stream's context when it hits a Send error. Previously only Recv
   errors triggered a reconnect — a stale stream where only Send was
   broken could sit there indefinitely.

Also: chain_id is a required config field now and goes in the
x-chain-id gRPC metadata header alongside x-api-key and
x-smart-contract-id. Prime rejects streams without it with "missing
chain ID", which was silently breaking every template-based client
until users discovered it the hard way. README documents the
durability contract so contract authors know they don't have to
reimplement any of it.
2026-04-19 21:23:47 -04:00

Dragonchain Smart Contract Templates

This repository contains templates for creating smart contract clients that connect to Dragonchain Prime via gRPC.

Available Templates

Template Language Directory
Go Go 1.21+ go/
Python Python 3.10+ python/
TypeScript Node.js 18+ typescript/

How It Works

Smart contracts connect to the Dragonchain Prime server using a bi-directional gRPC stream. The server sends transaction requests to your smart contract, which processes them and sends back responses.

┌─────────────────┐                    ┌─────────────────────┐
│                 │  SmartContractRequest │                     │
│   Dragonchain   │ ──────────────────────► │   Smart Contract    │
│   Prime Server  │                    │      Client          │
│                 │ ◄────────────────────── │                     │
│                 │  SmartContractResponse │                     │
└─────────────────┘                    └─────────────────────┘

Request Flow

  1. Your client connects to the server with API key and smart contract ID
  2. The server sends SmartContractRequest messages containing:
    • transaction_id - Unique identifier for correlation
    • transaction_json - The transaction data to process
    • env_vars - Environment variables
    • secrets - Secret values (API keys, credentials)
  3. Your client processes the transaction and sends back SmartContractResponse:
    • transaction_id - Same ID from the request
    • result_json - Your processing result as JSON
    • logs - Any logs captured during execution
    • output_to_chain - Whether to persist the result
    • error - Error message if processing failed

Quick Start

1. Choose a Template

Pick the template for your preferred language:

# For Go
cp -r go /path/to/my-smart-contract

# For Python
cp -r python /path/to/my-smart-contract

# For TypeScript/JavaScript
cp -r typescript /path/to/my-smart-contract

2. Configure

Edit config.yaml with your credentials:

server_address: "your-server:50051"
smart_contract_id: "your-smart-contract-id"
api_key: "your-api-key"

3. Implement Your Logic

Each template has a Process (Go), process (Python/TypeScript) function. Implement your business logic there:

Go (cmd/main.go):

func Process(ctx context.Context, txJSON string, envVars, secrets map[string]string) ProcessResult {
    // Your logic here
    return ProcessResult{Data: result, OutputToChain: true}
}

Python (main.py):

def process(tx_json: str, env_vars: dict, secrets: dict) -> ProcessResult:
    # Your logic here
    return ProcessResult(data=result, output_to_chain=True)

TypeScript (src/main.ts):

async function process(txJson: string, envVars: Record<string, string>, secrets: Record<string, string>): Promise<ProcessResult> {
    // Your logic here
    return { data: result, outputToChain: true };
}

4. Build and Run

Each template includes a Makefile:

# Install dependencies
make setup

# Generate proto code (Go and Python only)
make proto

# Build
make build

# Run
make run

Configuration Options

Option Description Default
server_address gRPC server address (host:port) Required
smart_contract_id Your smart contract ID Required
api_key API key for authentication Required
use_tls Enable TLS encryption false
tls_cert_path Path to TLS certificate -
num_workers Concurrent transaction processors 10
reconnect_delay_seconds Reconnection delay 5
max_reconnect_attempts Max retries (0 = infinite) 0

Environment Variables

Your smart contract receives these environment variables:

Variable Description
TZ Timezone
ENVIRONMENT Deployment environment
INTERNAL_ID Internal identifier
DRAGONCHAIN_ID Dragonchain ID
DRAGONCHAIN_ENDPOINT Dragonchain API endpoint
SMART_CONTRACT_ID This smart contract's ID
SMART_CONTRACT_NAME This smart contract's name
SC_ENV_* Custom environment variables

Secrets

Secrets are passed separately from environment variables and are prefixed with SC_SECRET_. Access them via the secrets parameter in your process function.

Concurrent Processing

All templates support concurrent transaction processing. Configure the number of workers with num_workers in your config file. Each incoming request is processed in parallel up to the worker limit.

Reconnection

All templates include automatic reconnection logic. If the connection is lost, the client will attempt to reconnect with exponential backoff based on reconnect_delay_seconds. Set max_reconnect_attempts to limit retry attempts (0 = infinite).

Docker Examples

Each template README includes a Docker example. General pattern:

# Build stage
FROM <base-image> AS builder
COPY . .
RUN <build-commands>

# Runtime stage
FROM <runtime-image>
COPY --from=builder <artifacts> .
CMD [<run-command>]

Development

Prerequisites

Go:

  • Go 1.21+
  • protoc
  • protoc-gen-go, protoc-gen-go-grpc

Python:

  • Python 3.10+
  • pip

TypeScript:

  • Node.js 18+
  • npm

Testing

Each template supports testing. Add tests and run:

make test

License

[Your License Here]

Description
Smart contract templates for Dragonchain
Readme 104 KiB
Languages
Python 29.5%
Go 29.2%
TypeScript 28.3%
Makefile 7.8%
Shell 5.2%