Skip to content

Fibonacci

IMPORTANT

The examples are designed to be run in order after completing the quickstart, which will help you set up your environment and get familiar with common commands.

If you are just here to browse, enjoy!

🔢 Fibonacci sequence background

The Fibonacci sequence is a classic mathematical sequence where each number is the sum of the two preceding ones, typically starting with F(0)=0 and F(1)=1. This example demonstrates how to compute Fibonacci numbers efficiently in SBPF assembly, using the program's return code to communicate the result.

The Fibonacci program takes a single byte of instruction data representing the sequence index n, and returns F(n) as a custom program error code, except for F(0)=0, since a return value of zero indicates success. This approach leverages the fact that the program's return value can be used to communicate arbitrary u32 values back to the caller.

🛡️ Input validation

Like the memo example, the program first validates that no accounts are passed by checking the number of accounts in the input buffer:

asm
.equ NUM_ACCOUNTS_OFFSET, 0
.equ INSTRUCTION_DATA_LENGTH_OFFSET, 8
.equ INSTRUCTION_DATA_OFFSET, 16
.equ E_ACCOUNTS, 0xffffffff
.equ E_MAX_N, 0xfffffffe
.equ MAX_N, 47
.equ MAX_N_SPECIAL_CASE, 1

.global entrypoint

entrypoint:
    # Indexed load double word the number of accounts into r3, for use as a
    # scratch register.
    ldxdw r3, [r1 + NUM_ACCOUNTS_OFFSET]
    # If number of accounts is nonzero, jump to abort_accounts. Note r4
    # initially contains zero.
    jne r3, r4, abort_accounts

If accounts are detected, the program immediately exits with error code E_ACCOUNTS (0xffffffff):

asm
abort_accounts:
    mov32 r0, E_ACCOUNTS
    exit
Full program
asm
.equ NUM_ACCOUNTS_OFFSET, 0
.equ INSTRUCTION_DATA_LENGTH_OFFSET, 8
.equ INSTRUCTION_DATA_OFFSET, 16
.equ E_ACCOUNTS, 0xffffffff
.equ E_MAX_N, 0xfffffffe
.equ MAX_N, 47
.equ MAX_N_SPECIAL_CASE, 1

.global entrypoint

entrypoint:
    # Indexed load double word the number of accounts into r3, for use as a
    # scratch register.
    ldxdw r3, [r1 + NUM_ACCOUNTS_OFFSET]
    # If number of accounts is nonzero, jump to abort_accounts. Note r4
    # initially contains zero.
    jne r3, r4, abort_accounts

    # Indexed load single byte the sequence number into r8. Only check a single
    # byte since MAX_N < 256.
    ldxb r8, [r1 + INSTRUCTION_DATA_OFFSET]
    # If sequence number > MAX_N, jump to exit with error code E_MAX_N.
    jgt r8, MAX_N, abort_max_n

    # Prepare call-preserved registers for loop. Since r6 defaults to 0:
    # {r6 = F(0) = 0, r7 = F(1) = 1}
    mov64 r7, 1

    # F(n) = n for n = {0, 1}. So compare sequence number to
    # MAX_N_SPECIAL_CASE then loop if not special case.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    mov64 r0, r8
    exit

loop:
    # Decrement sequence number tracker for iteration. Using r9 as a scratch
    # register, increment the sequence numbers of the two Fibonacci numbers
    # being tracked. For example on the first iteration,
    # {r6 = F(0), r7 = F(1)} -> {r6 = F(1), r7 = F(2)}
    mov64 r9, r6
    mov64 r6, r7
    add64 r7, r9

    # Decrement sequence number counter.
    sub32 r8, 1
    # If sequence number counter > 1, continue loop.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    # Now result in r7 = F(n), move into return code register.
    mov64 r0, r7
    exit

abort_accounts:
    mov32 r0, E_ACCOUNTS
    exit

abort_max_n:
    mov32 r0, E_MAX_N
    exit

Next, the program validates that the requested Fibonacci index n doesn't exceed MAX_N (47), which is the largest index whose Fibonacci number fits in a u32 while leaving room for two error codes:

asm
.equ NUM_ACCOUNTS_OFFSET, 0
.equ INSTRUCTION_DATA_LENGTH_OFFSET, 8
.equ INSTRUCTION_DATA_OFFSET, 16
.equ E_ACCOUNTS, 0xffffffff
.equ E_MAX_N, 0xfffffffe
.equ MAX_N, 47
.equ MAX_N_SPECIAL_CASE, 1
asm
entrypoint:
    # Indexed load double word the number of accounts into r3, for use as a
    # scratch register.
    ldxdw r3, [r1 + NUM_ACCOUNTS_OFFSET]
    # If number of accounts is nonzero, jump to abort_accounts. Note r4
    # initially contains zero.
    jne r3, r4, abort_accounts

    # Indexed load single byte the sequence number into r8. Only check a single
    # byte since MAX_N < 256.
    ldxb r8, [r1 + INSTRUCTION_DATA_OFFSET]
    # If sequence number > MAX_N, jump to exit with error code E_MAX_N.
    jgt r8, MAX_N, abort_max_n
test_max_fib_u32
rust
#[test]
fn test_max_fib_u32() {
    assert!(fib(MAX_FIB_INDEX_U32) <= E_INDEX_TOO_BIG.into());
    assert!(fib(MAX_FIB_INDEX_U32 + 1) > u32::MAX.into());
}

If the index is too large, the program exits with error code E_MAX_N (0xfffffffe).

asm
abort_max_n:
    mov32 r0, E_MAX_N
    exit
Full program
asm
.equ NUM_ACCOUNTS_OFFSET, 0
.equ INSTRUCTION_DATA_LENGTH_OFFSET, 8
.equ INSTRUCTION_DATA_OFFSET, 16
.equ E_ACCOUNTS, 0xffffffff
.equ E_MAX_N, 0xfffffffe
.equ MAX_N, 47
.equ MAX_N_SPECIAL_CASE, 1

.global entrypoint

entrypoint:
    # Indexed load double word the number of accounts into r3, for use as a
    # scratch register.
    ldxdw r3, [r1 + NUM_ACCOUNTS_OFFSET]
    # If number of accounts is nonzero, jump to abort_accounts. Note r4
    # initially contains zero.
    jne r3, r4, abort_accounts

    # Indexed load single byte the sequence number into r8. Only check a single
    # byte since MAX_N < 256.
    ldxb r8, [r1 + INSTRUCTION_DATA_OFFSET]
    # If sequence number > MAX_N, jump to exit with error code E_MAX_N.
    jgt r8, MAX_N, abort_max_n

    # Prepare call-preserved registers for loop. Since r6 defaults to 0:
    # {r6 = F(0) = 0, r7 = F(1) = 1}
    mov64 r7, 1

    # F(n) = n for n = {0, 1}. So compare sequence number to
    # MAX_N_SPECIAL_CASE then loop if not special case.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    mov64 r0, r8
    exit

