The History and Future of Sapio
Day 26: Rubin's Bitcoin Advent CalendarTweet
Sapio began as little more than a slide in presentations I would give on what BIP-119 could be with the support of a programming environment.
While my conceptions of what could be built with CTV were about on-par with where they are today, the tools available were very clunky. You can see one of the original diagrams from the C++ Code below (code here).
/* * [ vault_to_vault n ] * |a |b * (0) (1) * /\ /\ * wait + maturity / \ / \ wait + step_period (attached) * [ hot_to_hot ] / [vault_to_cold] [vault_to_vault n - 1] * / | | * [hot_to_cold] (0) (1) * . . * . . * . * wait + step_period * n (attached) * [vault_to_vault 0] * | * (0) * */
When I presented it on February 1st, 2020 at the CTV workshop, one of the last Bitcoin events before the pandemic began1, I knew I had to present a more concrete vision on how smart contracts could be built, rather than spit-and-glue C++.
And so I included slide inspired by the hand rolled smart contracts I was making in C++ about how the technique could be generalized.
a slide at the feb. 2020 CTV workshop.
This is a research project I am interested in pursuing. We have a few scripting languages. We have Dan here who wrote Ivy. There’s also Balzac and Solidity. It’s poorly named, but it actually has some really interesting ideas that aren’t in other scripting languages for bitcoin. There’s some notion of participants with private state they are storing, and has some notion of interactivity. I also threw up there BlueSpec which is like a VHDL competitor that is pretty neat. If you think about it, there’s a software layer for controlling vaults but there’s also a hardware layer- so how can we describe transactional hardware? You wind up with similar controls as a BlueSpec-like language where you are creating plumbing and a description of how things are moving rather than something that has imperative state.
As an example, one of the properties with OP_CHECKTEMPLATEVERIFY that is cool is the narrow window of a standard OP_CHECKTEMPLATEVERIFY script is that you have this composability property where for a given model that goes to arbitrary address outputs, you can just throw another one inside it. As the outputs of that annuinity, you can put undo send as the outputs of that annunity, and you can tag on more and more programs into that if you want. On this slide is a templately description of a language, which helps if someone else given the same program description can verify that the hash is the same for the given inputs. Instead of sending you a million branches, you can generate them yourselves.
Q: Is there code for your metascript thing?
A: No. It’s just an idea I’ve been toying with. I got relatively close to metascript just writing in C++ just writing with C++ templates. Then I got ready to kill myself doing that because writing templates.
I’d discussed similar slides at earlier events, usually included it as an example of something someone else could build while I kept pluggin’ away working on Bitcoin Core. Eventually I realized that me claiming that CTV could be used to do these things and CTV demonstrably doing these things was an obstacle… I needed to make the prototype.
So I set off hacking together a prototype… I spent an afternoon or two mucking around in C++ only to realize that wasn’t going to happen, and then I switched to python. Python was a great choice, and after quite a bit of time pluggin away, I had something that actually worked.
There was a moment of magic where I connected it to the Sapio Studio (which actually existed long before Sapio as just a visualizer for a set of transactions) to load a contract written in python and… it worked. Really well. It felt incredible. I began talking more about what Sapio could do, thinking through some of the problems and solutions. I even gave a talk in the metaverse with Udi where I dropped my virtual laser pointer on the ground for a minute and couldn’t pick it back up.
there were more people sitting further back I swear…
At a certain point I decided to start working on cleaning up Sapio by using Python’s gradual typing and trying to convert to using Miniscript instead of my custom-made Sapio script fragment builder. I was neck deep in type refactors and then I had a deep realization:
Python FUCKING SUCKS
I was incredibly greatful for the rapid iterating that python allowed me, but I realized at this point that it was going to be nearly impossible to make Sapio actually good and not just a toy working in python. What had started as a proof of concept for someone to do “for real” had gotten good enough conceptually but was bursting at the seams and was not going to ever yield something production grade.
So I did a reset.
I started building Sapio in Rust, re-implementing (but much more cleanly) the paradigms that I had previously developed, relying on well tested and type rust-bitcoin libraries instead of janky test-framework python code from Bitcoin Core.
And one day – almost like Deja Vu – I plugged the Sapio Rust served in place of the Python one for the Sapio Studio and everything Just Worked™.
Since then, Sapio has only matured and gotten better and better with each passing month. I’ve added tons of new features, improved the underlying architecture, made the ABIs more well defined, built stronger intergrations with the GUI, and more. Today, Sapio is actually usable on mainnet (if you’re an expert at least), and I’ve used to do congestion control payments and art projects.
Sapio has helped me cut through the content for this Advent Calendar like a swiss army knife. It’s actually becoming a pretty decent tool!
Sapio needs to get to the next level. There are many major areas of work in the pipeline. You might think of this as “Sapio is so incomplete it’s not ready”. I think of it more as Sapio is just getting started:
Upgrade to Taproot
Support for Taproot in rust-bitcoin and rust-miniscript is coming! Once that lands, I need to rebase (and maybe upstream?) some Sapio features, and then update the compiler to always use Taproot outputs!
Improve Sapio CTV Emulators with Taproot (if ctv seems to be slow)
Once taproot lands, the multi-sig federated oracle designs can be set up to do a MuSig Schnorr signature instead of just a bare multi-sig, allowing wider federations.
This engineering work only really matters if CTV seems unlikely, but could be useful to have anyways for future purposes & extensions to Sapio.
Build out some “full featured” applications backed by Sapio
Right now Sapio works for making little Applets, but there is no “end to end” software (e.g., vaults) made in Sapio.
This requires work on both the Sapio Studio front and potentially on a website for things like Sapio NFTs.
This will push the boundaries on integrating Sapio into real applications.
One particular feature that would be great is ‘auto-signing’ on valid state transitions proposed at a certain continuation point. For example, if we have an NFT we want to dutch auction, we should be able to have a sapio module running that is happy to spit out the relevant transactions with a nice API.
More advanced programming of transactions
Currently the Sapio transaction builder from within Sapio branches is a bit limited in what it can express.
Augmenting it with the ability to more fully describe partially signed bitcoin
transactions (PSBTs), e.g., when used in the
continuation context would
advance the state of the art.
Relatedly, it would be really useful if you could tell Sapio how to access a signing module and have sapio use that external key to generate the appropriate signatures for the state transitions.
Better sapio-cli / server that can keep WASM modules loaded in memory, aiding performance
Right now every time a module is used the entire thing has to reload which is super slow.
It should be possible to have a single server instances that manages a cache of all modules, greatly boosting performance, especially for recursive cross-module calling contracts.
Client Side Verification Caching Across Module Boundaries
For things like NFTs that we saw, we have to always re-compile the entire history of the NFT to do state transitions. However, many of these state transitions are just doing the exact same thing every time, re-verifying from genesis. We should be able to cache the compilations at well defined boundaries.
Better formal analysis tools / type system on top of Sapio
Currently Sapio has the ability to define various interfaces for composing Sapio contracts cleanly.
But we don’t have a great way of proving what we want a contract to do v.s. what it does.
This work will start as being able to express more properties about a module in it’s “manifest”, and will culminate in being able to check the validity of compositions of contracts based on them.
If anyones looking to do a PhD thesis on Sapio, this is prolly it.
More Module Types
Right now all WASM modules are for generating a ‘Compiled’ contract from a JSON.
I would love to add defined module types to cover all the standard components like:
- Miniscript Fragments
- Then Functions
- Continuation Functions
- Transaction Template Generators
- Trait Verifiers
More Emulator Types
Sapio works today with CTV
then functions because the functionality can be
emulated by a federation of signers.
Figuring out how to cleanly extend the signing server paradigm to a number of different types of Covenant proposal (e.g. APO, TLUV, CAT) or other opcodes could add a lot of value for making Sapio the defacto platform and proving ground for upgrades to Bitcoin.
Unifying Then and Continuation
Then and Continuation really are the same thing conceptually, it would be
Standard Library of useful applications / Plugins
Title says it all. There should be more off the shelf things to use!
Wallet Stack for Sapio Contracts
The Sapio Studio is rapidly imporving as a system for engaging with Sapio contracts, but it’s lacking in the management and storage of all of a user’s contracts. We can, and will, do a better job with this.
This includes being able to make watchtower-like functionality for Sapio. It’s coming, but will likely require a lot of new features to the language spec to express if this then that monitoring conditions. And with features comes complexity.
You can see hints to this in the slide earlier, being able to react to e.g. confirmation or mempool events.
This also includes dramatic improvements needed to the GUI so that users can understand much more deeply what contracts are doing.
Right now Sapio is just DIY to build and run it yourself, but we really ought to work towards stable binary releases to quickstart users.
Visual Programming for Building Sapio Contracts
When composing together Sapio modules, I would really like for it to be kind of labview like interface for adding data or other modules, where you can “typecheck” that the wires (module names) are composing into slots they work. If that sounded like gibberish, I just mean that I want to be able to plug in a module hash for a NFT Sale contract into my NFT contract and have the UX give me real time feedback if I should be able to do that.
Sapio Package Manager / Deterministic Builds / Signers
As more modules become commonly used (e.g., like NFTs) we want to ensure all users can build an exact copy themselves (Deterministic Builds) or that they can find a build signed by a number of respected code signers (Signers). While we can use Cargo / crates.io for the package management of our actual rust code, we need something to distribute the sapio wasm blobs nicely!
Writing tests for Sapio contracts is hard as heck. We need some bold ideas on what sorts of properties would be useful to test for. Fortunately, a lot of properties we care about (like not wasting money) can be checked by the sapio library to be safe, but we still want to be able to ensure we never lose a users funds out of Sapio.
#### Getting CTV Locked in
If I get even a tenth of this completed 2022 will be a good year for Sapio.
But I plan to get it all done.
Perhaps with your support – if you’re an engineer or funder interested in helping propel this, please reach out!
p.s. safe holiday travels!
That honor I think goes to the MIT Bitcoin Expo. ↩