When the Dino hopped Onchain

When the Dino hopped Onchain

ETHIndia 2024 was a resounding success, celebrating the thriving Ethereum ecosystem and pushing the boundaries of innovation. This year’s theme, Infinite Games, reflected not just the enduring nature of Web3 but also its philosophy—building systems and communities designed to last, where the focus is on long-term growth rather than short-term gains. Similarly, in web3, infinite games are about persistence, creativity, and thinking beyond the immediate moment.

When brainstorming ways to integrate an infinite game into the ETHIndia 2024 website, our team explored many possibilities. We considered classics like Conway’s Game of Life which embodies endless complexity, and even toyed with the idea of embedding a whole NES emulator featuring nostalgic retro games (Something Nintendo would not be happy with us doing) or turning the ETHIndia website board into an actual live playable chessboard. But none of these quite captured the essence we were searching for.

Then came an unexpected twist. One day, while deep in discussion, an internet outage interrupted our flow. And that’s when inspiration struck—there it was, staring us in the face: the Dino Game, the timeless offline browser game. A simple yet iconic game that we’ve all tried to master at some point in our lives, chasing high scores and testing our limits.

The Dino Game turned out to be a perfect fit for the Infinite Games theme. Its endless running mechanic symbolizes persistence, while bringing it onchain would allow players to prove their high scores for the first time, transparently and immutably. To make it even more aligned with the Ethereum and web3 ethos, we replaced the classic dino with an onchain bunny V, a nod to Vitalik’s bunny, and swapped the cacti with banks, symbolizing dodging traditional financial institutions using crypto. We even designed a custom font specifically for the game which perfectly complemented the retro aesthetic of the Dino Game. It was the perfect combination of nostalgia, creativity, and the ethos of web3. What started as a simple idea quickly turned into one of the most exciting engineering challenges of ETHIndia 2024.

And so, the journey began—to bring the Dino Game onchain, creating a verifiable, infinite game experience like never before.

The Perfect Plan 💯

“It’s just a Dino game onchain. What could go wrong?”

Aah! That’s what we all thought before we started building it, because we had what we called a “Perfect Plan.”

Our plan was straightforward: take the existing Dino game source code, integrate it into our React codebase, and then focus on solving the main challenge—preventing score spoofing. We can prevent score spoofing by implementing a proof of gameplay mechanism which will verify the game by simulating it on the server. We estimated that we’d have it up and running in a week, ready to ship by the weekend. What could possibly derail such a simple plan?

As it turned out, a lot of things.

The not sooooooo perfect start 🫤

The first step of our “Perfect Plan” was to integrate the Dino Game from the Chromium source code into our codebase. There’s a popular repository called t-rex-runner that contains the 10-year-old source code of the T-Rex game, extracted from Chromium. Our plan was to use this repository, apply some minor refactors, and make it compatible with React. The reason for integrating the game so closely into our React codebase was to leverage our existing wallet and API services. However, the T-Rex code was written in non-modular ES5, while our codebase was utilizing the modern ES6 modules, making it difficult to compile directly using Babel. We attempted to migrate some parts of the code to ES6, but the process was time-consuming, so we decided to explore alternative solutions.

Later, we explored the official Chromium repository and were pleased to find that the maintainers had already migrated the codebase to ES6 over the past year. We then extracted the updated source code from the Chromium repository and made several refactors, including replacing the singleton pattern with a class-based structure to better integrate it with React. We created a React component, added cleanup logic to ensure proper mounting and dismounting, and after these adjustments, the Dino game was up and running in our codebase. The newly extracted t-rex source code is also available on our github here.

The Failed Plan 😭

Once the game was up and running, the next step was to implement a Proof of Gameplay mechanism to verify the game score submitted by the client and prevent tampering with the API request. Shoutout to our friends at Stackr for the inspiration with their adaptation of comets and guidance on this one! We considered two approaches to verify the game on the server:

  1. Replay the entire game in a headless browser using the exact same user inputs. However, this approach was both costly and time-consuming, as it required launching a headless browser instance for every single game on the server.
  2. Separate the game’s score calculation logic from the rendering logic, then create a version of the game that only runs the scoring algorithm without rendering anything on the canvas. This approach would allow the game to run on the server without needing a browser.

Like any other game, the Dino Game relies on generating random numbers to drive key game mechanics, such as obstacles, day/night cycles, and background elements. Until there are random variables in the game logic, the game can’t be truly deterministic. A deterministic game is one where, given the same inputs, the outcome will always be the same, regardless of how many times it’s played. This is crucial because we need to ensure that when we replay the game on the server using the same inputs, the result matches exactly with the client’s gameplay, allowing us to verify the game. To achieve this, we needed a deterministic random number generator, which requires an initial seed. As long as the seed remains the same, the sequence of random numbers will be identical. In our case, we generated a random seed on the server at the start of each game session and sent it to the client to use as the seed for the entire game.

Fun Fact: Did you know that Math.random() is actually a deterministic random number generator? Its randomness comes from an initial seed, which is typically derived from constantly changing values like the current timestamp. This creates the illusion of randomness, but it’s not truly unpredictable or cryptographically secure. Read more about this here.