loop:
    # Decrement sequence number tracker for iteration. Using r9 as a scratch
    # register, increment the sequence numbers of the two Fibonacci numbers
    # being tracked. For example on the first iteration,
    # {r6 = F(0), r7 = F(1)} -> {r6 = F(1), r7 = F(2)}
    mov64 r9, r6
    mov64 r6, r7
    add64 r7, r9

    # Decrement sequence number counter.
    sub32 r8, 1
    # If sequence number counter > 1, continue loop.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    # Now result in r7 = F(n), move into return code register.
    mov64 r0, r7
    exit

abort_accounts:
    mov32 r0, E_ACCOUNTS
    exit

abort_max_n:
    mov32 r0, E_MAX_N
    exit

🔁 Fibonacci computation loop

The algorithm uses three registers to compute Fibonacci numbers iteratively:

  • r6: F(i1): initialized to 0
  • r7: F(i): initialized to 1
  • r8: Loop counter, decremented from n to 1

These registers (r6, r7, r8) are call-preserved (callee-saved/non-volatile) registers in the SBPF calling convention, meaning their values are preserved across function calls. This makes them ideal for storing loop state that needs to persist across iterations.

TIP

This example does not implement call so the call-preserved property isn't strictly needed. However, using call-preserved registers is a good practice for maintaining state across function calls in more complex programs.

The program handles the special cases F(0)=0 and F(1)=1 by checking if n1 and returning early if so:

asm
.equ NUM_ACCOUNTS_OFFSET, 0
.equ INSTRUCTION_DATA_LENGTH_OFFSET, 8
.equ INSTRUCTION_DATA_OFFSET, 16
.equ E_ACCOUNTS, 0xffffffff
.equ E_MAX_N, 0xfffffffe
.equ MAX_N, 47
.equ MAX_N_SPECIAL_CASE, 1
asm
    # Indexed load single byte the sequence number into r8. Only check a single
    # byte since MAX_N < 256.
    ldxb r8, [r1 + INSTRUCTION_DATA_OFFSET]
    # If sequence number > MAX_N, jump to exit with error code E_MAX_N.
    jgt r8, MAX_N, abort_max_n

    # Prepare call-preserved registers for loop. Since r6 defaults to 0:
    # {r6 = F(0) = 0, r7 = F(1) = 1}
    mov64 r7, 1

    # F(n) = n for n = {0, 1}. So compare sequence number to
    # MAX_N_SPECIAL_CASE then loop if not special case.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    mov64 r0, r8
    exit

For n>1, the program enters a loop that computes successive Fibonacci numbers using F(n)=F(n1)+F(n2):

asm
    # F(n) = n for n = {0, 1}. So compare sequence number to
    # MAX_N_SPECIAL_CASE then loop if not special case.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    mov64 r0, r8
    exit

loop:
    # Decrement sequence number tracker for iteration. Using r9 as a scratch
    # register, increment the sequence numbers of the two Fibonacci numbers
    # being tracked. For example on the first iteration,
    # {r6 = F(0), r7 = F(1)} -> {r6 = F(1), r7 = F(2)}
    mov64 r9, r6
    mov64 r6, r7
    add64 r7, r9

    # Decrement sequence number counter.
    sub32 r8, 1
    # If sequence number counter > 1, continue loop.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    # Now result in r7 = F(n), move into return code register.
    mov64 r0, r7
    exit

Each iteration performs the following:

  1. Save F(i1) from r6 into scratch register r9.
  2. Move F(i) from r7 to r6, making it the new F(i1).
  3. Add the old F(i1) from r9 to r7, computing F(i+1).
  4. Decrement the loop counter in r8.
  5. Return if the counter is still greater than 1.
Full program
asm
.equ NUM_ACCOUNTS_OFFSET, 0
.equ INSTRUCTION_DATA_LENGTH_OFFSET, 8
.equ INSTRUCTION_DATA_OFFSET, 16
.equ E_ACCOUNTS, 0xffffffff
.equ E_MAX_N, 0xfffffffe
.equ MAX_N, 47
.equ MAX_N_SPECIAL_CASE, 1

.global entrypoint

entrypoint:
    # Indexed load double word the number of accounts into r3, for use as a
    # scratch register.
    ldxdw r3, [r1 + NUM_ACCOUNTS_OFFSET]
    # If number of accounts is nonzero, jump to abort_accounts. Note r4
    # initially contains zero.
    jne r3, r4, abort_accounts

    # Indexed load single byte the sequence number into r8. Only check a single
    # byte since MAX_N < 256.
    ldxb r8, [r1 + INSTRUCTION_DATA_OFFSET]
    # If sequence number > MAX_N, jump to exit with error code E_MAX_N.
    jgt r8, MAX_N, abort_max_n

    # Prepare call-preserved registers for loop. Since r6 defaults to 0:
    # {r6 = F(0) = 0, r7 = F(1) = 1}
    mov64 r7, 1

    # F(n) = n for n = {0, 1}. So compare sequence number to
    # MAX_N_SPECIAL_CASE then loop if not special case.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    mov64 r0, r8
    exit

loop:
    # Decrement sequence number tracker for iteration. Using r9 as a scratch
    # register, increment the sequence numbers of the two Fibonacci numbers
    # being tracked. For example on the first iteration,
    # {r6 = F(0), r7 = F(1)} -> {r6 = F(1), r7 = F(2)}
    mov64 r9, r6
    mov64 r6, r7
    add64 r7, r9

    # Decrement sequence number counter.
    sub32 r8, 1
    # If sequence number counter > 1, continue loop.
    jgt r8, MAX_N_SPECIAL_CASE, loop
    # Now result in r7 = F(n), move into return code register.
    mov64 r0, r7
    exit

abort_accounts:
    mov32 r0, E_ACCOUNTS
    exit

abort_max_n:
    mov32 r0, E_MAX_N
    exit

📈 Compute unit consumption

The assembly implementation demonstrates O(n) linear compute unit growth with the Fibonacci index, consuming 5 compute units per iteration:

