Published on

Fizzbuzz Tutorial, Your Third Seahorse Solana Program

Authors

Welcome back. Let's write some more Seahorse! This tutorial is part 3 of a series and follows on from the previous poll app example. Start here if you're an absolute beginner.

Today we'll be doing a FizzBuzz program. FizzBuzz is a classic coding program and children's game. We input a number into the program, if the number is divisible by 3 (e.g. 9), it's 'fizz'. If the number is divisible by 5 (e.g. 10) it's 'buzz'. And numbers divisible by both 3 and 5 (e.g. 15) are 'fizzbuzz'.

So again create a new project at the top left corner of Solana Playgrounds, delete the boilerplate code and rename the .py file to something appropriate like 'fizzbuzz.py' import Seahorse and declare a placeholder ID.

fizzbuzz.py

from seahorse.prelude import *

declare_id('11111111111111111111111111111111')

First we want to create our FizzBuzz class. This class will be derived from Seahorse's base 'Account' class. It holds 2 boolean flags, 'fizz' and 'buzz' and a number 'n' which is of the type u64, which if you remember from previous lesson stands for unsigned (non-negative) integer 64 bits in size.

fizzbuzz.py

class FizzBuzz(Account):
  fizz: bool
  buzz: bool
  n: u64

Now we build our instructions. The first of which will be to initialize a new instance of FizzBuzz. The function takes 2 arguments owner: Signer which represents the user's account and an empty instance of the FizzBuzz class fizzbuzz: Empty[FizzBuzz]. Within the function we initialize the instance with fizzbuzz.init(), passing in the keyword argument payer=owner and another keyword argument seeds = ['fizzbuzz', owner]. This creates a PDA. Wait, what the hell is a PDA?

fizzbuzz.py

@instruction
def init(owner: Signer, fizzbuzz: Empty[FizzBuzz]):
  fizzbuzz.init(payer = owner, seeds = ['fizzbuzz', owner])

PDAs (program derived addresses)

This is the key part of the tutorial. Pay attention. You will NEED to know how PDAs work to build on Solana. It's really not that hard, so don't worry. In the previous lesson with the poll app, we didn't need to deal with PDAs because polls are designed to be voted on by many users. That's kind of the point of a poll after all, if only one user can vote in a poll it's not a poll.

But here we with FizzBuzz, each user creates their own instance of FizzBuzz that is tied to their account and they uniquely control. The information for that FizzBuzz instance isn't stored in the main program account and it isn't stored in the user's account either. It's stored in a PDA. So a PDA here is simply a third account that is storing data tied to the user account for this program. There's a lot more to PDAs but that's all you need to know for now. We'll cover how they are generated later in the tutorial.

Next up we write our 2nd instruction which holds the core logic. The function accepts 2 arguments, an instance of fizzbuzz fizzbuzz: FizzBuzz and an integer n: u64. The logic within the function is all very straight forward vanilla Python that I won't explain as I'm assuming you already know Python.

fizzbuzz.py

@instruction
def do_fizzbuzz(fizzbuzz: FizzBuzz, n: u64):
    fizzbuzz.fizz = n % 3 == 0
    fizzbuzz.buzz = n % 5 == 0
    if not fizzbuzz.fizz and not fizzbuzz.fuzz:
        fizzbuzz.n = n

Final code

Okay, so that's all of our code. You should have something that looks like this below.

fizzbuzz.py

from seahorse.prelude import *

declare_id('11111111111111111111111111111111')

class FizzBuzz(Account):
  fizz: bool
  buzz: bool
  n: u64


@instruction
def init(owner: Signer, fizzbuzz: Empty[FizzBuzz]):
  fizzbuzz.init(payer = owner, seeds = ['fizzbuzz', owner])


@instruction
def do_fizzbuzz(fizzbuzz: FizzBuzz, n: u64):
    fizzbuzz.fizz = n % 3 == 0
    fizzbuzz.buzz = n % 5 == 0
    
    if not fizzbuzz.fizz and not fizzbuzz.fuzz:
        fizzbuzz.n = n

Time to build and deploy. Let's do that as before, top left, select the 'Build & Deploy' icon. The command line shell should display something similar to Build successful. Completed in 4.32s. Make sure you have enough SOL in your wallet to deploy. Don't forget to initialize and export the IDL as we did in the previous tutorial!

Testing

Firstly let's fetch all the instances of the FizzBuzz class. Go to 'Accounts' and then 'FizzBuzz' from the testing menus and select 'Fetch All'. It should return an empty array, which makes sense as we haven't interacted yet with our program.


[]

Now let's set up an instance of FizzBuzz. Select 'init' and then in 'Accounts' select 'My address' from the dropdown options. Under 'fizzbuzz' select 'From seed'. There should be a box with 'Generate from seed'. This is where we create the address for our PDA. Let's go back to the code and see how the PDA is derived seeds = ['fizzbuzz', owner]. That means we need to provide 2 things to create the PDA address, firstly the string 'fizzbuzz' and secondly the owner public address.

So in the box under 'Seed(1)' we need to simply input fizzbuzz without quotation marks and all in lowercase. Tap the + icon to create another input field and select 'Pubkey' from the options. In the new second field labeled 'Seed(2)' copy and paste your owner public address (i.e. your address). Then select 'Generate'. Finally tap 'Test' to begin the test and wait for the transaction.

fizzbuzz tutorial 1

Try checking Accounts > FizzBuzz > Fetch All again. The array should no longer be empty, instead you should see something like this, with **** being your PDA's address.


[
    {
        "publickey": "******",
        "account": {
            "fizz": false,
            "buzz": false,
            "n": "0"
        }
    }
]

Great, let's test our do_fizzbuzz instruction. Go to Instructions > doFizzbuz > Args and input a positive number. In 'Accounts' we need to input the address of the PDA tied to our owner account. You can get this from either the block-explorer transaction where it was created or from the JSON file at Accounts > FizzBuzz > Fetch All. Begin the test and open the link for the transaction on a block explorer once it's completed.

fizzbuzz tutorial 2

Scroll down and check the transaction was successful. Click on the address for the PDA to bring up it's own page. There should be an option to find the data stored in the account somewhere. It should look something like this below.

fizzbuzz tutorial 3

Test the program with different numbers and see how the boolean flags change!

Okay, congrats for making it this far. Your third Seahorse program has been deployed and you've also created your first PDA! Not bad.