Out of the two options, we chose the more optimal one due to its time and cost efficiency. After replacing all the random non-deterministic logic with deterministic random logic, we expected the game to produce consistent scores. However, even with the same inputs, the scores still varied by a significant margin. Our engineering team has tackled many complex problems, but building a game was a new challenge for us. After some debugging, we finally found the reason which was causing the game to be non-deterministic.

The culprit was requestAnimationFrame(), which instructs the browser to call a user-defined callback function before the next repaint in order to perform an animation. The frequency of these callback calls can vary depending on the machine’s refresh rate, leading to inconsistent results. To address this, we modified the animation rendering callback to limit the frame rate to 60 FPS. This adjustment was literally a game-changer, and after many days of debugging, the game was finally deterministic on the frontend.

Our celebration was short-lived. Once the frontend was working, we removed the rendering logic and created a separate version of the Dino game that could run on the server without rendering anything. However, upon deploying the server-side verification system, we encountered a new set of challenges. Despite removing all browser dependencies and controlling the frame rate, the server-side game results were still inconsistently different from the client-side results. The complexity of accurately simulating the game physics and timing without a browser environment turned out to be far more intricate than we had anticipated.

With ETHIndia 2024 rapidly approaching and time running out, we faced a tough but pragmatic decision. Rather than spending additional time perfecting the server-side replay system, we pivoted to a more reliable and feasible approach that would still ensure game integrity within our timeframe. This led us to explore the Merkle Tree method, which ultimately became our solution for verifying game scores.

The Merkle Tree Save 🌲

After our initial setback with server-side verification, we needed a solution that was both secure and implementable within our tight timeline. Enter Merkle Trees – a cryptographic structure that would prove to be our perfect compromise between security and practicality.

Here's how we implemented it:

When a game starts, we generate a unique game session with a random seed. This seed is hashed to create the first leaf in our Merkle Tree. We then combine it with other critical game data – the score, timestamp, and player's wallet address – to generate additional leaves. The root hash of this Merkle Tree serves as our game session identifier. Throughout gameplay, we continuously track key events and the distance covered, adding each as new leaves to our tree. When players achieve a score they want to mint, they submit their game data along with a Merkle proof. Our server then verifies this proof to ensure the data hasn't been tampered with. As an additional security measure, we validate that the distance covered increases consistently throughout the session, preventing any attempts to spoof the gameplay progression.

While this solution might not have been as theoretically "perfect" as our original server-side replay plan, it proved to be the right practical choice.

Office Hours turned Dino Hours  🏢

0:00
/

Once we added the minting logic and deployed the game to our development environment, our office transformed into an impromptu arcade. All the roadmaps were put aside and the P0 was to play Onchain Dino 🦖.

What started as a routine testing phase quickly evolved into something more entertaining. We opened a thread for Dino high scores on our slack and everyone was trying to beat the high score and get the purple dino NFT. This intense competition provided us valuable feedback and helped us discover and fix critical bugs and edge cases. But perhaps the most valuable outcome wasn't the bugs we caught – it was watching our team experience the game exactly as our hackathon participants would.

Love it, Ship it 🚀

The Base and Devfolio team

As the clock struck midnight, the Onchain Dino game was finally ready to take flight. After weeks of relentless problem-solving, debugging, and countless rounds of testing, the moment to ship had arrived. The first person to play the Onchain Dino Game was none other than Jesse Pollak, the creator of Base, who, with the Base team, visited our office the night of the launch.

Jesse, fresh off the “Base Around the World” meetups across multiple cities, visited our office at midnight and not only claimed the coveted #000 NFT but also took a moment to appreciate the thought and effort that went into our project.

No sooner had the Base team left than the real action began – a race within the Devfolio team to secure the #001 NFT! The excitement was palpable as developers, designers, and everyone in between scrambled to claim the next mint. It wasn’t just about the NFT; it was about the pride of being part of something we had built together, an Easter egg that perfectly encapsulated the spirit of ETHIndia 2024.

Play the Game 🦖

Games have an incredible way of bringing people together, igniting competition, and creating shared moments of joy. The Onchain Dino Game was no exception. What started as an Easter egg for ETHIndia 2024 grew into something much larger, sparking excitement among participants, showcasing innovative engineering, and adding a touch of fun to the blockchain ecosystem.

From the 25,100 NFTs minted to the fierce battles for high scores, the game captured the imagination of players worldwide. As you can see in the stats we have shared, you’ll see how the game resonated with the ETHIndia community and became a unique way to celebrate our theme of “Infinite Games.”

But the journey doesn’t end here. We’re thrilled to announce that we’ll be making our version of the Dino Game open-source. This updated version, extracted from the modern Chromium source code, is a significant improvement over the original repository created 10 years ago (wayou/t-rex-runner). With cleaner, modernized ES6 code and React compatibility, it will provide a robust foundation for developers to build upon. Opensource code here - (devfolioco/t-rex-runner-game)

We hope this open-source release inspires others to experiment, innovate, and bring their ideas to life, just as we did. Because in the spirit of infinite games, the goal isn’t to win but to keep playing, keep building, and keep exploring new possibilities.

Here’s to the next game, the next hackathon, and the next big idea! 🚀