test_asm
rs
#[test]
fn test_asm() {
    test_fibonacci_program(ProgramLanguage::Assembly, true);
}
Test results
sh
Fibonacci numbers and compute units:
F(0):  0          (Compute Units: 8)
F(1):  1          (Compute Units: 8)
F(2):  1          (Compute Units: 13)
F(3):  2          (Compute Units: 18)
F(4):  3          (Compute Units: 23)
F(5):  5          (Compute Units: 28)
F(6):  8          (Compute Units: 33)
F(7):  13         (Compute Units: 38)
F(8):  21         (Compute Units: 43)
F(9):  34         (Compute Units: 48)
F(10): 55         (Compute Units: 53)
F(11): 89         (Compute Units: 58)
F(12): 144        (Compute Units: 63)
F(13): 233        (Compute Units: 68)
F(14): 377        (Compute Units: 73)
F(15): 610        (Compute Units: 78)
F(16): 987        (Compute Units: 83)
F(17): 1597       (Compute Units: 88)
F(18): 2584       (Compute Units: 93)
F(19): 4181       (Compute Units: 98)
F(20): 6765       (Compute Units: 103)
F(21): 10946      (Compute Units: 108)
F(22): 17711      (Compute Units: 113)
F(23): 28657      (Compute Units: 118)
F(24): 46368      (Compute Units: 123)
F(25): 75025      (Compute Units: 128)
F(26): 121393     (Compute Units: 133)
F(27): 196418     (Compute Units: 138)
F(28): 317811     (Compute Units: 143)
F(29): 514229     (Compute Units: 148)
F(30): 832040     (Compute Units: 153)
F(31): 1346269    (Compute Units: 158)
F(32): 2178309    (Compute Units: 163)
F(33): 3524578    (Compute Units: 168)
F(34): 5702887    (Compute Units: 173)
F(35): 9227465    (Compute Units: 178)
F(36): 14930352   (Compute Units: 183)
F(37): 24157817   (Compute Units: 188)
F(38): 39088169   (Compute Units: 193)
F(39): 63245986   (Compute Units: 198)
F(40): 102334155  (Compute Units: 203)
F(41): 165580141  (Compute Units: 208)
F(42): 267914296  (Compute Units: 213)
F(43): 433494437  (Compute Units: 218)
F(44): 701408733  (Compute Units: 223)
F(45): 1134903170 (Compute Units: 228)
F(46): 1836311903 (Compute Units: 233)
F(47): 2971215073 (Compute Units: 238)
test tests::test_asm ... ok
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 4 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xffffffff
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 6 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xfffffffe
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... success
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 8 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 18 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xd
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x15
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 48 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x22
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x37
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x59
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x90
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 68 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe9
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x179
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x262
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3db
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x63d
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 93 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa18
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 98 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1055
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1a6d
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 108 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2ac2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 113 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x452f
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 118 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6ff1
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 123 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb520
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 128 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x12511
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 133 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1da31
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 138 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2ff42
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 143 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4d973
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 148 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7d8b5
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 153 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xcb228
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 158 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x148add
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 163 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x213d05
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 168 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x35c7e2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 173 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5704e7
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 178 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8cccc9
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 183 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe3d1b0
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 188 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1709e79
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 193 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2547029
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 198 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3c50ea2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 203 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6197ecb
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 208 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9de8d6d
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 213 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xff80c38
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 218 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x19d699a5
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 223 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x29cea5dd
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 228 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x43a53f82
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 233 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6d73e55f
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 238 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb11924e1

🦀 Rust implementation

The Rust implementation mirrors the assembly logic but uses a function to encapsulate the Fibonacci computation, which is written specifically to produce a comparable assembly loop output:

rs
use pinocchio::{entrypoint, error::ProgramError, AccountView, Address, ProgramResult};

const E_MAX_N: u32 = 0xfffffffe;
const MAX_N: u8 = 47;
const MAX_N_SPECIAL_CASE: u8 = 1;

entrypoint!(process_instruction);

#[cfg_attr(not(target_os = "solana"), allow(unused_variables))]
fn process_instruction(
    _program_id: &Address,
    _accounts: &[AccountView],
    instruction_data: &[u8],
) -> ProgramResult {
    let n = instruction_data[0];

    match n {
        0 => Ok(()),
        MAX_N_SPECIAL_CASE => Err(ProgramError::Custom(MAX_N_SPECIAL_CASE as u32)),
        n if n > MAX_N => Err(ProgramError::Custom(E_MAX_N)),
        _ => Err(ProgramError::Custom(fib(n as u64))),
    }
}

// If r8 is a u8 the compiler generates an extra opcode to cast it to u8.
fn fib(mut r8: u64) -> u32 {
    let mut r6: u32 = 0;
    let mut r7: u32 = 1;
    loop {
        let r9 = r6;
        r6 = r7;
        unsafe {
            r7 = r7.unchecked_add(r9);
            r8 = r8.unchecked_sub(1);
        };
        if r8 == 1 {
            return r7;
        };
    }
}

Note that unlike the assembly version, the Rust implementation doesn't check for the number of passed accounts because Pinocchio's entrypoint! macro by default handles account parsing automatically, including specifying a maximum number of accounts, past which any extra accounts are ignored.

rs-disassembly.s (core Fibonacci logic highlighted)
asm
.globl entrypoint

entrypoint:
  add64 r10, -2048
  mov64 r2, r1
  add64 r2, 8
  ldxdw r3, [r1+0]
  jeq r3, 0, jmp_00a0
  stxdw [r10+16], r2
  ldxdw r2, [r1+88]
  add64 r1, r2
  add64 r1, 10351
  and64 r1, -8
  jeq r3, 1, jmp_00a8
  jne r3, 2, jmp_0150
  ldxb r2, [r1+0]
  jne r2, 255, jmp_0610
  stxdw [r10+24], r1

jmp_0078:
  ldxdw r2, [r1+80]
  add64 r1, r2
  add64 r1, 10343
  and64 r1, -8
  ja jmp_00a8

jmp_00a0:
  mov64 r1, r2

jmp_00a8:
  ldxdw r2, [r1+0]
  jeq r2, 0, jmp_08e0
  ldxb r1, [r1+8]
  jeq r1, 0, jmp_00e0
  jne r1, 1, jmp_00f0
  mov64 r0, 1
  ja jmp_0148

jmp_00e0:
  mov64 r0, r1
  ja jmp_0148

jmp_00f0:
  mov32 r0, -2
  jgt r1, 47, jmp_0148
  mov32 r2, 1
  mov32 r3, 0
  add64 r1, -1
  mov32 r0, 1

jmp_0120:
  add32 r0, r3
  add64 r1, -1
  mov64 r3, r2
  mov64 r2, r0
  jne r1, 0, jmp_0120

jmp_0148:
  exit

