Sapio: Stateful Smart Contracts for Bitcoin with OP_CTV
Speakers: Jeremy Rubin
Date: July 11, 2020
Transcript By: Michael Folkson
Tags: Op checktemplateverify
Category: Meetup
Media: https://www.youtube.com/watch?v=4vDuttlImPc
Slides: https://docs.google.com/presentation/d/1X4AGNXJ5yCeHRrf5sa9DarWfDyEkm6fFUlrcIRQtUw4/
utxos.org website: https://utxos.org/
Intro (Udi Wertheimer)
Today we are joined by Jeremy Rubin who is a Bitcoin Core contributor and the co-founder of the MIT Bitcoin Project. He is involved in a tonne of other cool stuff. He is also championing BIP 119 which is OP_CHECKTEMPLATEVERIFY. He is going to tell us about that and how it allows for new types of smart contracts.
Intro
Hey. Thanks for coming on your Saturday morning, I appreciate everyone making it out. Today I am going to give you your first class on Sapio programming 101, how to build stateful smart contracts for Bitcoin with OP_CHECKTEMPLATEVERIFY. Buckle up because there is going to be a lot to go through.
Who what where why
As Udi mentioned I am a Bitcoin researcher and developer. I came from MIT maybe five years ago. I started the Digital Currency Initiative and have been working as a Core contributor for the last number of years now. I am working on a new organization called Judica which is an organization devoted to Bitcoin research and development. The first project that I am trying to release out of that organization is Sapio which is a new paradigm for Bitcoin smart contracts. We are here in VR which is cool. I have never done a VR talk before so we’ll see how it goes. Why are we doing this? I think that we need a lot of new things so that when we say Bitcoin fixes this it actually means what we think it means. That’s the hopeful motive here.
Background
Let’s do a little bit of basic background before we get into the main part of the talk. Who here knows about CHECKTEMPLATEVERIFY at all or is it a new concept for you? If you haven’t heard about it CHECKTEMPLATEVERIFY is a simple covenanting system for Bitcoin. What does that mean in practice? It means CHECKTEMPLATEVERIFY allows you to do some more advanced kinds of smart contracting.
BIP-119 CheckTemplateVerify Summary
The specifics, this is a new opcode inside of the Bitcoin scripting language that allows you to specify an exact set of transactions that can spend a coin at the time that coin is created. These scripts can recursively commit to what the next transaction is so you could have a script that says “Go from coin A to coin B and then from coin B to coin C and coin C to coin D” and you could have an entire flow of a number of transaction steps that a coin is going to participate in. There are a lot of use cases for this. It enables a lot of functionality. You can do things like congestion control, there is smart contracting that I will talk about today and there is a lot more that you can do. In this talk we are not all that focused on all of these use cases, we are more focused on Sapio which is a smart contracting language based on CTV. We will go into the specifics of how you might use this in practice rather than everything that might be possible.
What if no CTV?
If you are going “This is a new BIP so this stuff is useless we have changes to Bitcoin” what I would point out for the more technically minded folks is that you could make a CTV emulation oracle that would give you a lot of the same functionality as CTV but with a different trust model. You would either have to have some multisig federation servers that you trusted or trust yourself to delete a key but you can do something very similar to CTV without adding any new features to Bitcoin. This language and way of thinking is general to either CTV or some trusted emulation service where maybe you are one of the participants in that federation. You can think about these designs more abstractly and think of CTV as a way of making this much more accessible and usable by anyone.
This Talk is All About Concrete Examples
This talk in particular is going be completely about concrete examples. I don’t want to lay out some really big abstract design and tell you all the features of the language. Instead I want to work through an example so you can see end-to-end how you might use this in practice.
My Goals
The goals are to get you excited to use Sapio, to get feedback on how you might use it, “I want to do this but it looks like this might not work” or “I want to do this and it looks great for that” and to teach you the very basics so that if you wanted to start playing around with it when it is fully open source and available then you’ll be able to know what you are doing a little bit.
Non Goals
Non goals, I am not trying to cover everything exciting. This is a 101 class. We could go for hours and hours on this stuff. Just treat this as an introduction and at some point later we could do a deep dive.
Liquid: A Contract Parable
In this talk we are going to use Liquid, Blockstream’s product, because in comparison to what else is deployed in Bitcoin it is a sophisticated smart contract. People are generally familiar with it and it is something that highlights a lot of the strengths of both CTV and the Sapio language. We are going to use this as our main example and explore this for the rest of the talk.
Federation Managed Funds Script
11 <watchman keys> 15 CHECKMULTISIG NOTIF 4032 CSV <backup keys> CHECKMULTISIG ENDIF
If you are not familiar with Liquid this is essentially Blockstream’s sidechain where they have an alternate universe of UTXOs where some group of people run servers to allow you to shuttle coins back and forth between Bitcoin and Liquid. The contract that we are focusing on is a mechanic for shuttling the coins back and forth and how those coins are managed. Right now the federation managed funds live inside of this script. If you don’t read Bitcoin script all this is saying is that you have 11 out of 15 of these watchmen who are doing some sort of multisig. They are allowed to move the coins however they want. The idea is you need 11 of them people to be dishonest in order for the funds to get stolen. You need 5 people to be dishonest in order for the funds to get frozen. What happens if the funds get frozen? Then you have another case which says “Or we can wait four weeks worth of blocks and then we have some backup keys that we are going to do a multisig with.” In Liquid’s case you have this 11-of-15 and then Blockstream has a 2-of-3 that is managed by the most important employees. It is not public who manages it but it is people who are maybe well respected and you would trust to make good security decisions. Those are the basics for how Liquid works, the functionary system. But this is low level. We are looking at this contract which is in this Forth like language which is hard to read.
Federation Managed Funds Miniscript
or_c(multi(11, <15 watchman keys>), and_v(multi(2, <3 backup keys>), older(4032)))
Blockstream and other people in the community came up with thing called Miniscript. What Miniscript does is it allows you to lift this stuff into a higher order language that is maybe a little easier to read. Now we can see the same structure where it is multisig of these watchmen keys, 11-of-15 or a multisig and a timeout with 2-of-3 of these keys. There is some funky business going on with these or_c
and and_v
. You need to know specifically what output you are looking for when you are using a Miniscript. It is designed to have a one-to-one mapping between this description and this script and back and forth. If you have the script you can generate this and if you have this you can generate that.
Federation Managed Funds Policy
or(thresh(11, <15 watchman keys>), and(thresh(2, <3 backup keys>), older(4032)))
There is another language that is called Policy which sits at a level above that. It says “Let’s think about the abstract idea of ORing two things together and ANDing things. You can describe the same sort of thing without worrying about the internal details of how it is represented. Policy compiles to Miniscript which then is encoded into bare Bitcoin Script. This right now is the state of the art for how you would write a Bitcoin smart contract.
Federation Managed Funds Sapio
What I am introducing with Sapio is a new layer on top of this stack. This layer gives you a Python interface into being able to write a smart contract. What you can do is you can declare this Liquid federation as a contract. You can give it a number of fields. It has a set of keys and a threshold for all of them, a set of backup keys and a threshold for the backup and a total amount of coins that are being sent to it. Then you can write out the different pathways. There is an unlocking condition which is the federation spend which requires 11-of-15 to sign. Then you have a backup case which is a backup threshold amount, backup keys and you have to wait for four weeks. The idea is that this is even easier to understand and reason about and build tooling around than Policy was.
Sapio -> Policy -> Miniscript -> Script
What we can do to make this concrete is we can look at this compilation pipeline. We start with the Sapio that I just showed you, then we go to Policy, then we go to Miniscript and then we go to Script. What we have here is the Sapio gets compiled to a Policy which is what we looked at before. I have highlighted in different colors what are the federation spend and the backup recovery parts. You can see what corresponds to what. Then we have Miniscript which again looks familiar and we have the Script. The Script is the same as what we looked at before but now it is coming from this Sapio language. Essentially it is a new front end
Recap
You can write scripts in Bitcoin, that is hard to do, Miniscript and Policy make that easier. Then Sapio adds another layer on top of that.
Recent Liquid Bug
Recently there was, let’s call it a bug in how Liquid works. We have this contract that we wrote out in Sapio and the idea is these are representing blocks and so you put that contract, you open it inside of this block. A number of blocks go by and this 4 week condition has now been triggered. That means that after this coin has just sat for 4032 blocks, now the backup federation can move the funds. This wasn’t supposed to ever happen, the funds were supposed to be moved automatically before the four weeks but that didn’t happen. People are arguing about the severity of this becuase ultimately is Blockstream an untrustworthy party? Probably not but it was outside the model that people were expecting of Liquid where Blockstream would never have control of the funds. This happened repeatedly and often. What does Sapio and CTV do about this?
CTV to the Rescue
So what we can do is we can take our contract, the same contract as before, and we can add a new contract around it. This is a big slide so we are going to take some time here to read through what is going on. We have this new contract which is a federated peg in. It has the same fields but now we have a few different cases. We have this normal case, this should be called federation spend which is the threshold of all the keys and then it is the same as what we had before. Then we have two new things. We have a requirement, This requirement is not actually enforced, just like a declaration of a variable. It is saying “Here is a requirement and it is called backup_start
.” This is when we have all the keys for starting the backup set in required. Here is where the new magic comes in with CTV. We have this new decorator which is guarantee
. When we say something is unlock
that means that whoever has satisfied this condition can spend. When we say guarantee
it means whatever transaction is returned from this functional block has to be the next transaction. This is using CHECKTEMPLATEVERIFY to guarantee that this transaction template is the next step. What this is reading as is “When the backup providers agree that that the backup should start they do a transaction which moves the funds into this backup operator.” So the contract gets opened up here which is the same one that we had before. How does this fix that bug?
Backup Operator (Looks Familiar)
The backup operator looks familiar as we said. It is the same thing that we saw before basically, the same Policy and Script output.
FederatedPegIn
The FederatedPegIn which was that new contract that we opened up here looks a little bit different. The new component that we have is instead of saying there is a timeout we are saying there is a transaction template that we have to go through. That substitutes out where we used to have a timeout, we are now checking that the next transaction matches an exact template.
How does this fix it? We have a diagram of how the coins are moving. Circles represent coins, squares represent transactions. We move the funds in from somewhere into our Peg In UTXO. We have the funds in our Peg In, If we have 11 out of 15 we can move the funds into some Peg Out transaction. If we have a 2 out of 3 then we can start this Backup process. Once we start this Backup process we can either go 11-of-15 to Peg Out again.The funds at all times remain within the purview of the federation’s main parties. But then if the Backup operators have claimed that the federation is dead then they need another 2-of-3 signature and four weeks to get to this Backup UTXO. Essentially what we are guaranteeing is that as long as the funds stay here within this Peg In we will always have at least four weeks of time in order to respond to a claim that the federation is dead. That means that these coins, once they are in the federation, don’t need to constantly rollover, they are safe staying put just where they were. One thing you might say is what if we Twant the funds, once we’ve gone into this Peg Out to go back into the Peg In? What you would be saying is “It is not enough that the funds that goes into a transaction that pegs out we want to know what to do with them after we have taken this step.”
Sapio has your back here again. Essentially what we have here is the same contracts that I showed you before but we’ve added a block of code here and a block of code here. It turns out that that is the same block of code on the contracts that we had before, all we have done is change this federation spend path to something that looks a little bit different. What is different here is it has been wrapped up here with a new wrapper that is not just unlock, it is called unlock but suggest. What that means is this is on lock so this transaction that we are returning out of this template is not guaranteed. But if you pass arguments into the function it will tell you what you are supposed to do. The recommended next transaction for the federation operator is to take out the appropriate amount of funds for the users who have requested a withdrawal and then put the rest back into the federation. This allows you to define a stateful contract where once the federation operators have made an action their default next step is pre-defined within the scope of the contract. It is known that the federation operators should take the relevant amount of funds out and then put them back into another instance of the contract. It is telling the operators what they should do but not preventing them from doing something bad if they wanted to.
D.R.Y. a little harder
This is where the talk becomes about not about Liquid. If you are having trouble understanding the Liquid related stuff that is just general Bitcoin contracting. At this point we are focusing more on how Sapio works and what the language lets you do and why it is so powerful. What we are going to do is dry up our code. As I said before it was a really big block of code and it was too hard to read. Now we are going to dry it up, we are going tout the functionality in one place and then we are going to turn it into something really compact and readable. This showcases how powerful Sapio is and what people are going to be able to do once this becomes a more mature platform.
The first thing we are going to do is take out these two common bits of code and we are going to move them to a Helper function. Now instead of having those blocks of code replicated in both places, it is now in just one spot. That’s a bit better. This is now less lines of code, hopefully it is a little easier to read on the slide but it is still too much code. The next step is we are going to combine these two classes that we had and this is why we are calling these stateful contracts, we are going to combine these two classes into a single class factory. A class factory is a function that omits instances of a contract and does some additional compilation. What we are doing here is we are taking both the backup step and the main introductory step and we are putting this inside of a single class. Then we are adding conditional compilation which you can see down at the bottom there that says “Depending on which state we are in add one function of the other function.” Now we are going to zoom in and you can see a much cleaner representation. We’ll zoom in on the interesting part. What we have done is we’ve said that if this state is normal then we are going to have a regular backup step, that is the first step in our process where we said the 2-of-3 backup operators claim that the federation is busted. Then if we are in a state of recovery what we are going to do is allow the finishing of the backup that required the four weeks to be waited for. Require that there is appropriate time for the federation to respond and say “No wait a minute. We are still alive and this is an attempt from Blockstream to steal the money.” What this showcases is that Sapio is a generally pretty powerful and flexible language for defining Bitcoin smart contracts and actually getting a compiled output that matches what you want. CTV adds a layer that enables a guaranteed step which helps fix sequencing and timing issues in smart contracts that you might write.
What else can we do?
What else can we do? What if we really want to go bananas? How far can we take this concept, what types of contracts can we make? The next one I am going to tell you about is TIC TAC TOE.
This is the code, it is pretty easy to read. What this does is enable a game state for Tic Tac Toe. We have some state machine and it transfers inside the contract and it is going to be completely secure and allow you to play Tic Tac Toe with anybody on the blockchain… cancelled. You can do that in Sapio, it is possible but in the scope of this talk I am just showing that as an example. You can do a lot but it is way too complicated. It is a little difficult to explain and I am not sure why anybody would want to play Tic Tac Toe on Bitcoin. The purpose of that is showing that this language is really powerful, flexible and we are going to be able to do a lot. No Tic Tac Toe for now, what else could we look at doing that is more concrete that people might want to do right now.
There are options contracts, CoinJoins, wallet vaults, fundraisers.You can do stuff on the Lightning Network, there are games, payment pools, you can do wills, escrows, blind merged mined chains, congestion control, subscriptions and more. There are tonnes and tonnes of applications you can build with the combination of CTV and Sapio. For this talk there is so much to do and so little time. I would really like to be able to present all of these to you and maybe at some point in the future we will be able to go for an entire hour on each of those applications but I think instead it is better to just go deep on how the framework works so that you can start thinking about how you might solve real problems with it rather than high level fly by on a bunch of different topics. We are going to continue looking at Liquid and we are going to start by furthering our journey into Sapio by thinking about fees.
Boring is the new exciting: Fees
The most boring thing but everybody has to deal with it, let’s look at how fees get handled in a CHECKTEMPLATEVERIFY Sapio contract.
Estimation
The best way to handle fees is to properly estimate them so when you make a contract guess how much fees you’ll need in the future and that is how much you should include. The problem is if you have a contract, this is an issue that Lightning Network and other multistep contracts face, you have to guess the right amount of fees by the time the contract actually goes out. If you have a contract that says this thing can only happen four weeks from now and it only happens four weeks from when a claim is made that a federation is dead it might be two years later by the time you are actually running this transaction. Estimating the fees is probably not an appropriate solution for long lived contracts.
Simple Contract
If you look at a simple contract like this, this is a short basic example. We have a FeeExample, all it does is give a guarantee that the next transaction moves 1 Bitcoin to a PayToSegWitAddress. We have some CTV UTXO and then it has a transaction it participates in. That moves the funds to some 1 Bitcoin location.
Simple Contract: CPFP
If you wanted to pay fees from this the right answer is to use child-pays-for-parent (CPFP). What you do is when you have this SegWIt address, when you want to use it you have to do a new transaction. If you want to use a coin you have to do a transaction, then you pay some fees out of that one. That goes and subsidizes up the tree and covers the whole amount with fees. Then the mempool will be able to recognize it and accept it as one high value package. That is the basic way fees are handled right now. You can use this wherever you want. When you go to use this what it looks like is you would add some other output to this transaction, maybe for 2 Bitcoin and you have a total amount of 3 Bitcoin. This extra amount gets burned. You have a way of adding fees dynamically. You can pick whatever output you want. This will help you do this transaction.
Simple Contract: Gas/Anchor Output
Another concept which is popular in the Lightning Network is this notion of anchor outputs, I have been calling them gas outputs. There may be some different terminology that needs to be unified. The idea is that you have your main contract which is paying somebody 1 Bitcoin. Then you add another output which is paying zero Bitcoin or a trivial fee amount. You create both. The incentive for doing this rather than just using child-pays-for-payment off of the main UTXO is that you may want this main UTXO for something. You might say “This UTXO is some other contract, I can’t just spend indirectly from it. Instead I am going to create a UTXO I don’t care about that I can use outside the state of my contract that I care about to drive fees forward. Now instead of spending from this was 1 Bitcoin which maybe has a timelock by the way. Let’s say this 1 Bitcoin was timelocked for a year, if it is a relative timelock there is actually not necessarily a great way for you to move things forward from this CTV. If you have got to wait a year the mempool won’t recognize it. This zero BTC output is able to be immediately spent and doesn’t have the timelock to prevent it from happening. You do the same thing we did before but now there is an unperturbed 1 Bitcoin output that we are able to drive forward.
Simple Contract: Conditionalizing
What is cool in Sapio is you are able to conditionalize some of these things and use a yield inside Python. Now what this says is “We are going to guarantee that either one of these two things happens”. Maybe we have some unlocking conditions applied to this branch and we’ve got very similar transactions but now we are saying “Either give us the one that has the exact Bitcoin output that we are trying to create which is this one or give us the one with two outputs and you have one of them be devoted for fees.” This gives more flexibility in whether you want to create this “gas” output or not. That is one way of using Sapio to structurally declare how you are going to pay for fees. You can also this output trick at the input level. You can say in Sapio “There is going to be an additional input that comes in here and this is just going to be used for fees.” You can do the same conditionalizing trick where you say “We either want the form where there is some extra input or we want the form where there is no extra input.” There are a lot of different ways that you could try to solve fees. You could use them together in different ways. It can get a little confusing because no single method is the right answer, it depends on what you are building.
How to Pick a Fee Method
Here is a general list of how you might think of when different solutions are favorable or appropriate. If you have a contract that involves nodes with relative timelocks then you really need to have these anchor outputs all along the way because the relative timelocks will prevent it from getting included in the mempool ever so you need to have these. Or you could also just pay high enough fees. If it is a short lived contract and you think you are going to be able to drive it forward just pay the appropriate amount of fees and that will be good enough. If you need txid non-malleability, let’s say you are using this in the Lightning Network context you may prefer it in the unconditional form because it means you have to sign fewer things, there are less variants of the contract that you are working with. For unconditional outputs the outputs are non-malleable whereas inputs are possibly malleable. If you don’t care about malleability at all then the conditional gas/anchor inputs are relatively nice, it is a pretty straightforward API for adding funds to a transaction. My favorite is the gas/anchor outputs. I think generally this should be the way the software evolves, people should get support for this but it requires some work from the community to make this work really well because you have issues around transaction pinning that have currently been a focus for the Lightning Network community.
Composability
We are going to get back to fees in a little bit. This is some context for ideas of thinking how contracts might pay fees that pertains to CHECKTEMPLATEVERIFY or not CHECKTEMPLATEVERIFY but now what I think is cool with Sapio is we can talk about composability and how contracts can work together.
Sapio is a lot like React
Sapio as a language and as a framework, who here has used React? You can think of Sapio as being like React but for Bitcoin Script. I am going to show that to you by looking at another example and showing how this composes with what we worked on previously. You will get the idea that with Sapio you are building a component hierarchy where you can pass properties up and down the stack and you can determine functionality that way. It gives you a really nice composability way of defining how you want things to work.
This is a new contract, this is a return-to-sender. Return-to-sender is interesting. What you have is a number of fields, there is a receiving contract, a receiving signal, a refund contract, an amount and a timeout. We have two different ways of proceeding. Either we can process a refund and that refund happens after the timeout. That sends the funds back to the refund contract. Or if we get the receiving signal from somewhere depending on what our receiving signal is, then we can move the funds to complete the transfer to the receiving agent. It is basically like an acknowledged receipt. You send money to somebody, then they say “You sent it to the wrong place, we don’t want it”. If they don’t send the receiving signal you just take it back to the place you specified. It is a nice undo send functionality. It is not like a double spend because they have to explicitly claim the funds in order for the deposit to finish. You can’t steal the funds unless you let the timeout decay but you don’t credit the person’s account until you’ve actually finished that transaction. There is no double spend but it allows an undo send like functionality. Kind of like Gmail, you mess up and you get to pull the message back.
What does this look like diagrammatically? This looks like another one of these state diagrams that we had before. What we have is we start by putting the funds from somewhere into this refund UTXO. After a day the funds can move back to our refund UTXO with this zero value output to use for child-pays-for-parent. Whatever our contract is here below we don’t have to disturb it to drive this output. On the other hand we have a signal and if we receive this signal, which is some sort of arbitrary script condition, then we can move the funds to the receiver.
So let’s compose this. This is where things get really cool. Before we talked about the federated peg in, we had this Liquid federation peg in mechanism and we were saying “All it takes.” What happens if you send money to the federation and they said “That is not our federation. That is the wrong thing. This is a completely different contracting. You didn’t send it in the right way”? You generated this contract when you sent it to them but maybe you messed it up. Now you can wrap it inside of a return-to-sender. You take this return-to-sender contract and you pass into the receiver this federation peg in. For the receiver signal you require a threshold of everyone to agree that the fees that were appropriately deposited. Now you have a way of saying “The funds only complete the peg in if the federation actually recognizes it, they intentionally took the money into the federation.” If they didn’t intentionally take it they didn’t take it. This can create a better legal framework for transfers like this where if you send money to the federation and they say “We changed the thing on our website, you sent to the old one.” Then you would be like “How do I get my money back?”. They’d be like “We deleted the keys” and you’d be like “Don’t you legally have the right?”. But you didn’t acknowledge it before sending. With this framework you can permanently embed a layer where there is an ability to undo the transaction or move it forward so you don’t run into situations where maybe a stale federation permanently freezes funds. You have the ability to make sure the federation is live onchain before the funds actually move. This protects you against a whole new class of vulnerability. There is a lot of complexity going on but we can still do the same thing that we did before which is unroll it into a diagram.
Now you start to see the power of Sapio. Previously we had this arrow coming from nowhere for this peg in but now we can see that we want the arrow to be coming from an Undo Send. We didn’t have to write those as two integrated pieces of functionality, we wrote the Undo Send contract and generically we were able to plug in the federation code and then it works. That is pretty cool. I get super excited when I see this. Once you have transitioned to this state it operates the same as it did. It doesn’t know about this prior state. You’ll notice that I have added something here which wasn’t in the previous diagram. A little zero output. We have added into our contract definition, for showing you the fees, I am not going to show you the contract where we add the fees because we have shown that a few different times. We will talk about how this actually ends up working in practice now. Now we have got a sophisticated contract and we want to understand how fees get paid.
Here it is without any fee harnesses added to the federation. This is all we are adding, it is pretty simple. The state we want to get into to claim the federated funds into the federation is this state. We want to get rid of the return to sender functionality. How do we drive that forward generally? What you are able to do with these gas outputs is make a new fee transaction. This fee transaction exists outside of the contract state of our main contract. There is no dependency that any downward state has on this thing. What we do is we claim these anyone-can-spend outputs into this and then we add a new output that pays a fee and then we give ourselves some change. What this does is drives forward progress on this contract. In this case we are driving it forward, we are claiming both of these, where the 2-of-3 has claimed you deposited here. But the federation is evil so we want to claim all of the things to start the backup process immediately because this is a dead federation. Maybe it has been a day and you haven’t taken the money back so we are just going to try to do it for you. I don’t know exactly why you you would want to do this particular case because you have got to then wait for three weeks. Let’s say you wanted to just try the contract for this much. What is cool about this is this is atomic. What does this mean? We did this and let’s say it confirms. This has driven the contract forward to this point. Let’s say anybody else came in and did a different fee transaction. Now we have some other fee transaction here. But note that both of these transactions paying fee are claiming the same output. You have got the Harry Potter duel going on. Neither can live whilst the other survives. One of these has to be the actual end transaction that gets confirmed, it can’t be both. Let’s say this new one coming in pays a higher fee, this kills the other transaction. This other fee paying one gets killed, this one goes through and now this one is orphaned because one of its inputs is dead. This might seem like a bad thing, I just tried to pay fee, but if you think about it when you try to pay fee here you are overpaying. You are trying to pay for two different state transitions within the contract. Now it has been orphaned because somebody else paid for it. You only need to pay for one. So you can now reattach a new transaction onto here which just claims the individual state that you are interested in driving forward and then creates a new change. You get more money back. You can have this tree of gas outputs, you can optimally claim money in a multiparty context. Anybody can claim whatever state they are interested in and pay enough fee that they are going to be the best bidder. When you are trying to atomically claim all the actions you are interested in you don’t end up overpaying because they will evict your payment. There are ways of cooperating so that you can work together to pay but right now the mempool does not recognize all of that rational behavior. It doesn’t completely work with current mempool behavior. You not only have these contracts but you have a way of driving forward the execution by paying fees external to the actual logic of the contract you are interested in. That’s the critical idea. You have separated out the control logic from the value logic. Previously you had to update lots of logic internally to change the fees that you are paying. As any developer knows this is a nightmare.
Traits & Composability
Now we have finished that story on fees I wanted to show you the composability because it gives you a more interesting example to work with before we finish the fee conversation. Let’s talk about how software engineering will proceed in this space in order to develop high quality Sapio libraries.
Previously we had the return to sender contract receive an arbitrary contract. What if instead we say that it receives a contract protocol which has an abstract method which means that it has to be implemented by a subclass. If you implement this Signaling contract then you have to implement the functions that are listed. Let’s assume we have that. Now it says it is a Signaling contract, so it has some method called Signal. What we are able to do is replace where we previously had this field for Signal, now it is just replaced with calling the function Signal on that contract. Then what we do is we take our create_peg_in_contract
and we get rid of the idea of having a Signal. Now there is no signal in here, we just have a federated peg in contract. We added a little bit of code which is just a signal function to that federated peg in which is called Signal and that returns a threshold for 11-of-15 of the keys. Now ReturnToSender
automatically learns to talk to this functionality. You have some system of passing props up and down between contracts and generating functionality automatically and linking them together. This can be tremendously powerful. It is a lot like React. It is not as mature as React is used in industry widely but I think over time we are going to be able to build out a contract programming environment which has a lot of reusable components, a lot of software infrastructure and support for those components and how you integrate them into applications. Sapio is going to be that integrative layer where people are going to be able to hook in and use as a plugin for building smarter applications on Bitcoin.
Sapio Programming 102 Syllabus
The next thousand slides are missing from this presentation. Udi deleted them. There is way too much, Udi didn’t actually delete them, he is a nice guy. I didn’t want to put them here. There is so much we could go in depth on and I think this is already an overwhelming amount of stuff. If we had Sapio 102, the next things we could talk about would be the UX layer that I built. There is a UX that I am working on which gives you a bare bones development, debugging and usable thing if you want to start using these contracts. You can click a button and deploy stuff to the network and drive transactions forward. It is in progress. We would talk about more specific contracts. We only looked at federations. We only looked at Blockstream’s Liquid federation peg ins. We could look at secure wallet vaults, we could look at congestion control, we could look at all those things we talked about before. We could spend hours on a single contract. We are limited in time and I wanted to give you a deep dive on one thing. In the 102 class we will be able to do more. Talking about integrating Sapio into applications, what APIs do you get, what ABIs do you get? How do you interface with these components? How should that work? That is the next topic, advanced programming. You are able to embed a lot of safety principles and practices. There are ways that are still in development around making assertions around when fees can be made, timing transitions between two different subcomponents. There are a lot of safety analysis tools that I am working on adding and paradigms that I am adding. We could talk about the compiler architecture. Then managing contract state, it is related to integrating applications. How do you build this with watchtowers? Can you put stateful things inside of these contracts that manage updates and things? The answer is yes you can. This could be a way of making a Lightning implementation where each contract node is aware of the state it is supposed to managing internally. That is the next class. We are not going to talk about that today.
What’s Next for Sapio?
What we will talk about is what are the next steps, what am I trying to do? I need to improve the language and polish it for open sourcing. It is still pretty rough around edges. You would really need to understand in depth how the things work in order to get building right now. I am hoping that will change, I know it will change, it is just a matter of development effort. I want to develop out this library of high quality contract components so that somebody who is having their first experience with Sapio doesn’t have to write their own components. They can just stitch components together like lego blocks and get really sophisticated functionality. That is why it is React like and why it is powerful. With React you can just download React Bootstrap and you can plug things in together and it is really simple. You don’t have to build all the components yourself. Improving the developer ecosystem and tools is really important. CTV, I said earlier if we don’t get it it is not a big deal we can do something else. It actually is kind of a big deal. CTV makes all this stuff really possible and without it it is severely limited in what contexts you’d want to be able to use it. Especially with regards to non-interactivity. Getting CTV adopted is really instrumental to making this vision that I showed you actually work. I am looking for funding and grants, it is a completely open source and free project that anybody can use. I am working on so many parts of the stack to get it done. I could really use help. I am trying to build this organization Judica to bring people on to work on some of the problems that will be faced in bringing this functionality to Bitcoin. If you are a developer and you are like “How do I get started with this today?” you can tweet at me and ask for alpha access. I am rolling it out to a limited number of people who aren’t going to complain about things being broken and might submit pull requests to fix things. If you want that alpha access and interested in getting involved or if you are interested in getting paid to work on it you can DM me for more details and we can have that discussion on what skills are needed.
Q&A
Q - What are you working on now? What needs to be done to improve it more?
A - If you look at the things on the Sapio 102 slide these are things that are under active development. I could talk about the engineering trade-offs are. I have a lot of ideas and code written that is experimental. I don’t have anything crystallizing. A lot of work is getting everything end-to-end working. Right now for example I can omit a list of transactions and sometimes it will require a signature for a transaction but I don’t have the code to send that to your Ledger Nano for signing. I don’t have the code for pulling 100 keys from your Ledger Nano for writing a contract. There are a lot of components that just don’t quite exist. There is security auditing and making sure that everything does exactly what it is supposed to do. There is a lot of performance engineering too. It is written in Python. Replacing the functionality that I can with faster things. There is a reason it is written in Python, I don’t think it will change, you want this really powerful meta programming environment where you can stitch things together really nicely. I think it would be really hard to get that in another framework. Until the ecosystem is more mature I think it would be better not shifting the actual front end language for building these. Then there is analysis tools. There is a whole lot to do. There is also work that exists out of Sapio that is more CTV and Bitcoin related. I am working on rewriting the mempool completely. It is a long term project that is really important. The mempool is not the best mempool that we could have. It is provably impossible to have an optimal mempool so we know that we are never going to have something that is perfectly rational. The mempool we have right now, there are a lot of challenges for anyone doing smart contract development especially Lightning. Making that better is a really critical task that I am spending a lot of time on. I would like to be focused completely on Sapio but it turns out that I am one of a few people who deeply understand the mempool so I am working on that as well. Then there is other more general wallet integration that need to be done. There is a lot. Just getting CTV merged, I am doing a lot of work to convince people that this is a good thing. This is part of that work. “If you want this you have to push for getting CTV because we are not going to be able to do it unless we get that kind of functionality.”
Q - When do you think CTV will get merged?
A - Tomorrow actually (joke). If you ask every developer when you will get a very different answer. I think we will probably need to have a honest community discussion around ossification and how changes get staged and prioritized and accepted, what trade-offs we are willing to make in that process. There are a reasonable number of people who think that it is three years from now at least. I think that is very sad in that if it is three years from now it is really hard for me to make the case that this is important stuff to work on if it is not going to be usable until at least three years from now. Other people are like “Ship it and let’s see if we can get it in six months.” I fall more in that camp. I think that personally the default thing that happens with Bitcoin, people are worried about ossification in that maybe ossification kills Bitcoin, I think the default thing that happens in Bitcoin is it dies. Because I think that is the default, I think we need to go as fast as possible. Other people say “We want to make sure we are going in the right place so we don’t swim into the big fish and get eaten.” There are two different concerns around how Bitcoin might die. I fall more in the camp that Bitcoin is so far in its early stages and experimental that we need to pushing really quickly. Other people feel that Bitcoin is more ossified and needs to move really slowly. That is something that if you believe Taleb, there is this intolerant minority, people who want things to happen really slowly might be the intolerant minority that blocks progress. From my perspective that looks like an attack on Bitcoin. If we have such slow progress that we don’t deliver a lot of these tools to people Bitcoin in my opinion dies. I model Bitcoin should take ten years to do anything like this as death by committee. It is a difficult question, I don’t have an answer of when something specifically is going to happen. I would like to see it happen sooner than later. I think that we didn’t talk about vaults that much. The Liquid federation is kind of like a vault. Vaults I think are one of the most important use cases that CTV is going to bring to the table. What I really like about them is they bring an immense set of self sovereignty financial tools to a really wide audience. It is really cool that you could say “I have set up secure storage for my Bitcoin and it sends an allowance to my phone. If I want to get the funds moved off my phone I have to go through some backup process. I have no provider who is doing that for me, I am doing it myself.” Being fiscally self sovereign I think is the aspiration of Bitcoin as much as being scalable. Delivering tools like CTV sooner that allow us to achieve even moderately better results, if we have a longer term thing that is even better, I think we should do those things now and we should accelerate that work rather than wait ten years for the perfect design that solves this forever. That is going to be waiting for a fully zero knowledge EVM that runs in O(1) all the time. Maybe we will get that, maybe that happens at some point but I don’t think it is yet.
Q - With OP_CTV and BIP 119, can you summarize exactly what gets controlled. You create a UTXO and the idea is there is some control over the transaction that spends that UTXO. Could you explain exactly what can be controlled? You have already mentioned examples like it could be amount, the output, the input, what exactly can be controlled and what are the design decisions about what can and cannot be controlled in the spending transaction?
A - The way that CHECKTEMPLATEVERIFY works is you take the hash of everything that affects the txid except for which outputs specifically are being spent. That is all of your outputs, that is all of the scriptSigs but not the witness data. That is how many outputs there are, all of the sequences. What timelocks you have, your timelock, your version. You hash all that together and then you put that in the script. That is what gets played forward. Only if the transaction matches those concrete details is it allowed on the network. That is a little bit abstract, it is maybe easier to think of it in terms of this very small Python function up here. Given a transaction template you can get a key and once you get a key for it it is always going to be the same key. That is a hash, this is an oracle that is emulating CHECKTEMPLATEVERIFY. You have a key, then you can request that it signs a transaction. All you do is you say “Let’s check that we have already registered this transaction, we have already computed the hash, and check that the transaction template matches the exact transaction.” If that happens we have asserted this is true. Then just return the signed transaction. We are saying “Create a key that can only sign off on a specific transaction and then allow getting that signature.” That is the basics of what CTV is doing metaphorically. Concretely it is using a hash instead of this oracle. That breaks cyclical problems of you put the key in, the key is generated from the transaction, it is a random key and we are willing to sign only that specific transaction that was registered with us for that key. If you go to utxos.org the BIP is linked and you can see exactly what it is doing. There have previously been covenant proposals which you could describe with a similar emulator like this. Really it is just a very simple hash check. There is not that much sophisticated stuff that you can do. It is very similar to what already happens with the signature in terms of what gets hashed. It is just whether or not you can change what you signed after you create the UTXO. With this it is a signature that you commit to inside of the coin. I think you used to be able to do, CHECKTEMPLATEVERIFY in Bitcoin, possibly, but then we removed certain features that made it not possible. I would have to double check that. We were able to do delegation, I’m not sure if we were able to do CHECKTEMPLATEVERIFY. It is not terribly complicated. Other covenant proposals, you could do introspection, this is a simple “check the hash matches and if so proceed, if not it is not a valid spend.” If you have OP_CAT or other functionality then you get to do more sophisticated stuff but we don’t have those so not worth looking into. There is an upgrade path for CTV if we wanted to get more complicated functionality in. OP_CAT would allow you to do very sophisticated contracts.