A complete blockchain implementation featuring: - synord: Full node with GHOSTDAG consensus - explorer-web: Modern React blockchain explorer with 3D DAG visualization - CLI wallet and tools - Smart contract SDK and example contracts (DEX, NFT, token) - WASM crypto library for browser/mobile
609 lines
14 KiB
Markdown
609 lines
14 KiB
Markdown
# Synor Developer Guide
|
|
|
|
> Build quantum-secure applications on the Synor blockchain
|
|
|
|
## Table of Contents
|
|
|
|
- [Quick Start](#quick-start)
|
|
- [Architecture Overview](#architecture-overview)
|
|
- [Running a Node](#running-a-node)
|
|
- [Using the CLI Wallet](#using-the-cli-wallet)
|
|
- [RPC API Reference](#rpc-api-reference)
|
|
- [Smart Contract Development](#smart-contract-development)
|
|
- [SDK Integration](#sdk-integration)
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
|
|
- Rust 1.75+ (`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`)
|
|
- RocksDB dependencies (see platform-specific instructions below)
|
|
|
|
**macOS:**
|
|
|
|
```bash
|
|
brew install rocksdb
|
|
```
|
|
|
|
**Ubuntu/Debian:**
|
|
|
|
```bash
|
|
sudo apt-get install librocksdb-dev libclang-dev
|
|
```
|
|
|
|
### Build from Source
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone https://github.com/g1-technologies/synor.git
|
|
cd synor
|
|
|
|
# Build all components
|
|
cargo build --workspace --release
|
|
|
|
# Run tests
|
|
cargo test --workspace
|
|
```
|
|
|
|
### First Steps
|
|
|
|
```bash
|
|
# 1. Initialize a new node (creates genesis block for devnet)
|
|
./target/release/synord init --network devnet
|
|
|
|
# 2. Start the node
|
|
./target/release/synord run --network devnet
|
|
|
|
# 3. Create a wallet (in another terminal)
|
|
./target/release/synor wallet create
|
|
|
|
# 4. Check your balance
|
|
./target/release/synor balance
|
|
```
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
Synor is a DAG-based blockchain with quantum-resistant cryptography.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Applications │
|
|
├──────────────┬──────────────┬──────────────┬───────────────────┤
|
|
│ synor-cli │ Web Wallet │ Explorer │ Faucet │
|
|
└──────┬───────┴──────┬───────┴──────┬───────┴─────────┬─────────┘
|
|
│ │ │ │
|
|
└──────────────┴──────────────┴─────────────────┘
|
|
│
|
|
┌─────────▼─────────┐
|
|
│ synor-rpc │ JSON-RPC API
|
|
└─────────┬─────────┘
|
|
│
|
|
┌──────────────────────┼──────────────────────┐
|
|
│ │ │
|
|
┌──────▼──────┐ ┌────────────▼────────────┐ ┌──────▼──────┐
|
|
│ synor-network│ │ synord (node) │ │synor-storage│
|
|
│ (libp2p) │ │ Consensus + Mempool │ │ (RocksDB) │
|
|
└──────┬──────┘ └────────────┬────────────┘ └──────┬──────┘
|
|
│ │ │
|
|
└──────────────────────┼──────────────────────┘
|
|
│
|
|
┌──────────────────────┼──────────────────────┐
|
|
│ │ │
|
|
┌──────▼──────┐ ┌────────────▼────────────┐ ┌──────▼──────┐
|
|
│ synor-dag │ │ synor-consensus │ │ synor-vm │
|
|
│ (GHOSTDAG) │ │ (UTXO + Validation) │ │ (WASM) │
|
|
└─────────────┘ └─────────────────────────┘ └─────────────┘
|
|
│
|
|
┌─────────▼─────────┐
|
|
│ synor-crypto │
|
|
│ Ed25519+Dilithium │
|
|
└───────────────────┘
|
|
```
|
|
|
|
### Key Components
|
|
|
|
| Crate | Purpose |
|
|
|-------|---------|
|
|
| `synor-crypto` | Hybrid Ed25519 + Dilithium3 signatures |
|
|
| `synor-types` | Core types (Address, Amount, Transaction, Block) |
|
|
| `synor-dag` | GHOSTDAG consensus ordering |
|
|
| `synor-consensus` | Block/transaction validation, UTXO management |
|
|
| `synor-storage` | RocksDB persistence layer |
|
|
| `synor-network` | P2P networking with libp2p |
|
|
| `synor-vm` | WASM smart contract execution |
|
|
| `synor-rpc` | JSON-RPC API definitions |
|
|
| `synord` | Full node daemon |
|
|
| `synor-cli` | Command-line wallet |
|
|
|
|
---
|
|
|
|
## Running a Node
|
|
|
|
### Configuration
|
|
|
|
Create `~/.synor/config.toml`:
|
|
|
|
```toml
|
|
[network]
|
|
network = "testnet" # mainnet, testnet, or devnet
|
|
|
|
[p2p]
|
|
listen_addr = "/ip4/0.0.0.0/tcp/16111"
|
|
max_peers = 50
|
|
|
|
[rpc]
|
|
http_enabled = true
|
|
http_addr = "127.0.0.1:16110"
|
|
ws_enabled = true
|
|
ws_addr = "127.0.0.1:16111"
|
|
|
|
[mining]
|
|
enabled = false
|
|
coinbase_address = "synor:qz..." # Your address for mining rewards
|
|
threads = 4
|
|
|
|
[storage]
|
|
data_dir = "~/.synor/data"
|
|
cache_size_mb = 512
|
|
```
|
|
|
|
### Network Selection
|
|
|
|
```bash
|
|
# Devnet (local development, fast blocks)
|
|
synord run --network devnet
|
|
|
|
# Testnet (public test network)
|
|
synord run --network testnet
|
|
|
|
# Mainnet (production)
|
|
synord run --network mainnet
|
|
```
|
|
|
|
### Node Commands
|
|
|
|
```bash
|
|
# Initialize chain
|
|
synord init --network testnet
|
|
|
|
# Run node
|
|
synord run --network testnet
|
|
|
|
# Export blocks
|
|
synord export --from 0 --to 1000 --output blocks.dat
|
|
|
|
# Import blocks
|
|
synord import --input blocks.dat
|
|
```
|
|
|
|
---
|
|
|
|
## Using the CLI Wallet
|
|
|
|
### Wallet Management
|
|
|
|
```bash
|
|
# Create new wallet (generates 24-word mnemonic)
|
|
synor wallet create
|
|
|
|
# Recover from mnemonic
|
|
synor wallet recover
|
|
|
|
# Show wallet info
|
|
synor wallet info
|
|
|
|
# List addresses
|
|
synor wallet addresses
|
|
|
|
# Generate new address
|
|
synor wallet new-address
|
|
```
|
|
|
|
### Transactions
|
|
|
|
```bash
|
|
# Check balance
|
|
synor balance
|
|
|
|
# Send SYNOR
|
|
synor send <address> <amount>
|
|
# Example: synor send synor:qz1234... 10.5
|
|
|
|
# View transaction
|
|
synor tx <hash>
|
|
|
|
# View mempool
|
|
synor mempool
|
|
```
|
|
|
|
### Block Queries
|
|
|
|
```bash
|
|
# Get block by hash
|
|
synor block <hash>
|
|
|
|
# Get block by blue score (DAG height equivalent)
|
|
synor block <blue_score>
|
|
|
|
# Get tips (current DAG tips)
|
|
synor tips
|
|
|
|
# Get chain info
|
|
synor info
|
|
```
|
|
|
|
---
|
|
|
|
## RPC API Reference
|
|
|
|
Connect to the RPC server at `http://localhost:16110` (HTTP) or `ws://localhost:16111` (WebSocket).
|
|
|
|
### Block Methods
|
|
|
|
```javascript
|
|
// Get block by hash
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getBlock",
|
|
"params": ["<hash>", true], // hash, include_txs
|
|
"id": 1
|
|
}
|
|
|
|
// Get blocks by blue score
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getBlocksByBlueScore",
|
|
"params": [1000, true], // blue_score, include_txs
|
|
"id": 1
|
|
}
|
|
|
|
// Get tips
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getTips",
|
|
"params": [],
|
|
"id": 1
|
|
}
|
|
|
|
// Get block count
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getBlockCount",
|
|
"params": [],
|
|
"id": 1
|
|
}
|
|
```
|
|
|
|
### Transaction Methods
|
|
|
|
```javascript
|
|
// Submit transaction
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_submitTransaction",
|
|
"params": ["<hex_encoded_tx>"],
|
|
"id": 1
|
|
}
|
|
|
|
// Get mempool size
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getMempoolSize",
|
|
"params": [],
|
|
"id": 1
|
|
}
|
|
```
|
|
|
|
### Network Methods
|
|
|
|
```javascript
|
|
// Get node info
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getInfo",
|
|
"params": [],
|
|
"id": 1
|
|
}
|
|
|
|
// Response:
|
|
{
|
|
"version": "0.1.0",
|
|
"protocolVersion": 1,
|
|
"peerCount": 8,
|
|
"blockCount": 12345,
|
|
"blueScore": 12340,
|
|
"mempoolSize": 42,
|
|
"synced": true
|
|
}
|
|
|
|
// Get peer info
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getPeerInfo",
|
|
"params": [],
|
|
"id": 1
|
|
}
|
|
|
|
// Get mining info
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_getMiningInfo",
|
|
"params": [],
|
|
"id": 1
|
|
}
|
|
```
|
|
|
|
### Contract Methods
|
|
|
|
```javascript
|
|
// Deploy contract
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_deployContract",
|
|
"params": {
|
|
"bytecode": "<hex_wasm>",
|
|
"init_args": "<hex_args>",
|
|
"deployer": "synor:qz...",
|
|
"gas_limit": 1000000
|
|
},
|
|
"id": 1
|
|
}
|
|
|
|
// Call contract
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"method": "synor_callContract",
|
|
"params": {
|
|
"contract_id": "<hex_id>",
|
|
"method": "transfer",
|
|
"args": "<hex_args>",
|
|
"caller": "synor:qz...",
|
|
"value": 0,
|
|
"gas_limit": 100000
|
|
},
|
|
"id": 1
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Smart Contract Development
|
|
|
|
### Quick Start
|
|
|
|
```bash
|
|
# Create new contract project
|
|
./scripts/new-contract.sh my_token
|
|
|
|
# Build contract
|
|
cd contracts/my_token
|
|
cargo build --target wasm32-unknown-unknown --release
|
|
|
|
# Optimize WASM (reduces size significantly)
|
|
synor-compiler optimize target/wasm32-unknown-unknown/release/my_token.wasm
|
|
```
|
|
|
|
### Contract Template
|
|
|
|
```rust
|
|
// contracts/my_token/src/lib.rs
|
|
#![no_std]
|
|
|
|
use synor_sdk::prelude::*;
|
|
|
|
#[synor_contract]
|
|
mod my_token {
|
|
use super::*;
|
|
|
|
// Storage keys
|
|
const TOTAL_SUPPLY: &[u8] = b"total_supply";
|
|
const BALANCES: &[u8] = b"balances";
|
|
|
|
/// Initialize the token
|
|
#[init]
|
|
pub fn init(initial_supply: u64) {
|
|
let caller = env::caller();
|
|
storage::set(TOTAL_SUPPLY, &initial_supply.to_le_bytes());
|
|
storage::set(&balance_key(&caller), &initial_supply.to_le_bytes());
|
|
|
|
env::emit_event("Initialized", &[
|
|
("supply", &initial_supply.to_string()),
|
|
("owner", &hex::encode(&caller)),
|
|
]);
|
|
}
|
|
|
|
/// Get balance of an address
|
|
#[view]
|
|
pub fn balance_of(address: Address) -> u64 {
|
|
storage::get(&balance_key(&address))
|
|
.map(|b| u64::from_le_bytes(b.try_into().unwrap()))
|
|
.unwrap_or(0)
|
|
}
|
|
|
|
/// Transfer tokens
|
|
#[call]
|
|
pub fn transfer(to: Address, amount: u64) -> bool {
|
|
let caller = env::caller();
|
|
let from_balance = balance_of(caller);
|
|
|
|
if from_balance < amount {
|
|
return false;
|
|
}
|
|
|
|
let to_balance = balance_of(to);
|
|
|
|
storage::set(&balance_key(&caller), &(from_balance - amount).to_le_bytes());
|
|
storage::set(&balance_key(&to), &(to_balance + amount).to_le_bytes());
|
|
|
|
env::emit_event("Transfer", &[
|
|
("from", &hex::encode(&caller)),
|
|
("to", &hex::encode(&to)),
|
|
("amount", &amount.to_string()),
|
|
]);
|
|
|
|
true
|
|
}
|
|
|
|
fn balance_key(address: &Address) -> Vec<u8> {
|
|
[BALANCES, address.as_bytes()].concat()
|
|
}
|
|
}
|
|
```
|
|
|
|
### Host Functions
|
|
|
|
Contracts can call these host functions (see `contracts/HOST_FUNCTIONS.md` for details):
|
|
|
|
| Function | Description |
|
|
|----------|-------------|
|
|
| `env::caller()` | Get caller address |
|
|
| `env::block_height()` | Current block height |
|
|
| `env::timestamp()` | Block timestamp |
|
|
| `env::value()` | SYNOR sent with call |
|
|
| `storage::get(key)` | Read from storage |
|
|
| `storage::set(key, value)` | Write to storage |
|
|
| `storage::delete(key)` | Delete from storage |
|
|
| `env::emit_event(name, data)` | Emit event |
|
|
| `crypto::hash(data)` | Blake3 hash |
|
|
| `crypto::verify(pubkey, msg, sig)` | Verify signature |
|
|
|
|
### Testing Contracts
|
|
|
|
```rust
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use synor_contract_test::*;
|
|
|
|
#[test]
|
|
fn test_transfer() {
|
|
let mut env = TestEnv::new();
|
|
let alice = env.create_account(1000);
|
|
let bob = env.create_account(0);
|
|
|
|
// Deploy contract
|
|
let contract = env.deploy("my_token", &alice, &[1000u64.to_le_bytes()]);
|
|
|
|
// Transfer tokens
|
|
env.call(&contract, &alice, "transfer", &[bob.as_bytes(), &100u64.to_le_bytes()]);
|
|
|
|
// Check balances
|
|
assert_eq!(env.view(&contract, "balance_of", &alice.as_bytes()), 900u64);
|
|
assert_eq!(env.view(&contract, "balance_of", &bob.as_bytes()), 100u64);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## SDK Integration
|
|
|
|
### JavaScript/TypeScript
|
|
|
|
```typescript
|
|
import { SynorClient, Wallet } from '@synor/sdk';
|
|
|
|
// Connect to node
|
|
const client = new SynorClient('http://localhost:16110');
|
|
|
|
// Create wallet from mnemonic
|
|
const wallet = Wallet.fromMnemonic(
|
|
'abandon abandon abandon ... art',
|
|
'' // passphrase
|
|
);
|
|
|
|
console.log('Address:', wallet.address);
|
|
|
|
// Get balance
|
|
const balance = await client.getBalance(wallet.address);
|
|
console.log('Balance:', balance.confirmed, 'SYNOR');
|
|
|
|
// Send transaction
|
|
const tx = await wallet.createTransaction({
|
|
to: 'synor:qz1234...',
|
|
amount: '10.5',
|
|
});
|
|
const result = await client.submitTransaction(tx);
|
|
console.log('TX Hash:', result.transactionId);
|
|
```
|
|
|
|
### Rust
|
|
|
|
```rust
|
|
use synor_types::{Address, Amount};
|
|
use synor_crypto::{Mnemonic, HybridKeypair, Network};
|
|
|
|
// Generate new wallet
|
|
let mnemonic = Mnemonic::generate(24)?;
|
|
let keypair = HybridKeypair::from_mnemonic(&mnemonic, "")?;
|
|
let address = keypair.address(Network::Testnet);
|
|
|
|
println!("Mnemonic: {}", mnemonic.phrase());
|
|
println!("Address: {}", address);
|
|
|
|
// Sign a message
|
|
let message = b"Hello, Synor!";
|
|
let signature = keypair.sign(message);
|
|
|
|
// Verify
|
|
assert!(keypair.public_key().verify(message, &signature).is_ok());
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
**"Failed to open database"**
|
|
|
|
```bash
|
|
# Check data directory permissions
|
|
ls -la ~/.synor/data
|
|
|
|
# Remove corrupted database (WARNING: loses local data)
|
|
rm -rf ~/.synor/data
|
|
synord init --network testnet
|
|
```
|
|
|
|
**"No peers found"**
|
|
|
|
```bash
|
|
# Check network connectivity
|
|
synor peers
|
|
|
|
# Manually add peer
|
|
synor peer add /ip4/1.2.3.4/tcp/16111/p2p/<peer_id>
|
|
```
|
|
|
|
**"Transaction rejected"**
|
|
|
|
- Check sufficient balance (including fees)
|
|
- Verify recipient address format
|
|
- Check mempool isn't full
|
|
|
|
### Logs
|
|
|
|
```bash
|
|
# Enable debug logging
|
|
RUST_LOG=debug synord run
|
|
|
|
# Specific component logging
|
|
RUST_LOG=synor_network=debug,synor_consensus=info synord run
|
|
```
|
|
|
|
---
|
|
|
|
## Resources
|
|
|
|
- **GitHub**: https://github.com/g1-technologies/synor
|
|
- **Testnet Faucet**: https://faucet.synor.cc
|
|
- **Block Explorer**: https://explorer.synor.cc
|
|
- **Discord**: https://discord.gg/synor
|
|
|
|
---
|
|
|
|
*Last updated: January 7, 2026*
|