jmp_0150:
  mov64 r2, r10
  add64 r2, 16
  jlt r3, 6, jmp_0420
  mov64 r2, r10
  add64 r2, 16

jmp_0178:
  ldxb r4, [r1+0]
  jne r4, 255, jmp_02b0
  stxdw [r2+8], r1
  ldxdw r4, [r1+80]
  add64 r1, r4
  add64 r1, 10343
  and64 r1, -8
  ldxb r4, [r1+0]
  jne r4, 255, jmp_02f8

jmp_01c0:
  stxdw [r2+16], r1
  ldxdw r4, [r1+80]
  add64 r1, r4
  add64 r1, 10343
  and64 r1, -8
  ldxb r4, [r1+0]
  jne r4, 255, jmp_0340

jmp_01f8:
  stxdw [r2+24], r1
  ldxdw r4, [r1+80]
  add64 r1, r4
  add64 r1, 10343
  and64 r1, -8
  ldxb r4, [r1+0]
  jne r4, 255, jmp_0388

jmp_0230:
  stxdw [r2+32], r1
  ldxdw r4, [r1+80]
  add64 r1, r4
  add64 r1, 10343
  and64 r1, -8
  add64 r2, 40
  ldxb r4, [r1+0]
  jne r4, 255, jmp_03d8

jmp_0270:
  stxdw [r2+0], r1
  ldxdw r4, [r1+80]
  add64 r1, r4
  add64 r1, 10343
  and64 r1, -8
  add64 r3, -5
  jgt r3, 5, jmp_0178
  ja jmp_0420

jmp_02b0:
  lsh64 r4, 3
  mov64 r5, r10
  add64 r5, 16
  add64 r5, r4
  ldxdw r4, [r5+0]
  stxdw [r2+8], r4
  add64 r1, 8
  ldxb r4, [r1+0]
  jeq r4, 255, jmp_01c0

jmp_02f8:
  lsh64 r4, 3
  mov64 r5, r10
  add64 r5, 16
  add64 r5, r4
  ldxdw r4, [r5+0]
  stxdw [r2+16], r4
  add64 r1, 8
  ldxb r4, [r1+0]
  jeq r4, 255, jmp_01f8

jmp_0340:
  lsh64 r4, 3
  mov64 r5, r10
  add64 r5, 16
  add64 r5, r4
  ldxdw r4, [r5+0]
  stxdw [r2+24], r4
  add64 r1, 8
  ldxb r4, [r1+0]
  jeq r4, 255, jmp_0230

jmp_0388:
  lsh64 r4, 3
  mov64 r5, r10
  add64 r5, 16
  add64 r5, r4
  ldxdw r4, [r5+0]
  stxdw [r2+32], r4
  add64 r1, 8
  add64 r2, 40
  ldxb r4, [r1+0]
  jeq r4, 255, jmp_0270

jmp_03d8:
  lsh64 r4, 3
  mov64 r5, r10
  add64 r5, 16
  add64 r5, r4
  ldxdw r4, [r5+0]
  stxdw [r2+0], r4
  add64 r1, 8
  add64 r3, -5
  jgt r3, 5, jmp_0178

jmp_0420:
  jsle r3, 2, jmp_04c8
  jeq r3, 3, jmp_04f0
  jne r3, 4, jmp_0548
  ldxb r3, [r1+0]
  jne r3, 255, jmp_06d0
  stxdw [r2+8], r1
  ldxdw r3, [r1+80]
  add64 r1, r3
  add64 r1, 10343
  and64 r1, -8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0718

jmp_0480:
  stxdw [r2+16], r1
  ldxdw r3, [r1+80]
  add64 r1, r3
  add64 r1, 10343
  and64 r1, -8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0760

jmp_04b8:
  stxdw [r2+24], r1
  ja jmp_0078

jmp_04c8:
  jeq r3, 1, jmp_00a8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_08a8
  stxdw [r2+8], r1
  ja jmp_0078

jmp_04f0:
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0650
  stxdw [r2+8], r1
  ldxdw r3, [r1+80]
  add64 r1, r3
  add64 r1, 10343
  and64 r1, -8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0698

jmp_0538:
  stxdw [r2+16], r1
  ja jmp_0078

jmp_0548:
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0798
  stxdw [r2+8], r1
  ldxdw r3, [r1+80]
  add64 r1, r3
  add64 r1, 10343
  and64 r1, -8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_07e0

jmp_0590:
  stxdw [r2+16], r1
  ldxdw r3, [r1+80]
  add64 r1, r3
  add64 r1, 10343
  and64 r1, -8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0828

jmp_05c8:
  stxdw [r2+24], r1
  ldxdw r3, [r1+80]
  add64 r1, r3
  add64 r1, 10343
  and64 r1, -8
  ldxb r3, [r1+0]
  jne r3, 255, jmp_0870

jmp_0600:
  stxdw [r2+32], r1
  ja jmp_0078

jmp_0610:
  lsh64 r2, 3
  mov64 r3, r10
  add64 r3, 16
  add64 r3, r2
  ldxdw r2, [r3+0]
  stxdw [r10+24], r2

jmp_0640:
  add64 r1, 8
  ja jmp_00a8

jmp_0650:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+8], r3
  add64 r1, 8
  ldxb r3, [r1+0]
  jeq r3, 255, jmp_0538

jmp_0698:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+16], r3
  ja jmp_0640

jmp_06d0:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+8], r3
  add64 r1, 8
  ldxb r3, [r1+0]
  jeq r3, 255, jmp_0480

jmp_0718:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+16], r3
  add64 r1, 8
  ldxb r3, [r1+0]
  jeq r3, 255, jmp_04b8

jmp_0760:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+24], r3
  ja jmp_0640

jmp_0798:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+8], r3
  add64 r1, 8
  ldxb r3, [r1+0]
  jeq r3, 255, jmp_0590

jmp_07e0:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+16], r3
  add64 r1, 8
  ldxb r3, [r1+0]
  jeq r3, 255, jmp_05c8

jmp_0828:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+24], r3
  add64 r1, 8
  ldxb r3, [r1+0]
  jeq r3, 255, jmp_0600

jmp_0870:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+32], r3
  ja jmp_0640

jmp_08a8:
  lsh64 r3, 3
  mov64 r4, r10
  add64 r4, 16
  add64 r4, r3
  ldxdw r3, [r4+0]
  stxdw [r2+8], r3
  ja jmp_0640

