Skip to content

block52/poker-vm

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Poker VM

PVM UnitTests UI Build UI Tests CVE-2025-55182

A stateless execution layer for poker game logic on the Block52 blockchain network.

image

Architecture

The Poker VM (PVM) is a pure execution layer that processes poker game logic without maintaining persistent state. All game state is stored on the blockchain, making the PVM stateless, horizontally scalable, and fault-tolerant.

Key Principles

  • Stateless Execution: PVM reads state from blockchain, executes game logic, returns results
  • No Database: No MongoDB, Redis, or external storage - blockchain is the single source of truth
  • Pure Functions: Game logic is deterministic and side-effect free
  • Horizontal Scaling: Multiple PVM instances can run in parallel
  • Real-time Updates: WebSocket connections for live game state synchronization

Components

  • PVM Core: TypeScript-based poker game logic engine
  • RPC Interface: JSON-RPC endpoint for transaction submission and queries
  • WebSocket Server: Real-time game state updates for connected clients
  • REST API: Health checks and utility endpoints

Benefits

  • No Data Migration: Spin up new PVM instances without data sync
  • Instant Failover: Any instance can handle any request
  • Global Distribution: Deploy PVM nodes globally for low latency
  • Cost Efficient: No database hosting or maintenance costs
  • Deterministic: Same input always produces same output
  • Testable: Pure functions make testing straightforward

Quick Start

Prerequisites

  • Node.js 20+
  • Yarn
  • A running Block52 blockchain node (for production use)

Local Development

  1. Clone the repository:

    git clone https://github.com/block52/poker-vm.git
    cd poker-vm
  2. Start the PVM server:

    cd pvm/ts
    yarn install
    yarn dev
  3. Start the UI (optional):

    cd ui
    yarn install
    yarn dev
  4. Access services:

Production Setup

The PVM connects to a Block52 blockchain node for state storage:

# Set blockchain node endpoint (optional, defaults to localhost:26657)
export BLOCKCHAIN_RPC=https://node1.block52.xyz/rpc/

cd pvm/ts
yarn build
yarn start

Public PVM Endpoint

A public PVM instance is available for development and testing:

Endpoint URL
RPC https://pvm.block52.xyz
Health https://pvm.block52.xyz/health

Example: Query the PVM

# Health check
curl https://pvm.block52.xyz/health

# Get client info
curl -X POST https://pvm.block52.xyz \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "method": "get_client", "params": [], "id": 1}'

Available RPC Methods:

Category Methods
Read find_contract, get_account, get_block, get_blocks, get_block_by_hash, get_client, get_contract_schema, get_game_state, get_last_block, get_mempool, get_nodes, get_shared_secret, get_transaction, get_transactions
Write block, burn, create_account, create_contract_schema, deploy_contract, mine, mined_block_hash, mint, new_hand, new_table, perform_action, transfer, withdraw

Blockchain Network Endpoints

Network RPC REST gRPC WebSocket
Localhost http://localhost:26657 http://localhost:1317 http://localhost:9090 ws://localhost:26657/ws
Texas Hodl https://texashodl.net/rpc https://node.texashodl.net grpcs://texashodl.net:9443 wss://texashodl.net/ws
Block52 https://node1.block52.xyz/rpc/ https://node1.block52.xyz grpcs://node1.block52.xyz:9443 wss://node1.block52.xyz/ws

Development

PVM Architecture

