Skip to main content
For the complete documentation index, see llms.txt

Battleship tutorial

Prerequisites: work through the private tip jar example first. This tutorial assumes you can already compile a contract, run a local devnet and read a MidnightJS test.

This tutorial is about defensive programming. Every circuit in a Compact contract is a public entry point: anyone can call it, in any order, with any arguments, and with any witness implementation they like. The contract has to defend itself.

Battleship makes that concrete. Each player's ships are private and the shots are public. A dishonest player has every reason to claim a MISS when a shot was in fact a HIT, or to move a ship mid-game. The contract stops both, without trusting either player. You will see four techniques, each one an assert in the contract and a test that proves it:

  • A state machine. Explicit TurnState, BoardState and WinState values open exactly one circuit at a time, so no one can act out of turn.
  • Role checks. Each player is identified by a DApp-specific public key derived from a private secret, and every circuit checks that the caller holds the right role.
  • On-chain verification of off-chain data. Players commit to their ships with a hash on the ledger. When they later report a HIT or MISS from their private state, the contract rehashes the shot and checks the claim against that commitment.
  • Cheat-check tests. The test suite plays the game on a devnet and deliberately cheats: it shoots out of turn and rewrites a player's private state, and expects each attempt to be rejected.

The source for this tutorial is examples/battleship in midnight-examples.

Set up​

Clone midnight-examples, install the workspace and compile every contract:

git clone https://github.com/midnightntwrk/midnight-examples.git
cd midnight-examples
yarn install && yarn compile

Then move into the example:

cd examples/battleship

You'll start the local network in the second part, when you run the tests.