jmp_08e0:
  mov32 r3, 7256
  hor64 r3, 0
  mov64 r1, 0
  mov64 r2, 0
  call fn_09a8
  ldxdw r2, [r1+8]
  ldxdw r1, [r2+0]
  ldxdw r2, [r2+8]
  add64 r2, -1
  call sol_log_
  mov32 r1, 6985
  hor64 r1, 0
  mov64 r2, 14
  call sol_log_
  exit

fn_0958:
  call fn_0960

fn_0960:
  call custom_panic
  call abort

fn_0970:
  add64 r10, -64
  stxdw [r10+48], r2
  stxdw [r10+40], r1
  sth [r10+56], 1
  mov64 r1, r10
  add64 r1, 40
  call fn_0958

fn_09a8:
  add64 r10, -128
  stxdw [r10+40], r2
  stxdw [r10+32], r1
  mov32 r1, 7280
  hor64 r1, 0
  stxdw [r10+48], r1
  mov64 r1, r10
  add64 r1, 96
  stxdw [r10+64], r1
  mov64 r1, r10
  add64 r1, 32
  stxdw [r10+112], r1
  mov32 r1, 6208
  hor64 r1, 0
  stxdw [r10+120], r1
  stxdw [r10+104], r1
  mov64 r1, r10
  add64 r1, 40
  stxdw [r10+96], r1
  stdw [r10+80], 0
  stdw [r10+56], 2
  stdw [r10+72], 2
  mov64 r1, r10
  add64 r1, 48
  mov64 r2, r3
  call fn_0970

fn_0a78:
  add64 r10, -128
  mov64 r0, r1
  ldxdw r9, [r10+120]
  stxdw [r10+80], r9
  jeq r2, 0, jmp_0ad8
  mov32 r2, 1114112
  ldxw r6, [r0+16]
  mov64 r1, r6
  and32 r1, 2097152
  jeq r1, 0, jmp_0af0
  mov32 r2, 43
  ja jmp_0ae8

jmp_0ad8:
  mov32 r2, 45
  ldxw r6, [r0+16]

jmp_0ae8:
  add64 r9, 1

jmp_0af0:
  mov64 r1, r6
  and32 r1, 8388608
  stxdw [r10+96], r4
  stxw [r10+88], r2
  jne r1, 0, jmp_0bd0
  mov64 r1, 0
  stxdw [r10+104], r1
  mov64 r7, r9
  ldxh r2, [r0+20]
  jlt r7, r2, jmp_0cd0

jmp_0b40:
  mov64 r9, r5
  ldxdw r8, [r0+8]
  ldxdw r7, [r0+0]
  mov64 r1, r7
  mov64 r2, r8
  ldxw r3, [r10+88]
  ldxdw r4, [r10+104]
  ldxdw r5, [r10+96]
  call fn_10a0
  mov32 r3, 1
  jne r0, 0, jmp_1088
  ldxdw r4, [r8+24]
  mov64 r1, r7
  mov64 r2, r9
  ldxdw r3, [r10+80]
  callx r4
  mov64 r3, r0
  ja jmp_1088

jmp_0bd0:
  stxdw [r10+104], r3
  jge r4, 32, jmp_0c68
  mov64 r7, 0
  jeq r4, 0, jmp_0cb8
  ldxdw r1, [r10+104]
  mov64 r2, r4
  ja jmp_0c28

jmp_0c08:
  add64 r7, r3
  add64 r1, 1
  add64 r2, -1
  jeq r2, 0, jmp_0cb8

jmp_0c28:
  ldxb r4, [r1+0]
  lsh32 r4, 24
  arsh32 r4, 24
  mov32 r3, 1
  mov32 r4, r4
  jsgt r4, -65, jmp_0c08
  mov32 r3, 0
  ja jmp_0c08

jmp_0c68:
  mov64 r1, r3
  mov64 r2, r4
  mov64 r7, r6
  mov64 r6, r5
  mov64 r8, r0
  call fn_1148
  mov64 r5, r6
  mov64 r6, r7
  mov64 r7, r0
  mov64 r0, r8

jmp_0cb8:
  add64 r7, r9
  ldxh r2, [r0+20]
  jge r7, r2, jmp_0b40

jmp_0cd0:
  and32 r2, -1
  mov64 r1, r6
  and32 r1, 16777216
  stxdw [r10+64], r5
  jne r1, 0, jmp_0d48
  and32 r7, -1
  sub32 r2, r7
  mov64 r1, r6
  rsh32 r1, 29
  and32 r1, 3
  jsgt r1, 1, jmp_0e60
  mov32 r8, 0
  jeq r1, 0, jmp_0e88
  mov64 r8, r2
  ja jmp_0e88

jmp_0d48:
  stxdw [r10+72], r2
  ldxdw r1, [r0+16]
  stxdw [r10+56], r1
  and32 r1, -1
  and32 r1, -1612709888
  or32 r1, 536870960
  stxw [r0+16], r1
  ldxdw r8, [r0+0]
  stxdw [r10+112], r0
  ldxdw r9, [r0+8]
  mov64 r1, r8
  mov64 r2, r9
  ldxw r3, [r10+88]
  ldxdw r4, [r10+104]
  ldxdw r5, [r10+96]
  call fn_10a0
  mov32 r3, 1
  jne r0, 0, jmp_1088
  and32 r7, -1
  ldxdw r2, [r10+72]
  sub32 r2, r7
  mov32 r7, 0
  and32 r2, 65535

jmp_0e00:
  mov64 r1, r7
  and32 r1, 65535
  jge r1, r2, jmp_1030
  ldxdw r3, [r9+32]
  mov64 r1, r8
  mov64 r6, r2
  mov32 r2, 48
  callx r3
  mov64 r2, r6
  add32 r7, 1
  jeq r0, 0, jmp_0e00
  ja jmp_0f10

jmp_0e60:
  mov64 r8, r2
  jne r1, 2, jmp_0e88
  mov64 r8, r2
  and32 r8, 65534
  rsh32 r8, 1

jmp_0e88:
  stxdw [r10+72], r2
  and32 r6, 2097151
  stxw [r10+112], r6
  mov32 r6, 0
  ldxdw r7, [r0+8]
  ldxdw r9, [r0+0]

jmp_0eb8:
  mov64 r1, r8
  and32 r1, 65535
  mov64 r2, r6
  and32 r2, 65535
  jge r2, r1, jmp_0f20
  ldxdw r3, [r7+32]
  mov64 r1, r9
  ldxw r2, [r10+112]
  callx r3
  add32 r6, 1
  jeq r0, 0, jmp_0eb8

jmp_0f10:
  mov32 r3, 1
  ja jmp_1088

