How it is built
Architecture overview
A casino floor holds hundreds to thousands of electronic gaming machines (EGMs) plus tables, and an operator must know, to the cent, what each machine took in and paid out, who played, and which vouchers are outstanding. The casino management system (CMS) is the back-office service that does this: it polls machines for meters and events, accounts for cashless play and ticket-in/ticket-out (TITO) vouchers, tracks players through loyalty cards, runs promotions and bonuses, and reports to the regulator. Commercial examples are Light & Wonder, IGT ADVANTAGE and Konami Synkros; their internals are proprietary.
The central design fact is that money moves through a device that cannot be trusted to stay online, and the books must still balance. So the machine is the source of truth for its own cumulative meters, the host stores every event with a sequence number, and every cash-like movement (a voucher printed, a voucher redeemed, a transfer to the machine) is a small state machine with a unique id that is reconciled afterwards. A second fact shapes the rest: gaming is regulated, so the software that touches money is signed, verifiable and audited, and a change to it needs approval outside the engineering team.
Parts:
- Machine link — talk to EGMs over serial (SAS) or Ethernet (G2S), collect meters and events —
sas-g2s-protocols(no page yet), Message sequence numbers, CRC-32C checksums, Recursive-descent parsing,publish-subscribe-event-bus(no page yet) - Meter and event accounting — turn raw meters into verified daily figures — Event sourcing, Double-entry ledger, Money representation, Reconciliation,
resource-usage-accounting(no page yet) - Voucher and cashless engine — TITO tickets and fund transfers as persisted lifecycles — Payment state machine, Hierarchical state machine, Idempotency keys, Optimistic concurrency control,
gapless-sequence-numbers(no page yet),csprng(no page yet) - Player tracking and promotions — identify players, score play, trigger offers —
identity-resolution(no page yet), Entity resolution, Union-find,event-condition-action-rules(no page yet), Hierarchical timing wheel,time-decay-scoring(no page yet),largest-remainder-rounding(no page yet),benefit-accumulators(no page yet) - Compliance and reporting — regulator reports, audit trails, anomaly checks — Tamper-evident audit log, Time-series anomaly detection, Isolation forest
- Software integrity and keys — signed game and system software, protected keys —
code-signing(no page yet), Signed update metadata, Hardware security modules, Envelope encryption,key-rotation(no page yet), Message authentication codes, Mutual TLS - Reliability — redundancy, recovery, supervised services — Hot-standby redundancy, Primary-backup replication, Write-ahead log, Point-in-time recovery, Durable job queue, Process supervision, Graceful draining, Health checking,
hdr-histogram(no page yet) - Assurance — replayable tests and hostile-input tests — Deterministic simulation testing, Coverage-guided fuzzing
EGM ──RS-232 / SAS──► SMIB / gateway ──┐
EGM ──Ethernet / G2S─────────────────────┤
table, kiosk, cage ───────────────────────┤
▼
floor server (poll, parse, sequence, store)
│ events + meters (append-only)
┌─────────────────────────┼───────────────────────────┐
▼ ▼ ▼
ticket / cashless engine meter accounting player tracking
(state machine per ticket, (deltas per machine, (card in/out, rating,
idempotent, reconciled) ledger, variance checks) offers, bonuses)
│ │ │
└───────────┬─────────────┴───────────────────────────┘
▼
database: primary ─► hot standby (WAL) audit log (hash-chained)
│
▼
regulator reports, finance, anomaly alerts
How the parts fit together
Machine link: two protocol generations on one floor
SAS (Slot Accounting System) is described in the public record as the de facto casino communication standard for automating slot meter reporting and event logging, player tracking, bonusing, ticketing and cashless gaming (source: US patent 8,429,229, background section; saspy README). The README of the open-source saspy library adds the shape: the link is a serial line between the EGM and a slot machine interface board (SMIB); the master polls with 1-byte addresses (a general poll returns a 1-byte event code, called an exception) and long polls carry commands, and all long polls except read-type include a CRC-16; the host-to-SMIB side is not standardised by SAS. G2S (Game to System) replaces the SMIB with Ethernet and administers services from G2S servers (source: US patent 8,429,229). Patent literature describes G2S as XML data over TCP/IP. Casinos therefore run a mixed floor for years, and the CMS keeps a protocol adapter per generation (sas-g2s-protocols, no page yet) that emits one internal event schema.
The adapter's contract: every event gets a per-machine sequence number (Message sequence numbers) at the point it enters the host, so a gap, a duplicate or a reorder is detectable; frames are checksummed (CRC-32C checksums is the common fast check for the host's own storage and links, while SAS itself uses CRC-16 on the wire); and the adapter never blocks the poll loop on a database write. Text-like G2S messages and configuration files are parsed with a hand-written, bounded parser (Recursive-descent parsing) and nothing from the floor is trusted to be well formed.
Once an event has its sequence number it is published to a publish-subscribe-event-bus (no page yet) topic per machine group, and the consumers subscribe independently: meter accounting, the voucher engine, player tracking, the compliance log and the floor-monitoring screens. The poll loop therefore does one thing, publish, and a slow consumer (a report job, a promotion rule) falls behind on its own subscription instead of slowing the poll of the machines. Per-machine order is kept (all events of one machine go to one partition), and a consumer that restarts resumes from its stored position and relies on the sequence numbers to skip what it has seen.
Meter accounting: cumulative counters and deltas
An EGM keeps cumulative meters. The host does not trust its own copy and does not add events; it reads meters at defined times, subtracts the previous reading, and stores the delta with the reading time. Events (game end, door open, power loss) are stored as an append-only stream (Event sourcing); the current state of a machine is a fold over its events. Money is held in integer minor units with an explicit currency (Money representation), and day-end figures are posted to a Double-entry ledger, so a bucket never gains value without another losing it. Shares, such as a progressive contribution split across several pools or revenue shared with a venue partner, must sum to the whole amount, which is the case for largest-remainder-rounding (no page yet). The check that catches faults is a variance report: the sum of machine meters against the cage's counts, the vouchers printed against vouchers redeemed, using the matching approach of Reconciliation.
Usage is attributed as well as totalled. resource-usage-accounting (no page yet) takes each metered delta (coin-in, coin-out, games played, time on device) and assigns it to the holder it belongs to: the machine, the open card session, the active promotion, and the progressive pool. Each delta is booked once to each holder with the reading time, so a session's wagers, the time the player was seated and a machine's hold over a shift all add up to the same machine meters, and a delta that arrives with no open session is booked to the machine alone and not guessed onto a player.
Ticket-in/ticket-out and cashless: money as a state machine
A voucher is printed by a machine, held by a person for hours or days, and redeemed at another machine or a kiosk. Each ticket therefore has a lifecycle (issued, redeemable, redeeming, redeemed, expired, voided) modelled as a Payment state machine with persisted states: a timeout between "redeem requested" and the machine's answer is unknown, never failure, and is resolved by asking again. The Hierarchical state machine shape gives shared behaviour (any state can be voided by the cage) without repeating transitions. A redemption request carries an Idempotency key, so the machine retrying after a lost response does not pay twice. A ticket must be redeemed once even if two machines see it concurrently; the check is a conditional update on the ticket's version (Optimistic concurrency control). Where a rule or an auditor wants numbers without gaps (validation or journal numbers), that is gapless-sequence-numbers (no page yet), and number allocation is serialised even though the rest is not.
A voucher's validation number is a bearer secret: whoever presents it at a kiosk can be paid. It therefore comes from a csprng (no page yet), a cryptographically secure random generator seeded by the operating system, with enough bits that guessing a valid number is not feasible, and never from a counter or a clock. The sequential voucher number needed for the journal is a separate field, because a gapless sequence is predictable by design; the same generator makes the nonces for cashless sessions and the keys that are then wrapped under the master key.
Player tracking and promotions
A card inserted at a machine ties the play to a person. The same person may hold several cards, appear under different spellings, or be a guest at several properties of a group, so the loyalty database needs identity-resolution (no page yet): Entity resolution with blocking and scoring to find candidate pairs and Union-find to merge the matches into one profile. A rating uses the recorded wagers and time; promotions are rules of the form "when this event happens and this condition holds, do this" (event-condition-action-rules, no page yet) with timers for expiry and cool-down (Hierarchical timing wheel). Offers weigh recent play more than old play, which time-decay-scoring (no page yet) formalises. Keep promotional credit in separate ledger accounts from cash credit so each can be reported on its own.
benefit-accumulators (no page yet) are the per-player balances that rating and promotions work with: points earned per unit of play, tier credits for the current period, comp value and free-play credit. Each accumulator is updated by an event from the rated session, has its own earn rule, expiry and cap, and is written as a posting against a separate promotional account, so a balance can always be rebuilt from the events. Tiers and offers read the accumulators (with their decay), not the raw wagers, which keeps the promotion rules simple and the rating stable when the earn rate is changed.
Compliance and reporting
Regulators publish technical standards and operators must show that their systems comply. Gaming Laboratories International publishes freely downloadable standards, including GLI-13 (monitoring and control systems and validation systems), GLI-16 (cashless systems and technologies) and GLI-11 (gaming devices) (source: GLI standards page). The system therefore keeps a Tamper-evident audit log of significant events and of every operator change, because an inspector will ask who changed a setting, when and with whose approval. Statistical checks sit beside the rules: Time-series anomaly detection compares each machine's hold to its own seasonal baseline and flags outliers, with Isolation forest as a model-light alternative for multi-feature checks. An alert is an investigation trigger (a faulty meter, a tampered machine, collusion), not a verdict.
Software integrity: signing, keys and dual control
Because game and system software determines payouts, a regulator-facing system verifies what runs. Release artefacts are signed (code-signing, no page yet), and update clients check small signed metadata files that pin versions and hashes with separate roles (Signed update metadata); verification uses a normal signature scheme such as ECDSA signatures or Ed25519. Signing keys live in Hardware security modules, data keys are wrapped under master keys (Envelope encryption) and rotated without downtime (key-rotation, no page yet), and host-to-device messages that need integrity use a keyed tag (Message authentication codes). Back-office connections use Mutual TLS so each gateway and kiosk has its own identity. Sensitive operations such as changing a payout parameter or releasing a software version follow dual-control-approval (no page yet): two named people, recorded.
Reliability: the floor must keep running
A CMS outage must not stop play; machines keep playing and accumulate meters, and tickets can still be printed. The host's job is to catch up without double-counting. The database writes through a Write-ahead log and replicates to a hot standby (Primary-backup replication, Hot-standby redundancy); Point-in-time recovery answers "what was the state at 03:12?" for investigations. Poll workers and report jobs run under Process supervision, drain on deploy (Graceful draining), and jobs such as regulator exports go through a Durable job queue so a crash retries instead of skipping.
Health checking decides what the rest does about a failure: the poll workers and the machine links report liveness per link and per machine group, a stalled link is marked unreachable instead of silently quiet, and the standby takes over on a failed check of the primary together with a lease, as in the section above. A machine that is silent for longer than its poll interval raises an alert and its meters are caught up on reconnect.
hdr-histogram (no page yet) records latency percentiles for the paths where the floor feels delay: poll cycle time per link, event-to-ledger time, ticket redemption round trip (request to answer at the machine) and promotion award time after a rated event. The tail shows a slow serial link or a lock held on a hot voucher row, and merged histograms from all poll workers give the property-wide picture.
Assurance
Deterministic simulation testing replays failover, duplicate and out-of-order scenarios from a seed; this is the right tool for voucher races. Coverage-guided fuzzing targets the protocol parsers, which read bytes from devices on a shared floor.
Data and control flow
One ticket, printed and redeemed:
- A player cashes out at machine A. The machine prints a ticket with a validation number and reports the event (ticket out) with the amount.
- The host assigns the event a sequence number, creates the ticket in state "issued" with the amount, validation number and machine id, and posts the liability to the ledger.
- Hours later the player inserts the ticket in machine B. The machine sends the validation number; the host looks up the ticket and moves it from "issued" to "redeeming" with a conditional update.
- The host answers with the amount; machine B credits and reports "ticket in". The host moves the ticket to "redeemed" and clears the liability.
- If the host's answer is lost, machine B asks again with the same idempotency key and receives the first answer; if the ticket was in "redeeming" for too long the engine asks the machine and resolves it. Time goes mostly to the lookup and the conditional write; the machine's wait is the user-visible latency.
One day-end meter close:
- At the cut-off the poller reads every machine's meters and stores readings with times.
- Deltas are computed against the previous close; gaps in the sequence of events are flagged.
- Deltas are posted to the ledger; the variance report compares the sum to cage and ticket totals.
- Anomaly checks run; exceptions go to a queue for a person. Reports are generated from the closed figures and stored with the audit log entry for the run.
One failover:
- The standby loses the primary's heartbeat and promotes.
- Pollers reconnect; machines still hold their meters, so the host reads them again and recomputes deltas from the last stored reading.
- Retried ticket requests are answered from the idempotency records.
Scaling
In the order you meet the limits:
- Poll rate per serial line. SAS uses master-slave polling with one machine at a time per line; the README of saspy gives polling rates from 200 ms to 5 s, and a faster real-time-event mode. Levers: more gateways, fewer addresses per line, real-time event reporting.
- Event ingest for large floors. Thousands of machines emit game-end events. Levers: batch writes, a partition by machine, aggregate before storing detail.
- Ticket validation latency. The path is a single-row read and a conditional write. Levers: index on validation number, keep hot tickets in memory, a regional database near the floor.
- Report and analytics load. Regulator and finance reports are heavy. Levers: run on replicas or a warehouse copy, schedule off-peak, precompute day-end aggregates.
- Multi-property groups. Loyalty is shared across sites. Levers: a central identity service with local caches, and local operation when the link is down.
- Audit and history growth. Logs are kept for years. Levers: partitions, cold storage in Object storage, anchoring only roots.
Failure modes
| Failure | Symptom | Cause | Fix |
|---|---|---|---|
| Meter variance | machine total differs from cage and ticket totals | missed poll, meter rollover, failed event | delta accounting with sequence gaps flagged, re-read meters, reconcile and document |
| Double payout | one ticket paid twice | race between two machines, retry without idempotency | conditional update on ticket version, idempotency keys, one redeemer |
| Stuck ticket | ticket in "redeeming" for hours | host or machine crashed mid-redemption | treat as unknown, query the machine, resolve with a timeout rule and an audit entry |
| Lost events during outage | gap in machine history | poller down while the machine kept playing | read cumulative meters afterward, store deltas, flag unattributed intervals |
| Duplicate or merged players | wrong comp, split history | cards and names not resolved | entity resolution with review of uncertain merges, split tools |
| Unsigned or modified software | regulator audit failure, or tampering | missing signature check, key leak | signed metadata, HSM-held keys, dual control for release |
| Replay or spoofed gateway | forged events | no per-device identity or integrity tag | mutual TLS per device, keyed tags, sequence numbers |
| Parser crash | polling stops on a bad frame | malformed bytes from a device | fuzzed bounded parser, per-line isolation, supervised restart |
| Split-brain after failover | two hosts accept tickets | promotion without fencing | single writer with lease or fencing, then restart old primary as standby |
| Report mismatch | regulator figure differs from finance | reports built from live data | build reports from closed figures, keep inputs and version of the report code |
Real implementations
Open-source casino management systems are practically absent; the licensed products are proprietary and regulator-certified. What is public is mostly the protocol side and the standards.
| name | what it is | repo | licence | notes |
|---|---|---|---|---|
| saspy | Python library for talking SAS to an EGM over RS-232 on single-board computers | thomas-pythonas/saspy | MIT | reads meters and exceptions; its README is a good compact description of the SAS layers |
| GLI standards | freely downloadable regulator-facing standards: GLI-11, GLI-13, GLI-16 and others | GLI standards page | — | documents, not code; versions listed on the page |
Proprietary systems named in the graph: Light & Wonder, IGT ADVANTAGE, Konami Synkros. They are not described here.
Sources
- GLI standards (free downloads, including GLI-11, GLI-13, GLI-16): https://gaminglabs.com/gli-standards/
- saspy README (SAS layers, polling, exceptions, TITO and AFT functions): https://github.com/thomas-pythonas/saspy/blob/master/README.md
- US patent 8,429,229, background on SAS, G2S and SMIB architecture: https://patents.google.com/patent/US8429229