At Traent, we develop hybrid blockchain technologies, a novel approach to bring real-time and data-intensive applications on blockchain while preserving the confidentiality and auditability of the data. We provide Traent Era, a collaboration platform where companies can interact in a simple, organized and transparent way. And we are exploring creative ways of using it. Today, we want to talk about Doom!
Table of Contents
- The authors
- Why run Doom on blockchain
- Objectives
- How we run Doom on Blockchain
- Benefits of executing Doom on blockchain
- Acknowledgements
- Technical explanation
- Adapt the Cloudflare version of Doom to run on Traent Workflow Engine
- Make the execution of the gameplay deterministic
- Input events
- Generate a video of the gameplay
- Ensuring that the gameplay produced by the workflow is identical to the user’s gameplay
- Sharing the ledger
- Conclusions
The authors
Why run Doom on blockchain
Doom is a beloved first-person shooter game that has been entertaining players for nearly 30 years. The game was initially created in 1993 by iconic developers John Carmack and John Romero. It was released as open-source in 1997, and from that moment it was ported everywhere. This led to several innovative adaptations, including a version on Microsoft Notepad at 60fps and another that can be played on a pregnancy test.
it was only a matter of time before someone figured out a way to run Doom on the blockchain. So we decided to take on this challenge.
Objectives
Our primary goal was to enable users to play the game in their browser, while also running the game engine entirely on our smart contract engine.
So we started by establishing some requirements:
- We want to store the doom binary and the game assets on blockchain (hey, we are data-intensive!)
- The game should be executable in the user browser and verified by the smart contract using the binary stored on the blockchain
- We want to record the user inputs on the blockchain so we can use this data as the input of the smart contract
- We want to generate a “certified” version of the video gameplay so that the smart contract will generate the video based on the user info
- We want a method to identify a specific game session, making it possible to verify the identity between the one run in the client controlled by the player and the one replicated in the smart contract (we opted to take the hash of game memory, good enough for this use case)
How we run Doom on Blockchain
First, we needed a way to execute the code.
We used the Traent Workflow engine, a powerful smart contract engine that takes full advantage of our hybrid technology. Smart contracts are self-executing programs that run on a blockchain network. They are designed to enforce the rules of a contract. They are tamper-proof, transparent, and provide a decentralized environment for executing code. Thanks to the Traent Workflow engine, we can execute heavy-duty processing tasks on the data contained in our blockchains. This allows automating the creation of documents or the execution of complex AI models inside the blockchain.
Secondly, we needed a frontend to piggyback the game input controls.
We used Traent Era, the only collaboration platform on blockchain, as it humanizes the interaction with Traent Hybrid Blockchain nodes. One of Era’s key features is the possibility to customize the view of the data contained in the blockchain. With Era Views we have been able to create an app that allows the user to play Doom. Users can record events (key hits, mouse events) and stream to the blockchain using Era Streams. A way to store data from IoT devices, APIs and applications directly in the blockchain.
Benefits of executing Doom on blockchain
One of the major benefits of running Doom on blockchain through smart contracts is that we can brag about it. Another benefit could be that we can provide an environment to verify the execution of a speed run. Since the game code is stored on the blockchain, it cannot be modified or tampered with by anyone. This means that the game can be verified in a secure and transparent environment, free from the risk of hacking or cheating.
Furthermore, by running Doom on blockchain, we can create a new type of gaming experience. Because the game runs on the blockchain network, players can participate in decentralized tournaments. At the end of the competition, the smart contract determines the winner. This allows each player to see how the game is going and who wins, creating a new level of transparency and fairness.
Acknowledgements
Before we start discussing the technicalities, we want to acknowledge the preview work that made our work way easier than starting from the original executable.
First of all, we want to thank the team behind Chocolate Doom: a modern port of Doom that aims to reproduce the original Doom accurately. They have done a fantastic job with tons of improvements to the original codebase (https://github.com/chocolate-doom/chocolate-doom)
We also want to thank the people from Cloudflare, they used arcane magic to bring Doom demos right to the browser. They used Emscripten to transpile C code from Chocolate Doom to Javascript and Web Assembly and wiring LibSDL to render the game using the browser canvas.
Technical explanation
After due thanks, we can talk about the main challenges we had to solve to get the game to run:
- Adapt the Cloudflare version of Doom to run on Traent Workflow Engine
- Make the execution of the gameplay deterministic
- Generate a video of the gameplay with h264-mp4-encoder
- Ensure that the gameplay produced by the workflow is identical to the user’s gameplay
Adapt the Cloudflare version of Doom to run on Traent Workflow Engine
The Cloudflare version of Doom relies on the following:
- screen
- document (a DOM, a canvas element)
- setTimeout
- WebGLRenderingContext
But also several other objects affect the execution:
- navigator
- requestAnimationFrame
- AudioContext
- devicePixelRatio
Nothing that we cannot solve with some ugly monkey patching and some useful polyfills!
Let’s explain the code.
From 1 to 5 line, we see…
- mock class needed for output mode (canvas/webgl) selection. the class just needs to exist so that the checking condition works
- force set the same locale on all environment (otherwise it would take the browser locale in the browser and no locale in the workflow engine)
- force the doom runtime to use the fake request animation frame function that display frames according to the virtual timing
- disable audio output
- disable custom pixel ratio (use the default: 1:1)
Line 7: The screen is mainly used to auto-size the canvas, so we can just provide an object with width and height.
Line-8: Using document (and a DOM) in Node.js-like environments is a standard problem, we use a polyfill (https://github.com/Raynos/min-document).
From 9 to 13 line: the canvas is actually used to display the frames, so we have to provide a non-trivial implementation (frameHandler function) that is dependent on the execution environment.
If you are using a browser to play the game, frameHandler will use a 2D canvas (for real-time gameplay), if you want to verify the gameplay using the workflow, frameHandler will use an H264 encoder to generate a video of the playthrough.
Make the execution of the gameplay deterministic
The game makes extensive use of functions like Date.now() and Math.random(). Using “True” time sources like Date.now() prevents deterministic execution of the game (in the browser) and replay (in workflow).
In order to make the execution of the gameplay deterministic and verifiable, we need to replace the implementation of Date.now() and performance.now() with a fake time progression (virtual time ticks).
Also, we want the replay of the gameplay to avoid needless sleeps, so we have reimplemented setTimeout to reschedule ASAP.
Input events
On the browser we record all input events. To have the exact same result on the browser environment and on the Workflow Engine we need to intercept all addEventListener calls and attach our custom addEventListener in order to accumulate all events and dispatch them with the correct timing according to our custom virtual time handling, otherwise we would have timing discrepancies between the browser execution (with events dispatched according to the user machine timings) and the workflow execution (with events replayed according to the virtual time execution.
Generate a video of the gameplay
The Doom runtime supports hooking a frame handler that would receive the buffer of every game frame when it is emitted.
On the workflow engine we implement a frame handler that takes the frame and passes it to a video encoding library. We use: https://github.com/TrevorSundberg/h264-mp4-encoder that produces a h264 video inside a mp4 container.
Ensuring that the gameplay produced by the workflow is identical to the user’s gameplay
When playing the game on the Traent View, we capture:
- the player name
- all inputs and their timing
- some stats like health and armor (captured by inspecting the internal memory of the game!)
- on level completion or player death, a digest of the memory of the Doom runtime and the completion time
Then we write these data on the ledger.
The workflow:
- executes the Doom runtime;
- dispatches all inputs with the correct timing to the game loop;
- on level completion or player death, it produces a digest of the memory of the Doom runtime and halts its execution;
- checks the produced digest against the digest submitted by the customized Traent View.
Additionally:
- it produces a video of the gameplay from all frames outputted by the Doom runtime;
- it produces a certificate that attests to the validity of the gameplay and whether the player cheated or not (if the digests don’t match).
Sharing the ledger
Not satisfied yet, we decided to take advantage of another feature of the Traent Hybrid Blockchain: the portable ledger. The blockchain we used to run Doom is a lightweight private ledger, created on-demand by the node, and distributed among a sub-group of nodes of the private network. In order to make it accessible to the public, via Era is possible to export the full private ledger or just a selection of the contained data, in the format of a portable ledger.
A portable ledger can be opened using the Traent Viewer (https://viewer.traent.com/), an open-source (https://github.com/traent/viewer) application that allows to visualize its content using the Era Views included in the ledger, perform a low level inspection of the structure, validate the integrity of the data, and, more importantly, make it possible to execute and audit of the consistency of the ledger history.
The audit is made possible thanks to a cryptographical consistency proof included in the portable ledger. The proof is verified automatically by the Traent Viewer, also retrieving and checking the content of a sequence of notarization events, periodically written by Traent on the Algorand public blockchain. The proof can be verified only if the ledger has never been forked.
Have a look at the demo!
We implemented the workflow to automatically produce a video of the game session at game-over. The video is stored in-chain (therefore included in the portable ledger) and generated directly from the game data contained in the ledger.
We also generated via the workflow a certificate for the run, including a screenshot and the game stats.
You are able to view the portable ledger yourself using the Traent Viewer, freely available at https://viewer.traent.com/
Conclusions
Every story has an end… every ending is a new beginning.
If you’ve made it this far, you are awesome, and we want to give you something back!
You can access the code by visiting https://github.com/traent/blockchain-doom
If you want to try doom on blockchain yourself, or if you want to know more about our technology, contact us (info@traent.com). We will be more than happy to give you access to Traent Era and to talk about other possible use cases!