jmp_0f20:
  mov64 r1, r9
  mov64 r2, r7
  ldxw r3, [r10+88]
  ldxdw r4, [r10+104]
  ldxdw r5, [r10+96]
  call fn_10a0
  mov32 r3, 1
  jne r0, 0, jmp_1088
  ldxdw r4, [r7+24]
  mov64 r1, r9
  ldxdw r2, [r10+64]
  ldxdw r3, [r10+80]
  callx r4
  mov32 r3, 1
  ldxdw r6, [r10+72]
  jne r0, 0, jmp_1088
  sub32 r6, r8
  mov32 r8, 0
  and32 r6, 65535

jmp_0fb8:
  mov64 r1, r8
  and32 r1, 65535
  mov32 r3, 1
  jlt r1, r6, jmp_0fe0
  mov32 r3, 0

jmp_0fe0:
  jge r1, r6, jmp_1088
  stxw [r10+104], r3
  ldxdw r3, [r7+32]
  mov64 r1, r9
  ldxw r2, [r10+112]
  callx r3
  ldxw r3, [r10+104]
  add32 r8, 1
  jeq r0, 0, jmp_0fb8
  ja jmp_1088

jmp_1030:
  ldxdw r4, [r9+24]
  mov64 r1, r8
  ldxdw r2, [r10+64]
  ldxdw r3, [r10+80]
  callx r4
  mov32 r3, 1
  jne r0, 0, jmp_1088
  ldxdw r1, [r10+112]
  ldxdw r2, [r10+56]
  stxdw [r1+16], r2
  mov32 r3, 0

jmp_1088:
  and32 r3, 1
  mov64 r0, r3
  exit

fn_10a0:
  mov64 r6, r5
  mov64 r7, r4
  mov64 r8, r2
  mov32 r2, r3
  jeq r2, 1114112, jmp_1108
  ldxdw r4, [r8+32]
  mov64 r9, r1
  mov64 r2, r3
  callx r4
  mov64 r1, r9
  mov64 r2, r0
  mov32 r0, 1
  jne r2, 0, jmp_1140

jmp_1108:
  jeq r7, 0, jmp_1138
  ldxdw r4, [r8+24]
  mov64 r2, r7
  mov64 r3, r6
  callx r4
  ja jmp_1140

jmp_1138:
  mov32 r0, 0

jmp_1140:
  exit

fn_1148:
  add64 r10, -64
  mov64 r7, r1
  add64 r7, 7
  and64 r7, -8
  mov64 r3, r7
  sub64 r3, r1
  jge r2, r3, jmp_11f8

jmp_1180:
  mov64 r0, 0
  jne r2, 0, jmp_11b8
  ja jmp_1718

jmp_1198:
  add64 r0, r3
  add64 r1, 1
  add64 r2, -1
  jeq r2, 0, jmp_1718

jmp_11b8:
  ldxb r4, [r1+0]
  lsh32 r4, 24
  arsh32 r4, 24
  mov32 r3, 1
  mov32 r4, r4
  jsgt r4, -65, jmp_1198
  mov32 r3, 0
  ja jmp_1198

jmp_11f8:
  mov64 r5, r2
  sub64 r5, r3
  jlt r5, 8, jmp_1180
  stxdw [r10+56], r3
  mov64 r2, r5
  and64 r2, 7
  mov64 r0, 0
  mov64 r3, 0
  jne r7, r1, jmp_1550

jmp_1240:
  ldxdw r4, [r10+56]
  add64 r1, r4
  jeq r2, 0, jmp_12e8
  mov64 r0, r5
  and64 r0, -8
  mov64 r4, r1
  add64 r4, r0
  mov64 r0, 0
  ja jmp_12a8

jmp_1288:
  add64 r0, r6
  add64 r4, 1
  add64 r2, -1
  jeq r2, 0, jmp_12e8

jmp_12a8:
  ldxb r7, [r4+0]
  lsh32 r7, 24
  arsh32 r7, 24
  mov32 r6, 1
  mov32 r7, r7
  jsgt r7, -65, jmp_1288
  mov32 r6, 0
  ja jmp_1288

jmp_12e8:
  rsh64 r5, 3
  add64 r0, r3
  ja jmp_13a8

jmp_1300:
  mov64 r1, r2
  add64 r1, r5
  ldxdw r9, [r10+56]
  mov64 r7, r9
  and64 r7, 3
  mov64 r5, r3
  sub64 r5, r9
  mov32 r6, 16711935
  hor64 r6, 16711935
  mov64 r8, r4
  and64 r8, r6
  rsh64 r4, 8
  and64 r4, r6
  add64 r4, r8
  mov32 r6, 65537
  hor64 r6, 65537
  lmul64 r4, r6
  rsh64 r4, 48
  add64 r4, r0
  mov64 r0, r4
  jne r7, 0, jmp_1608

jmp_13a8:
  mov64 r3, r5
  mov64 r2, r1
  jeq r3, 0, jmp_1718
  mov64 r5, r3
  jlt r3, 192, jmp_13d8
  mov64 r5, 192

jmp_13d8:
  stxdw [r10+56], r5
  lsh64 r5, 3
  mov64 r4, 0
  jlt r3, 4, jmp_1300
  mov64 r4, r5
  and64 r4, 2016
  mov64 r1, r2
  add64 r1, r4
  mov64 r4, 0
  mov64 r7, r2

jmp_1428:
  ldxdw r9, [r7+0]
  mov64 r8, r9
  rsh64 r8, 6
  xor64 r9, -1
  rsh64 r9, 7
  or64 r9, r8
  mov32 r8, 16843009
  hor64 r8, 16843009
  and64 r9, r8
  add64 r9, r4
  ldxdw r4, [r7+8]
  mov64 r6, r4
  rsh64 r6, 6
  xor64 r4, -1
  rsh64 r4, 7
  or64 r4, r6
  and64 r4, r8
  add64 r4, r9
  ldxdw r9, [r7+16]
  mov64 r6, r9
  rsh64 r6, 6
  xor64 r9, -1
  rsh64 r9, 7
  or64 r9, r6
  and64 r9, r8
  add64 r9, r4
  ldxdw r4, [r7+24]
  mov64 r6, r4
  rsh64 r6, 6
  xor64 r4, -1
  rsh64 r4, 7
  or64 r4, r6
  and64 r4, r8
  add64 r4, r9
  add64 r7, 32
  jne r7, r1, jmp_1428
  ja jmp_1300

jmp_1550:
  mov64 r6, r1
  sub64 r6, r7
  mov64 r7, r1
  ja jmp_1590

jmp_1570:
  add64 r3, r9
  add64 r7, 1
  mov32 r4, r8
  jeq r4, 1, jmp_1240