The PVM is a stateless execution layer with three main interfaces:

  1. RPC Endpoint (http://localhost:8545):

    • Submit transactions
    • Query game state
    • JSON-RPC 2.0 compatible
  2. WebSocket Server (ws://localhost:8545/ws):

    • Real-time game state updates
    • Connect with ?tableAddress=<table_id>&playerId=<player_address>
    • Automatic reconnection handling
  3. REST API (http://localhost:8545/health):

    • Health checks
    • Metrics and diagnostics

Testing

Run unit tests:

cd pvm/ts
yarn test

Run integration tests:

cd pvm/ts
yarn test:integration

PHH Format Testing

The engine supports replaying hands in PHH (Poker Hand History) format for fuzz testing and validation against real-world hand histories.

cd pvm/ts
yarn test tests/phh/

Supported PHH Features:

  • No-Limit Texas Hold'em (variant = "NT")
  • Action mapping: cbr (check/bet/raise), cc (check/call), f (fold), sm (show)
  • Automatic blind posting and dealing
  • Total-to-additional amount conversion for raises

Example: Running a PHH hand through the engine

import { PhhRunner } from "./src/testing/phhRunner";

const runner = new PhhRunner();
const result = await runner.runHand(`
variant = "NT"
blinds_or_straddles = [100, 200]
starting_stacks = [10000, 10000]
players = ["P1", "P2"]
actions = [
  "d dh p1 AcKc",
  "d dh p2 2h3h",
  "p1 cbr 600",
  "p2 cc",
  "d db Jc3d5c",
  "p1 cbr 800",
  "p2 f",
]
`);

console.log(result.success); // true
console.log(result.actionsExecuted); // 7

See GitHub Issue #1578 for integration progress with the PHH Dataset.

Building for Production

cd pvm/ts
yarn build

The build outputs to dist/ and can be run with:

node dist/index.js

Deployment

Docker Deployment

Build and run the PVM in a container:

cd pvm/ts
docker build -t poker-vm .
docker run -p 8545:8545 poker-vm

Environment Variables

Variable Default Description
PORT 8545 HTTP server port (always used for PVM)
BLOCKCHAIN_RPC http://localhost:26657 Block52 blockchain RPC endpoint
NODE_ENV development Environment mode

Horizontal Scaling

Since the PVM is stateless, you can run multiple instances behind a load balancer:

# Instance 1
PORT=8545 node dist/index.js

# Instance 2
PORT=8546 node dist/index.js

# Instance 3
PORT=8547 node dist/index.js

Configure your load balancer (nginx, HAProxy, etc.) to distribute requests across instances.

Health Checks

The PVM provides health check endpoints for monitoring:

curl http://localhost:8545/health

Response:

{
    "status": "healthy",
    "uptime": 12345,
    "version": "1.0.0"
}

Game Features

Player Status

The PVM tracks various player states throughout the game:

Status Description Can Act Receives Cards In Dealer Rotation Notes
ACTIVE Player is actively participating Default status for players in a hand
FOLDED Player has folded their hand Cannot act until next hand
ALL_IN Player has bet all their chips Eligible for side pots
SITTING_OUT Player is away or joined mid-hand Skipped in dealing and betting
SHOWING Player is showing cards at showdown Cards revealed to table
BUSTED Player has no chips left Eliminated from tournament

Status Transitions:

stateDiagram-v2
    [*] --> SITTING_OUT : Join mid-hand
    [*] --> ACTIVE : Join before hand

    SITTING_OUT --> ACTIVE : New hand starts\nor Sit-in action

    ACTIVE --> FOLDED : Fold
    ACTIVE --> ALL_IN : Bet all chips
    ACTIVE --> SITTING_OUT : Sit out action\nor 0 chips (cash)
    ACTIVE --> SHOWING : Showdown
    ACTIVE --> BUSTED : Lose all chips\n(tournament)

    ALL_IN --> SHOWING : Showdown

    FOLDED --> ACTIVE : New hand starts
    SHOWING --> ACTIVE : New hand starts
    ALL_IN --> ACTIVE : New hand starts\n(if chips won)

    BUSTED --> [*] : Eliminated
Loading

Game Round Flow

stateDiagram-v2
    [*] --> ANTE : Game starts

    ANTE --> PREFLOP : Blinds posted\n& cards dealt

    PREFLOP --> FLOP : Betting complete
    PREFLOP --> SHOWDOWN : All-in called
    PREFLOP --> END : All fold

    FLOP --> TURN : Betting complete
    FLOP --> SHOWDOWN : All-in called
    FLOP --> END : All fold

    TURN --> RIVER : Betting complete
    TURN --> SHOWDOWN : All-in called
    TURN --> END : All fold

    RIVER --> SHOWDOWN : Betting complete
    RIVER --> END : All fold

    SHOWDOWN --> END : Winner determined

    END --> ANTE : New hand
    END --> [*] : Game over
Loading

Join Timing Flow

flowchart TD
    A[Player Requests Join] --> B{Hand in Progress?}

    B -->|No - ANTE before blinds| C[Set ACTIVE]
    B -->|No - END round| C
    B -->|Yes - Blinds posted| D[Set SITTING_OUT]
    B -->|Yes - Any betting round| D

    C --> E[✅ Participate in current/next hand]
    D --> F[⏳ Wait for next hand]

    F --> G{New Hand Starts}
    G --> H[reInit activates player]
    H --> I[Set ACTIVE]
    I --> E
Loading

Hand Lifecycle Sequence

sequenceDiagram
    participant P1 as Player 1 (SB)
    participant P2 as Player 2 (BB)
    participant P3 as Player 3 (joins mid-hand)
    participant Game as Texas Holdem

    Note over Game: Round: ANTE
    P1->>Game: POST SMALL_BLIND
    P2->>Game: POST BIG_BLIND
    P1->>Game: DEAL
    Note over Game: Round: PREFLOP

    P3->>Game: JOIN (mid-hand)
    Game-->>P3: Status: SITTING_OUT
    Note over P3: No cards dealt

    P1->>Game: CALL
    P2->>Game: CHECK
    Note over Game: Round: FLOP

    P1->>Game: CHECK
    P2->>Game: BET
    P1->>Game: FOLD
    Note over P1: Status: FOLDED

    Note over Game: Round: END
    Game-->>P2: Winner!

    P2->>Game: NEW_HAND
    Note over Game: reInit() called
    Game-->>P1: Status: ACTIVE
    Game-->>P3: Status: ACTIVE
    Note over P3: Now eligible for cards
Loading

Join Timing Matrix

Players joining at different game phases receive different initial statuses:

Current Round Blinds Posted Player Status on Join Can Play This Hand
ANTE No ACTIVE ✅ Yes
ANTE Yes SITTING_OUT ❌ No (next hand)
PREFLOP Yes SITTING_OUT ❌ No (next hand)
FLOP Yes SITTING_OUT ❌ No (next hand)
TURN Yes SITTING_OUT ❌ No (next hand)
RIVER Yes SITTING_OUT ❌ No (next hand)
SHOWDOWN Yes SITTING_OUT ❌ No (next hand)
END N/A ACTIVE ✅ Yes (next hand)

Dealer Manager Behavior

The dealer manager uses player status to determine positions and turn order:

Player Status Eligible for Dealer Eligible for Blinds Included in Turn Order Receives Cards
ACTIVE
FOLDED
ALL_IN ✅ (already)
SITTING_OUT
SHOWING ✅ (already)
BUSTED

Action Validation by Status

Which actions each player status can perform:

Player Status Bet/Raise Call Check Fold All-In Show Muck Sit Out Sit In
ACTIVE
FOLDED
ALL_IN
SITTING_OUT
SHOWING
BUSTED

WebSocket Connection

Connect to a live poker table for real-time updates:

const ws = new WebSocket("ws://localhost:8545/ws?tableAddress=<table_id>&playerId=<player_address>");

ws.onmessage = event => {
    const message = JSON.parse(event.data);
    if (message.type === "gameStateUpdate") {
        console.log("Game state updated:", message.gameState);
    }
};

Message Types:

  • connected: WebSocket connection established
  • gameStateUpdate: Game state changed (player action, new round, etc.)
  • error: Error occurred during processing

RPC Interface

Submit transactions via JSON-RPC:

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "poker.action",
    "params": {
      "tableId": "0x123...",
      "playerId": "block52...",
      "action": "bet",
      "amount": 100
    },
    "id": 1
  }'

SDK

The Block52 SDK provides TypeScript/JavaScript interfaces for interacting with the PVM:

import { Block52Client } from "@bitcoinbrisbane/block52";

const client = new Block52Client({
    rpc: "https://node1.block52.xyz/rpc/",
    rest: "https://node1.block52.xyz",
    grpc: "grpcs://node1.block52.xyz:9443"
});

// Submit a poker action
await client.poker.bet({
    tableId: "0x123...",
    playerId: "block52...",
    amount: 100
});

// Query table state
const tableState = await client.poker.getTableState("0x123...");

Installation

npm install @bitcoinbrisbane/block52
# or
yarn add @bitcoinbrisbane/block52

Publishing (Maintainers)

cd sdk
nvm use 20.18
yarn prepare && yarn publish

For detailed SDK documentation, see sdk/README.md.

Blockchain Integration

The PVM operates as a stateless execution layer on top of the Block52 blockchain:

┌─────────────────────────────────┐
│      Client (UI/Bot/SDK)        │
│   (Submit transactions)         │
└─────────────┬───────────────────┘
              ↓
┌─────────────────────────────────┐
│   PVM (Execution Layer)         │  ← Stateless poker logic
│   - Validate transactions       │
│   - Execute game rules          │
│   - Calculate outcomes          │
└─────────────┬───────────────────┘
              ↓
┌─────────────────────────────────┐
│   Block52 Blockchain            │  ← State storage
│   - Store game state            │
│   - Manage player accounts      │
│   - Handle chip escrow          │
└─────────────────────────────────┘

Data Flow

  1. Client → PVM: Submit poker action (bet, fold, call, etc.)
  2. PVM → Blockchain: Read current game state
  3. PVM: Execute game logic, validate action
  4. PVM → Blockchain: Write updated state
  5. PVM → Client: Broadcast update via WebSocket

Smart Contracts

Contract Description Address Network
Bridge Deposit stables to poker VM 0x092eEA7cE31C187Ff2DC26d0C250B011AEC1a97d mainnet
Vault Validator staking 0x893c26846d7cE76445230B2b6285a663BF4C3BF5 mainnet

Project Structure

poker-vm/
├── pvm/ts/              # PVM execution layer (TypeScript)
│   ├── src/
│   │   ├── core/        # Game logic engine
│   │   ├── rpc.ts       # JSON-RPC interface
│   │   ├── websocket.ts # Real-time connections
│   │   └── index.ts     # Server entry point
│   └── tests/           # Unit and integration tests
├── sdk/                 # TypeScript SDK for clients
├── ui/                  # React-based poker UI
├── contracts/           # Solidity smart contracts
├── bot/                 # Bot implementations
│   ├── ts/              # TypeScript bots
│   └── python/          # Python bot framework
└── tests/               # End-to-end tests

Email

pitboss at block 52 dot xyz

-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: 406F D0E4 4DC5 B26E F121  58C4 36F2 5F29 0099 78F4
Comment: Pit Boss <pitboss@block52.xyz>

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
1MIHZBpp/rvs
=XIiJ
-----END PGP PUBLIC KEY BLOCK-----

Security

CVE-2025-55182 (React2Shell) Status: ✅ Not Affected

This repository has been analyzed for the critical CVE-2025-55182 vulnerability affecting React Server Components and Next.js. The poker-vm repository is NOT vulnerable as it uses React 18.3.1 and does not use Next.js or React Server Components.

For full details, see SECURITY-CVE-2025-55182.md.

Running Security Checks

To verify the repository remains free of CVE-2025-55182 vulnerabilities:

./scripts/check-react-cve-2025-55182.sh

This script checks all package.json and lock files for vulnerable React Server or Next.js versions.

Contributing

Contributions are welcome! Please see our contributing guidelines for more information.

License

MIT License - see LICENSE for details.

About

Blockchain Poker... again

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 60.8%
  • HTML 32.5%
  • Haskell 1.8%
  • JavaScript 1.6%
  • Shell 1.0%
  • Solidity 0.8%
  • Other 1.5%