← Writing

Joining open source as a contributor

At a TOKEN2049 side event, some developer friends told me open source is a good place to start, so I decided to try it myself.

A merged pull request on GitHub, anza-xyz/solana-sdk #1064, program-option: Fix infinite recursion in COption::clone_from. My description explains that the fallback arm called clone_from on the COption itself, so any call with a None side never returns; the maintainer, joncinque, approves and writes that the code didn't work, that the change is the same as Option's implementation, and that the change works.

TOKEN2049 came to Marina Bay Sands on 7 and 8 October [1], and the week around it filled up with side events, as it does every year. At one of them I spent hours talking with some developer friends. One thing they said stayed with me: if you want to get better at building, open source is a good place to start. Pick a library you already use, read it, and when you find something wrong, send a small fix.

I decided to try it myself. The day after the conference ended I opened my first pull request, and I have kept going since. I won’t list every contribution here; anyone curious can find the projects in a list on my GitHub [2].

How I look for a bug

Small fixes are the way in, but small does not mean easy to find. Maintainers do not need a stranger to rename their variables. What helps them is a place where the code does not do what it says it does, shown with a test.

So I read code the way I used to read a derivation: line by line, asking what each step claims and whether it still holds at the edges. What does this function promise, in its name, its types, its documentation or the standard it implements? And what happens with the inputs nobody tried: an empty value, a negative number, a string that happens to look like hex? The three bugs below were all found that way.

Three bugs I fixed, for example

The first is the smallest. Rust’s Option has no fixed memory layout, and Solana account data is read byte by byte by other programs, so the Solana SDK has COption, a C-compatible version of it [3]. COption implements clone_from, which overwrites one value with a copy of another. It handled two Some values correctly, but the branch for every other case called clone_from again, on the same two values. A call with None on either side never returned: it just kept calling itself, forever in an optimised build, or until the stack ran out in a debug one.

The diff of anza-xyz/solana-sdk #1064 on GitHub: in program-option/src/lib.rs, the line (to, from) => to.clone_from(from), is replaced by (to, from) => *to = from.clone(), inside COption's clone_from.
The fix is one line: copy the value instead of calling the same function again [4].

The fix copies the value instead, as Rust’s own Option does, with a test that hangs on the old code and passes on the new one. The maintainer checked it against Option and merged it [4].

The second was in viem, a TypeScript library for Ethereum. When a Solidity event marks a string argument as indexed, the log does not store the string itself but the Keccak-256 hash of its UTF-8 bytes [5], so a filter has to hash the string the same way to find the event. viem passed indexed strings through a helper that turns hex-looking input into raw bytes. For most strings that made no difference. But a string that happens to look like hex, such as an address written as text, was hashed as twenty raw bytes instead of 42 characters, and a filter for that event quietly found nothing. The fix hashes strings as text and leaves bytes arguments as they were [6].

The third took me back to my year on superconducting qubits. Quantum Metal, formerly Qiskit Metal, is an open-source tool for drawing the layout of superconducting quantum chips, first developed at IBM and now maintained by its community [7]. One of its components draws a rectangular spiral of a requested length, and in a chip layout that length is meant to set how the component behaves electrically. The formula for the spiral’s width subtracted twice the spacing its turns actually use, so the default 2000 µm spiral came out 1849.5 µm long. I worked the width out again from the drawn centre line, and added a test that measures the drawn spiral against the requested length [8].

What the maintainers taught me

None of this is written in a CONTRIBUTING file. I learned it one review at a time.

First, read before you write. Before I change anything in a repository, I read its recent history: how titles are written, how long the descriptions are, whether there is a template. A pull request that looks like the ones a maintainer already merges is easier for them to review.

Second, show the bug before you fix it. A failing test that passes after the change takes a maintainer a minute to check. A description alone can take an hour.

Third, keep it small and be patient. One problem per pull request, nothing reformatted on the side, and only a couple open in the same repository at once. Some projects also only accept signed commits, and on many a newcomer’s tests don’t run until a maintainer approves them [9], so a pull request can wait days for reasons that have nothing to do with the code.

Fourth, be glad to be wrong. On Solana Playground, the maintainer pointed out that a recent change had probably broken my fix and asked me to re-check. I did, found the case was already handled further up, and closed it myself [10]. On another fix the reviewer asked for more than I had done, and for sturdier tests, and the change was better for it.

What I got out of it

I am still a beginner at open source. But being able to repair something in a library I use myself, whether it makes the library a little better for the people who use it or gives its developers one more test, leaves me a lot of room to grow, and I have learned a great deal from it. It has changed how I think as a developer, and it has shown me how much work it takes to keep a large product maintained.

One more thing, a little off topic. Through these contributions, a few people who share my interests have emailed me: to talk about the technology in projects we both contribute to, to compare our backgrounds, and to trade views that do not always agree. I have enjoyed every one of those conversations. None of them was planned, and maybe that was the point of contributing all along: the surprises you don’t see coming.

References

  1. TOKEN2049. TOKEN2049 Singapore returns as the largest industry gathering of the year. PR Newswire via AAP, 6 August 2026. aap.com.au.
  2. My list of projects I have contributed to. github.com.
  3. solana-program-option: a C representation of Rust’s Option, used across the FFI boundary for Solana program interfaces. docs.rs.
  4. anza-xyz/solana-sdk #1064. program-option: Fix infinite recursion in COption::clone_from. Merged 3 November 2026. github.com.
  5. Solidity documentation. Contract ABI specification: events. docs.soliditylang.org.
  6. wevm/viem #5238. fix: hash indexed string args as UTF-8 in encodeEventTopics and parseEventLogs. Merged 19 October 2026. github.com.
  7. Quantum Metal (formerly Qiskit Metal). Python framework for designing and analyzing superconducting quantum chips. github.com.
  8. qiskit-community/qiskit-metal #1244. qlibrary: ResonatorCoilRect draws a spiral of the requested length. Merged 25 October 2026. github.com.
  9. GitHub Docs. Approving workflow runs from forks. docs.github.com.
  10. solana-playground/solana-playground #483. Fix PDA seed refs not matching camelCase account and argument names. Closed 23 October 2026. github.com.

More writing →