jmp_1590:
  ldxb r9, [r7+0]
  lsh32 r9, 24
  arsh32 r9, 24
  mov32 r8, 1
  mov32 r4, r9
  mov32 r9, 1
  jsle r4, -65, jmp_15e0
  add64 r6, 1
  jeq r6, 0, jmp_1570
  ja jmp_15f8

jmp_15e0:
  mov32 r9, 0
  add64 r6, 1
  jeq r6, 0, jmp_1570

jmp_15f8:
  mov32 r8, 0
  ja jmp_1570

jmp_1608:
  and64 r9, 252
  lsh64 r9, 3
  jlt r3, 192, jmp_1628
  mov64 r3, 192

jmp_1628:
  add64 r2, r9
  mov64 r1, 0
  and64 r3, 3
  lsh64 r3, 3

jmp_1648:
  ldxdw r0, [r2+0]
  mov64 r5, r0
  rsh64 r5, 6
  xor64 r0, -1
  rsh64 r0, 7
  or64 r0, r5
  mov32 r5, 16843009
  hor64 r5, 16843009
  and64 r0, r5
  add64 r0, r1
  add64 r2, 8
  add64 r3, -8
  mov64 r1, r0
  jne r3, 0, jmp_1648
  mov32 r1, 16711935
  hor64 r1, 16711935
  mov64 r2, r0
  and64 r2, r1
  rsh64 r0, 8
  and64 r0, r1
  add64 r0, r2
  mov32 r1, 65537
  hor64 r1, 65537
  lmul64 r0, r1
  rsh64 r0, 48
  add64 r0, r4

jmp_1718:
  exit
  add64 r10, -64
  mov64 r3, 20
  ldxdw r1, [r1+0]
  mov64 r4, r1
  jlt r1, 1000, jmp_1878
  mov64 r3, 16
  mov64 r4, r1

jmp_1758:
  mov64 r5, r4
  mov64 r0, r5
  and32 r0, -1
  udiv64 r4, 10000
  mov64 r6, r4
  and32 r6, -1
  lmul32 r6, 10000
  sub32 r0, r6
  mov64 r6, r0
  and32 r6, 65535
  udiv32 r6, 100
  mov64 r7, r6
  lmul32 r7, 100
  sub32 r0, r7
  mov32 r7, 7050
  hor64 r7, 0
  lsh32 r0, 1
  and64 r0, 65534
  lsh32 r6, 1
  mov64 r8, r7
  add64 r8, r0
  add64 r7, r6
  mov64 r0, r10
  add64 r0, 44
  add64 r0, r3
  ldxb r6, [r7+1]
  stxb [r0+1], r6
  ldxb r6, [r7+0]
  stxb [r0+0], r6
  ldxb r6, [r8+1]
  stxb [r0+3], r6
  ldxb r6, [r8+0]
  stxb [r0+2], r6
  add64 r3, -4
  jgt r5, 9999999, jmp_1758
  add64 r3, 4

jmp_1878:
  jle r4, 9, jmp_1940
  and32 r4, -1
  mov64 r5, r4
  and32 r5, 65535
  udiv32 r5, 100
  mov64 r0, r5
  lmul32 r0, 100
  sub32 r4, r0
  lsh32 r4, 1
  mov32 r0, 7050
  hor64 r0, 0
  and64 r4, 65534
  add64 r0, r4
  mov64 r4, r10
  add64 r4, 44
  mov64 r6, r4
  add64 r6, r3
  ldxb r7, [r0+1]
  stxb [r6-1], r7
  add64 r3, -2
  add64 r4, r3
  ldxb r0, [r0+0]
  stxb [r4+0], r0
  jne r1, 0, jmp_1950
  ja jmp_1958

jmp_1940:
  mov64 r5, r4
  jeq r1, 0, jmp_1958

jmp_1950:
  jeq r5, 0, jmp_19b0

jmp_1958:
  mov32 r1, 7050
  hor64 r1, 0
  lsh64 r5, 1
  and64 r5, 30
  add64 r1, r5
  add64 r3, -1
  mov64 r4, r10
  add64 r4, 44
  add64 r4, r3
  ldxb r1, [r1+1]
  stxb [r4+0], r1

jmp_19b0:
  mov64 r1, r3
  sub64 r1, 20
  stxdw [r10-8], r1
  mov64 r5, r10
  add64 r5, 44
  add64 r5, r3
  mov64 r1, r2
  mov32 r2, 1
  mov64 r3, 1
  mov64 r4, 0
  call fn_0a78
  exit

.rodata
  data_0000: .byte 0x66, 0x69, 0x62, 0x6f, 0x6e, 0x61, 0x63, 0x63, 0x69, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2e, 0x72, 0x73, 0x00, 0x2a, 0x2a, 0x20, 0x50, 0x41, 0x4e, 0x49, 0x43, 0x4b, 0x45, 0x44, 0x20, 0x2a, 0x2a, 0x00, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x3a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x69, 0x73, 0x20, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, 0x31, 0x36, 0x31, 0x37, 0x31, 0x38, 0x31, 0x39, 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33, 0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32, 0x38, 0x32, 0x39, 0x33, 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, 0x34, 0x30, 0x34, 0x31, 0x34, 0x32, 0x34, 0x33, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37, 0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35, 0x33, 0x35, 0x34, 0x35, 0x35, 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, 0x36, 0x34, 0x36, 0x35, 0x36, 0x36, 0x36, 0x37, 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31, 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, 0x37, 0x36, 0x37, 0x37, 0x37, 0x38, 0x37, 0x39, 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33, 0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x30, 0x39, 0x31, 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35, 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39

The Rust implementation introduces some compute unit overhead compared to assembly:

