DEV Community

Murtala Mudi
Murtala Mudi

Posted on

100 Days of Solana — Day 20: I Tried to Break Solana and It Charged Me for It

Let me tell you about the moment Solana surprised me.

I was building a transfer script this week. Nothing fancy, just a tool that moves SOL from one wallet to another programmatically. I wanted to see what happens when a transaction fails on-chain. Not a simulation. Not a dry run. An actual failed transaction sent straight to the network.

So I deliberately tried to transfer 500 SOL from a wallet holding about 5.5 SOL.

Obviously it was going to fail. That was the point.

What I did not expect was the bill.


Failure is not free on Solana

In Web2, when a database transaction rolls back, nothing happens to your infrastructure costs in that moment. The operation failed, the state did not change, you try again. No charge for the failed attempt.

On Solana, validators are real machines run by real people. When you send a transaction, those machines do actual work before they even get to decide if it succeeds. They ingest it, parse the signatures, verify the accounts, check the bounds. That work costs compute resources.

So they get paid. Even when your transaction fails.

Here is exactly what I saw in the terminal after my intentionally broken transfer hit the network:

Transaction executed in slot 465034224:
  Recent Blockhash: ENvhACYop3KqzHZVwcGxmKTCKCvpQtnUotTUiU4K3B4c
  Account 0: srw- cRrbhRLCyJcWV6Tmzti4v7aXXXSaRVckTGwaDCspNZM (fee payer)

  Instruction 0
    Program: 11111111111111111111111111111111
    Transfer { lamports: 500000000000 }

  Status: Error processing Instruction 0: custom program error: 0x1
    Fee: ◎0.000005
    Account 0 balance: ◎5.537975 -> ◎5.537970

  Log Messages:
    Program 11111111111111111111111111111111 invoke [1]
    Transfer: insufficient lamports 5537970000, need 500000000000
    Program 11111111111111111111111111111111 failed: custom program error: 0x1
Enter fullscreen mode Exit fullscreen mode

Look at that balance line. 5.537975 -> 5.537970. The transfer did not go through. But the wallet still lost 0.000005 SOL.

Small amount. Big lesson.


What that error code actually means

The runtime returned custom program error: 0x1. That is not a random code. In Solana's System Program source code, 0x1 maps directly to InsufficientFundsForTransfer. Every error has a specific hex identity. When something breaks, you can trace it back to exactly what went wrong at the program level.

This is actually useful once you get used to it. Error messages in Web2 backends can be vague. Here everything is explicit and traceable.


The pipe pattern changed how I think about building transactions

Something else shifted this week on the code side.

If you read older Solana tutorials, you will see transactions built like this: create an object, mutate it, add instructions one by one. It is the old way and it works, but the modern @solana/kit does it differently.

Everything is a pipeline. You start with a base message and pass it through a series of functions, each one adding something to it:

const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  (tx) => setTransactionMessageFeePayerSigner(signer, tx),
  (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
  (tx) => appendTransactionMessageInstruction(
    getTransferSolInstruction({
      source: signer,
      destination: destinationAddress,
      amount: lamportAmount,
    }),
    tx
  )
);
Enter fullscreen mode Exit fullscreen mode

Each step is pure. Nothing mutates. You can read it top to bottom and understand exactly what the transaction contains before it ever touches the network. Coming from JavaScript where we mutate state constantly, this took a little getting used to. But once it clicks it feels cleaner than the old approach.


The 1,232 byte limit is real and it forces good habits

One more thing worth knowing. Every Solana transaction has to fit inside 1,232 bytes. That is the network packet size limit and it is not flexible.

In Web2 you can send massive JSON payloads without thinking about it. On Solana you have to be intentional about how many accounts you include, how you pack your instructions, what you actually need versus what you are dragging along unnecessarily.

It is a constraint that makes you think more carefully about what you are building. I have started to appreciate that.


What I am walking away with from this week

Three things:

Always simulate before you send. The SDK has pre-flight simulation built in. Use it so your users are not paying fees for errors you could have caught locally.

Errors are traceable. Hex codes, program logs, account balance diffs. Everything is on-chain and readable. The transparency is actually one of the best parts of building here.

The functional pipe pattern is worth learning. It makes your transaction construction readable and predictable in a way that feels very different from the object mutation style.

Twenty days in. Still learning. Still occasionally breaking things on devnet.

But I understand why things break now, and that is progress.

100DaysOfSolana #Solana #Web3 #buildinpublic


Part of my ongoing #100DaysOfSolana journey with Major League Hacking.

Top comments (0)