test_rs
rs
#[test]
fn test_rs() {
    test_fibonacci_program(ProgramLanguage::Rust, false);
}
Test results
sh
Fibonacci numbers and compute units:
F(0):  0          (Compute Units: 13)
F(1):  1          (Compute Units: 14)
F(2):  1          (Compute Units: 23)
F(3):  2          (Compute Units: 28)
F(4):  3          (Compute Units: 33)
F(5):  5          (Compute Units: 38)
F(6):  8          (Compute Units: 43)
F(7):  13         (Compute Units: 48)
F(8):  21         (Compute Units: 53)
F(9):  34         (Compute Units: 58)
F(10): 55         (Compute Units: 63)
F(11): 89         (Compute Units: 68)
F(12): 144        (Compute Units: 73)
F(13): 233        (Compute Units: 78)
F(14): 377        (Compute Units: 83)
F(15): 610        (Compute Units: 88)
F(16): 987        (Compute Units: 93)
F(17): 1597       (Compute Units: 98)
F(18): 2584       (Compute Units: 103)
F(19): 4181       (Compute Units: 108)
F(20): 6765       (Compute Units: 113)
F(21): 10946      (Compute Units: 118)
F(22): 17711      (Compute Units: 123)
F(23): 28657      (Compute Units: 128)
F(24): 46368      (Compute Units: 133)
F(25): 75025      (Compute Units: 138)
F(26): 121393     (Compute Units: 143)
F(27): 196418     (Compute Units: 148)
F(28): 317811     (Compute Units: 153)
F(29): 514229     (Compute Units: 158)
F(30): 832040     (Compute Units: 163)
F(31): 1346269    (Compute Units: 168)
F(32): 2178309    (Compute Units: 173)
F(33): 3524578    (Compute Units: 178)
F(34): 5702887    (Compute Units: 183)
F(35): 9227465    (Compute Units: 188)
F(36): 14930352   (Compute Units: 193)
F(37): 24157817   (Compute Units: 198)
F(38): 39088169   (Compute Units: 203)
F(39): 63245986   (Compute Units: 208)
F(40): 102334155  (Compute Units: 213)
F(41): 165580141  (Compute Units: 218)
F(42): 267914296  (Compute Units: 223)
F(43): 433494437  (Compute Units: 228)
F(44): 701408733  (Compute Units: 233)
F(45): 1134903170 (Compute Units: 238)
F(46): 1836311903 (Compute Units: 243)
F(47): 2971215073 (Compute Units: 248)
test tests::test_rs ... ok
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xfffffffe
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 13 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... success
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 14 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 23 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 28 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 33 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 38 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 43 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 48 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xd
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 53 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x15
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 58 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x22
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 63 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x37
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 68 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x59
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 73 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x90
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 78 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe9
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 83 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x179
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 88 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x262
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 93 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3db
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 98 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x63d
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 103 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xa18
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 108 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1055
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 113 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1a6d
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 118 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2ac2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 123 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x452f
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 128 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6ff1
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 133 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb520
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 138 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x12511
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 143 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1da31
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 148 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2ff42
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 153 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x4d973
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 158 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x7d8b5
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 163 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xcb228
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 168 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x148add
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 173 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x213d05
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 178 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x35c7e2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 183 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x5704e7
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 188 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x8cccc9
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 193 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xe3d1b0
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 198 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x1709e79
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 203 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x2547029
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 208 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x3c50ea2
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 213 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6197ecb
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 218 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x9de8d6d
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 223 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xff80c38
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 228 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x19d699a5
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 233 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x29cea5dd
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 238 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x43a53f82
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 243 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0x6d73e55f
[ ... DEBUG ... ] Program DASMAC... invoke [1]
[ ... DEBUG ... ] Program DASMAC... consumed 248 of 1400000 compute units
[ ... DEBUG ... ] Program DASMAC... failed: custom program error: 0xb11924e1

✅ All tests

tests.rs
rs
use std::vec;

use fib_rs::Fib;
use mollusk_svm::result::Check;
use solana_sdk::instruction::Instruction;
use solana_sdk::program_error::ProgramError;
use test_utils::{setup_test, single_mock_account, ProgramLanguage};

const MAX_FIB_INDEX_U32: u8 = 47;
const E_PASSED_ACCOUNT: u32 = u32::MAX;
const E_INDEX_TOO_BIG: u32 = u32::MAX - 1;

fn fib(n: u8) -> u64 {
    Fib::single(n.into()).try_into().unwrap()
}

fn test_fibonacci_program(language: ProgramLanguage, test_account_error: bool) {
    let setup = setup_test(language);

    if test_account_error {
        // Verify failure for passing an account.
        let (account, accounts) = single_mock_account();
        setup.mollusk.process_and_validate_instruction(
            &Instruction::new_with_bytes(setup.program_id, &[], accounts.clone()),
            &[account],
            &[Check::err(ProgramError::Custom(E_PASSED_ACCOUNT))],
        );
    }

    // Verify failure for index too big.
    setup.mollusk.process_and_validate_instruction(
        &Instruction::new_with_bytes(setup.program_id, &[MAX_FIB_INDEX_U32 + 1], vec![]),
        &[],
        &[Check::err(ProgramError::Custom(E_INDEX_TOO_BIG))],
    );

    // Initialize a vector with 48 slots, one for each Fibonacci number from F(0) to F(47), along
    // with their compute unit consumption.
    let mut fib_numbers: Vec<(u32, u64)> = vec![(0, 0); (MAX_FIB_INDEX_U32 + 1) as usize];

    // For F(0) = 0, the program result should be considered a success.
    fib_numbers[0] = (
        0,
        setup
            .mollusk
            .process_and_validate_instruction(
                &Instruction::new_with_bytes(setup.program_id, &[0], vec![]),
                &[],
                &[Check::success()],
            )
            .compute_units_consumed,
    );

    // For F(1) onwards, verify correct Fibonacci numbers are returned as a custom error.
    for n in 1..=MAX_FIB_INDEX_U32 {
        let expected_fib: u32 = fib(n) as u32;
        fib_numbers[n as usize] = (
            expected_fib,
            setup
                .mollusk
                .process_and_validate_instruction(
                    &Instruction::new_with_bytes(setup.program_id, &[n], vec![]),
                    &[],
                    &[Check::err(ProgramError::Custom(expected_fib))],
                )
                .compute_units_consumed,
        );
    }

    // Pretty print the Fibonacci numbers along with their compute unit consumption.
    println!("Fibonacci numbers and compute units:");
    for n in 0..=MAX_FIB_INDEX_U32 {
        println!(
            "{:<7}{:<10} (Compute Units: {})",
            format!("F({}):", n),
            fib_numbers[n as usize].0,
            fib_numbers[n as usize].1
        );
    }
}

#[test]
fn test_asm() {
    test_fibonacci_program(ProgramLanguage::Assembly, true);
}

#[test]
fn test_rs() {
    test_fibonacci_program(ProgramLanguage::Rust, false);
}

/// Verify the index of the maximum Fibonacci number that fits in a u32, while allowing space for
/// two error codes that may be returned by the Fibonacci program.
#[test]
fn test_max_fib_u32() {
    assert!(fib(MAX_FIB_INDEX_U32) <= E_INDEX_TOO_BIG.into());
    assert!(fib(MAX_FIB_INDEX_U32 + 1) > u32::MAX.into());
}

NOTE

The assembly file in this example was adapted from an implementation by 7etsuo.