Episode 71: Timelocks
Ep. 71

Episode 71: Timelocks

•

Episode description

In this episode of Bitcoin, Explained, Aaron and Sjors discuss the different types of timelocks available on Bitcoin (and what can go wrong when used incorrectly).

Chapters

00:00:00 Listener boosts and Podcasting 2.0
00:01:55 What are Bitcoin timelocks?
00:03:56 nLockTime: from relay policy to consensus
00:06:41 Recovery and inheritance with presigned transactions
00:08:32 CheckLockTimeVerify: locking coins on-chain
00:13:37 CheckSequenceVerify and relative timelocks
00:18:26 Encoding time and block height
00:21:51 Why Lightning needs relative timelocks
00:24:31 The danger of mixing time and height constraints
00:28:51 nLockTime and fee sniping

Episode Sponsor: https://voltage.cloud/

Sjors New Book: Bitcoin: A Work In Progress

Follow us on Twitter:

https://twitter.com/bitcoinmagazine

https://twitter.com/videobitcoin

Transcript

Download transcript (.vtt)
0:20

Aaron van Wirdum Live from Utrecht, this is Bitcoin.

0:23

Sjors Provoost Explained.

0:24

Aaron van Wirdum Sjors, you want to start the episode off with some boosts. Is that right?

0:28

Sjors Provoost That's right. Well, yeah, we've only got a few.

0:32

Aaron van Wirdum Remind the listeners of the context here.

0:34

Sjors Provoost So boosts, if you're using a podcasting 2.0 application like Fountain and there's a couple of other ones, it can stream satoshis right to our Lightning node.

0:45

Aaron van Wirdum And people can make comments apparently.

0:47

Sjors Provoost Exactly you can also leave a comment and then you can attach satoshis to that comment and then there is a possibility that I'll read it.

0:54

Aaron van Wirdum Do you have to attach satoshis to to leave a comment or…

0:57

Sjors Provoost Yes but you can add like one satoshi.

0:59

Aaron van Wirdum And they and these satoshis go right into our pocket.

1:02

Sjors Provoost That's right

1:03

Aaron van Wirdum Well your pocket. I'm still waiting for the last paycheck so where's my money?

1:05

Sjors Provoost They go to my pocket, and then [unclear]… You need to run your own full-time node then it can stream directly to you.

1:14

Aaron van Wirdum All right let's hear the best pay is this the best paying boost you're gonna read?

1:19

Sjors Provoost Coincidentally yes. So this is the Makerman or Makerman I don't know. Hey guys love the podcast. Thank you been mostly listening to old episodes until now and saw your setup with podcasting 2.0 That's what we talk about. FYI, I could not find you in the Fountain search. If you're somehow having difficulty streaming sats, there is another alternative podcast link, but that URL is unpronounceable and very long. So if you find me on Twitter or something, I'll tell you what it is.

1:49

Aaron van Wirdum All right. Well, thank you, Makerman. How much did Makerman pay us?

1:53

Sjors Provoost 10,000 satoshi.

1:55

Aaron van Wirdum Nice. All right. Today, we're going to discuss time locks. This was actually a suggestion by a friend of the show, Ruben Somsen. As you are well aware, but probably our listeners as well at this point, we increasingly have to... Dig deeper and deeper to come up with subjects to discuss because we've almost explained all of Bitcoin at this point. We…

2:17

Sjors Provoost Have explained all of Bitcoin except for a few things that take too much research.

2:21

Aaron van Wirdum Yeah for which we would really like to have an expert on the actual podcast at some point but somehow we never had an episode on time locks yet so this was a pretty good suggestion I think.

2:32

Sjors Provoost I think so too.

2:33

Aaron van Wirdum So Sjors, we're going to discuss time locks. First of all, maybe as a very, you know, most of our listeners will know this, but let's just start with a very general, what is a time lock?

2:43

Sjors Provoost What is time? Oh, okay.

2:45

Aaron van Wirdum Yes, let's start there.

2:46

Sjors Provoost Yeah, a time lock means that, so normally when you make a transaction, you know, you create it in your wallet, you send it out to a bunch of other peers in the network, and then eventually a miner will put it into a block, basically as soon as possible. But maybe there's a reason why you don't want that to happen immediately. You can use a time lock to prevent a transaction from being mined now, and it has to be mined after a certain date or a certain block height.

3:14

Aaron van Wirdum Yeah, I guess the even shorter summary I would give, but maybe it's a little inaccurate if I make it this short, but we'll get into that a little later. But I would just say it's a way of locking bitcoins into the blockchain in a way that they cannot be spent yet, but they can be spent later.

3:29

Sjors Provoost Well, that's not always true because you can also do it in a way that is not yet in the blockchain itself. So you can make a transaction that cannot be put into the blockchain at all.

3:39

Aaron van Wirdum Right okay so I think that's the type of stuff we're going to get into exactly this episode so anyways, that's a general idea somehow you want to prevent bitcoins from being spent right now but they should be able to be spent later right that's the one sentence summary then I guess. Okay so has this always been an option in Bitcoin Sjors?

3:59

Sjors Provoost No the very old version of Bitcoin did have a field that would suggest that but it didn't actually do it.

4:06

Aaron van Wirdum Just one step back maybe we… Is it better to... Are there some examples of why you would want to do this? Or should we mention these throughout the episode as well?

4:16

Sjors Provoost We can probably try to explain them as we come up with it.

4:19

Aaron van Wirdum Okay, so... In that case, I interrupted you at a very bad time because you were given a great explanation of the history of time locks to start off with. And you said it wasn't always possible.

4:32

Sjors Provoost No, it wasn't enforced. So in the original version of Bitcoin, what you could do is tell a transaction. You could tell a transaction that you didn't want it to be mined before a certain block, but this was a policy thing. So your peers might not relay it, but if it was in a block, you would still accept it. So in other words, you couldn't trust it for security purposes.

4:50

Aaron van Wirdum Okay first question you say you can put it in a transaction like where is it how does it what does this actually look like in this case?

4:58

Sjors Provoost Yeah so this early mechanism is called nLockTime so that is a transaction in a field all the way at the end of a transaction.

5:05

Aaron van Wirdum Okay so you actually attach it? It's part of the actual transaction.

5:08

Sjors Provoost Yeah it's part of the transaction hash as well and…

5:10

Aaron van Wirdum In the very early days as you said if you put that in the transaction that would mean that Bitcoin nodes will not… If they receive the transaction over the peer-to-peer network...

5:20

Sjors Provoost They'll ignore it.

5:21

Aaron van Wirdum They will ignore it. And miners…

5:22

Sjors Provoost But if it's in a block, they'll be fine.

5:23

Aaron van Wirdum Right. So if some other miner somehow mines it, they'll still accept the block. So it wasn't a consensus rule. It was a peer-to-peer network rule, essentially.

5:33

Sjors Provoost Yeah.

5:34

Aaron van Wirdum It was a mempool policy, as you mentioned.

5:36

Sjors Provoost A policy rule. Right, yeah.

5:37

Aaron van Wirdum Okay, so this was... At the very beginning, it was there, but not as a consensus rule.

5:42

Sjors Provoost Yeah. And then I think fairly quickly, but I forgot to check when exactly, maybe 2012 or earlier, this was turned into a consensus rule.

5:50

Aaron van Wirdum It was in the first year, I'm pretty sure.

5:52

Sjors Provoost Yeah.

5:52

Aaron van Wirdum Because I did check it. So unless my memory again is even worse than I think, I think this was... In the first or maybe the second year was made into an actual consensus rule.

6:02

Sjors Provoost Well, and it was also improved. So the initial version, I believe, was only height. So you could only say, don't mine this before block height number 300, whatever. But this was improved to also allow you to specify a time. So you could say, well, don't mine this before the year 2020, because maybe blocks come in faster or slower. So you can choose.

6:23

Aaron van Wirdum Right. Okay. So, year one let's say roughly it was there as a policy rule and then after from my memory about a year it was implemented as a consensus rule and that was nLockTime so that was one way of doing… okay so maybe here is a good point to ask why would anyone want to use this? Are there any practical examples of why someone would want to put this on their own transaction?

6:51

Sjors Provoost I guess you could use it as some sort of dead man's switch. So maybe you create a wallet and you're not sure that you're going to hold on to the private keys very well. And you have a backup wallet somewhere else where you do think you'll hold on to the private keys very well. Now what you can do is you can make a transaction that goes from this your new wallet that you're not sure about back to your old wallet and you put a time lock in at 10 years in the future. And then maybe if you lose your keys, you can still take that transaction that you signed when you did have the keys and broadcast it then to get your money back to the safe space. So it's kind of like a dead-man’s switch because that transaction will, if you broadcast it, it eventually will happen. But if you just spend the coin somewhere else, then it won't happen.

7:38

Aaron van Wirdum Just to be clear, so who's putting the time lock there in this? You are. So the creator of the transaction, that's the person that's putting the time lock there, right?

7:48

Sjors Provoost Yes.

7:49

Aaron van Wirdum Not the recipient. No. Because usually your recipient gives an address and the address contains all kinds…

7:55

Sjors Provoost In this case, in this example we did, you are the recipient. But in any case, you're giving the recipient. Or maybe it's an inheritance thing, right? So you give a transaction to your children that you say, well, if you broadcast this thing you'll get my coins, but not before this year. And also not if I decide to move the coins in the meantime, because then that transaction will be unusable.

8:13

Aaron van Wirdum Right. Well, that's kind of a clear example, I guess. Yeah. So you would give the actual transaction itself to you. So you're not sending them coins.

8:21

Sjors Provoost You can give it to them very early because you're not giving them any private keys. You're just giving them these transactions. Well, if nothing else happens, these coins will be yours, assuming that the transaction goes to them. But I can change my mind.

8:32

Aaron van Wirdum Right, okay. So this was essentially the first version of a time lock on Bitcoin. Now, I think from there on, the next step essentially was to actually enforce it on the blockchain, right? Am I saying that right?

8:48

Sjors Provoost Yeah, that's what we talked about now as well. Well, so the difference is here you have a transaction that is not yet in the blockchain and you're preventing that transaction from being included. But the next thing that would happen is that a transaction would be in the blockchain, but your ability to spend it would be limited. So basically, you're constraining the output of a transaction. You're not constraining the whole transaction. You're just saying, well, this output is here on the blockchain, but you can't spend it until the year 2100.

9:14

Aaron van Wirdum Right. So in the previous example, when you want to give something to your kids with nLockTime, you had to give them the actual transaction, which they would have to broadcast themselves later. And now we're moving to a situation or I mean

9:27

Sjors Provoost Yeah now we're moving to a situation where you're sending them the coins on the blockchain but you're saying you know here they are but you can't spend them until the year 2100 but they are yours, like I can't take them back anymore.

9:37

Aaron van Wirdum Okay so what is this?

9:38

Sjors Provoost So this uses a mechanism called CheckLockTimeVerify. And what this really does under the hood is it says the output of the transaction is a script, right? Or a hash of a script. And the script says, like, the only transaction that can spend me is a transaction that has a high nLockTime. So the enforcement happens by saying, in order to spend it, you have to put in a very high nLockTime. And because the blockchain will make sure that the transaction with a high nLockTime is not included before the year 2100, this works. It's kind of a weird delegation of responsibility.

10:13

Aaron van Wirdum Right, so this is CheckLockTimeVerify. This was implemented in Bitcoin in 2015 through a soft fork. It's essentially, as you're explaining, it's still using nLockTime. It's still using what we discussed before, but now there's an extra step as a soft fork that actually requires... The next transaction when you want to spend the coins, it requires that transaction to have nLockTime. Am I saying this right?

10:41

Sjors Provoost That's correct. Because usually when you're spending a transaction, the output script determines how it can be spent. Right but it only determines what the input should be because normally in the input you would put a signature or something like that but now it's saying it's not just the input that has to be a certain way the transaction itself has to have certain rules too.

11:00

Aaron van Wirdum Yeah so I guess so one of the things this changes I just mentioned with nLockTime alone the person that adds the lock time is the sender of the transaction and now it's embedded also like the recipient has to first decides that it has to be locked right?

11:19

Sjors Provoost Like yeah if you're trying to receive coins if you want to receive coins from somebody you have to give them the script that it goes through. So you're really constraining yourself in a way when you're doing this but in the inheritance scenario you would tell your kids like you know give me an address that has this script in it and your own public because otherwise of course you wouldn't do this and of course there are more complicated setups like Lightning things etc where you would want to use constructions like this.

11:46

Aaron van Wirdum So you mentioned Lightning, but I don't think that's actually correct. Lightning doesn't use this. Lightning uses another time lock, which we're going to discuss next. But what are some examples for this CLTV type of time lock? Why would anyone want to use this? So we've discussed the inheritance example, which I think is valid. And are there other examples you can think of?

12:10

Sjors Provoost I don't know.

12:11

Aaron van Wirdum You yeah well there's this thing called fidelity bonds so that would be one example if you somehow want to prove that you're not a spammer of some kind then you have to actually lock up bitcoins and prove that you've done so.

12:23

Sjors Provoost Yeah it's a way to publicly prove that you are locking up coins.

12:26

Aaron van Wirdum That's true yeah so that's one example and I think another one is what's that called when you want to trustlessly exchange coins right you want to have some sort of trustless exchange.

12:36

Sjors Provoost But then relative locks are probably better too. So we'll get to that.

12:42

Aaron van Wirdum Yeah, well, so this one was rolled out first. And I definitely think this is one of the motivations at least end up at that point. What's this called?

12:50

Sjors Provoost Atomic swaps.

12:51

Aaron van Wirdum Atomic swaps. Thank you. That's what I was thinking of. Yeah.

12:53

Sjors Provoost I mean, it's a bit risky because you're composing the transactions at a certain time, but you don't know when they're actually going to be put on the chain. So if you use an absolute date, you have to be careful with that sort of stuff.

13:02

Aaron van Wirdum Right. Well, the idea with atomic swaps is that you basically publish a contract on the blockchain I'm gonna say that's right and then the other person can claim the coins if they fulfill if they send coins back on another…

13:17

Sjors Provoost Yeah I guess in that case it's up to you how long you want to how long you want that contract to be open.

13:21

Aaron van Wirdum Well the point is if the other person doesn't do that so that's where the time lock comes in and after a while you can claim the coins back so that's why there needs to be a time lock in these kinds of smart contracts so yeah time locks are very useful in many types of smart contracts. Probably their main use case right? Then so we come to Lightning and CheckSequenceVerify.

13:43

Sjors Provoost Yeah well actually yeah I mean Lightning also required SegWit to really work but this is one of the first goals that was taken to help with Lightning.

13:50

Aaron van Wirdum Okay so what's the difference between CheckLockTimeVerify and CheckSequenceVerify?

13:57

Sjors Provoost So CheckLockTime, I mean, in terms of how you use it, the usage basically just means that you can do relative times. So you can say not at block 500,000, but you can say 10 blocks from now or 10 hours from now. That's basically the utility. And the way it's implemented is by something called nSequence. Or it's implemented as a two-step process. First, there was a BIP 68, which introduced nSequence. And nSequence is something you put on the input of a transaction. And it's similar to the nLockTime, which has a similar mechanic. So it's basically saying this input of this transaction can only be spent after five blocks. And that is five blocks after the output that it's spending. So an input always spends an output, and by setting an nSequence field on this input, you are saying this input can only spend an output that is at least 10 blocks old. And by itself, that's not very useful because you're just constraining yourself. But the code, the opcode, CheckSequenceVerify, in a similar way to what we discussed before, can say, well... You can only spend this output if you provide an input that has a certain nSequence in it.

15:11

Aaron van Wirdum What is an nSequence?

15:13

Sjors Provoost It's just a number. It's a number that is put in the transaction input. Just like the nLockTime is a number that you put on a transaction as a whole. And it's interpreted as either a time or a height. But like a relative time or a relative height. So seconds or...

15:32

Aaron van Wirdum Right. So if I understand you correctly, nSequence was always in the Bitcoin protocol, but it was just a number that didn't actually mean anything?

15:40

Sjors Provoost Yeah, exactly. It was meaningless. And so probably zero in most cases. And it was given a meaning in a soft fork. And the meaning is like you cannot put this input in a block. So the transaction as a whole, you can't put it in a block until this many blocks have gone by or this many seconds have gone by.

16:00

Aaron van Wirdum Right. So this number that was always there is now interpreted by Bitcoin nodes to actually mean this is a time.

16:07

Sjors Provoost Yes.

16:08

Aaron van Wirdum Right. Okay. And then they will check if the time complies with the actual time in their computer clock to determine if enough time is passed.

16:16

Sjors Provoost Not the computer clock, the time in the blocks. So to be accurate, the median time past. So take the timestamp that is in the last 11 blocks and you take the middle one.

16:28

Aaron van Wirdum Well, if you're a miner, then you have to actually use your computer clock to determine if you include it in a block, I would assume, right?

16:35

Sjors Provoost No, you can know this in advance because the way you do it is you look at the last block that you've received and then you do this calculation with the 11 most recent blocks and then you know what you can put in the mempool and what you can put in the mempool is what you can put in the block. So you don't have to look at your computer time. You look at your computer time in order to produce a block. But the miner that is making the block that's actually enforcing this rule doesn't have to worry about his computer time, only has to worry about what the last block is that he's working with.

17:03

Aaron van Wirdum Oh, well, that's an interesting detail. So it's not actually checking for the time, it's checking for the time based on blocks that have come before it.

17:11

Sjors Provoost Yeah, and that's exactly to prevent this type of confusion because what if your clocks are two seconds different or things like that?

17:17

Aaron van Wirdum Oh yeah of course so it's so it uses a derivative of time really yeah okay so if I understand correctly CLTV was essentially building on nLockTime which we discussed at the start of the episode the first thing we discussed was nLockTime and CLTV CheckLockTimeVerify was in fact using that CheckSequenceVerify does not use nLockTime it instead uses nSequence.

17:47

Sjors Provoost Yes. This is newly introduced.

17:49

Aaron van Wirdum Right. So the nSequence, the sequence that's included in the new input for transaction. So if you want to create a new transaction, you have to include an nSequence number. And that sequence number has to correspond with the actual time or the actual block height.

18:07

Sjors Provoost The relative time or the relative block height right, relative to when it was included

18:13

Aaron van Wirdum When the output was being spent? Right okay well that's clear enough for me. I hope our listeners are keeping up as well or maybe they're way ahead of me maybe they already understood what I'm still trying to figure out…

18:25

Sjors Provoost It’s fairly confusing.

18:26

Aaron van Wirdum So okay so I think I understand that part I think my next question would be how then is the time actually embedded in the nSequence how is how does this like literally work?

18:40

Sjors Provoost It's either a number of seconds I think or a number of blocks.

18:45

Aaron van Wirdum Okay how do you know which one? How do you know which one?

18:48

Sjors Provoost Yeah so there's a little trick there there's multiple ways you can do it right so we have this field that is left over from the olden days where it had no meaning and it was 32 bytes so as an engineer then you have to decide okay we have 32 bytes and we want to use this for two different things so there are multiple ways you can do that I'll just go on a little bit of a tangent because we'll get to a certain bug or issue that uses this problem so how would you put that in there well one thing you can do is you can say well I want to be able to put in both a date and a number both of them so what I'm going to do is I'm going to take two bytes and I'm going to reserve that for if you want to put in a date and I'm going to use two bytes for a block

19:26

Aaron van Wirdum Height… is what you mean? Yeah you want to put in both the data and block height you want to use the same number?

19:31

Sjors Provoost I want to use the same, no, if I wanted to be able to specify both, because a script might ask either for a time or for a height, so naively you might say, well, I want to be able to do both. Let's just split the four bytes in half and use two bytes for one of them and the other two for the other one.

19:45

Aaron van Wirdum Right, so if the first two bytes are used, that would mean time, for example, and if the other two are used, that would mean block.

19:51

Sjors Provoost Yeah, or you can use both of them if it means both, right? Maybe you want to restrain both time and height.

19:57

Aaron van Wirdum Sure. Yeah. Okay.

19:58

Sjors Provoost But the problem with that approach would be that two bytes only gives you two to the power of 16 combinations, and that is about 65,000 numbers. So that means you could only use it for 65,000 blocks or 65,000 seconds. And that 65,000 seconds is about a day. So, so basically it gives you very limited options. I mean, you could define it as Instead of seconds, you could say it's hours, etc. So you could do it this way, but it's not great. It doesn't give you a lot of room. So what you can do instead is you say, I'm going to take the first bit of this number. And if the first bit is 0, it means the rest, the other 31 bits are a date. And if the first bit is a 1, the other 32 bits are a height. Then you have 2 to the power of 32 combinations, which is 2 billion different numbers that you can put in there. Now, that's actually not how it works because what it's using instead is saying if the number is more than 500 million, it is interpreted as a date. If the number is less than 500 million, it is interpreted as a height. But that's essentially the same.

21:02

Aaron van Wirdum Do you know why it doesn't work in the way you explained first? That sounds cleaner to me somehow.

21:07

Sjors Provoost I don't know.

21:08

Aaron van Wirdum You don't know? Okay. So if the number is higher than, what did you say, 500,000?

21:13

Sjors Provoost 500 million, I think.

21:15

Aaron van Wirdum Then it's a, which is which?

21:18

Sjors Provoost If it's less than 500 million, it's interpreted as a number of blocks.

21:22

Aaron van Wirdum Right.

21:23

Sjors Provoost And if it's more than 500 million, it's interpreted as a timestamp.

21:26

Aaron van Wirdum Okay.

21:27

Sjors Provoost So yeah, I don't know why they didn't use the first bit. There may be some logic there. Right.

21:32

Aaron van Wirdum Okay, well, that clears up that part for me. So that's how CheckSequenceVerify works. I guess I get that part.

21:39

Sjors Provoost Yeah, I guess the other thing is, my guess is that it is identical to how nLockTime works. And that's just what whatever somebody or Satoshi did in the first year, right? To make that particular choice and not do it the other way.

21:51

Aaron van Wirdum So CheckSequenceVerify was basically specifically implemented to better enable the Lightning network. This was in 2016. Do you know why this is better for the Lightning Network?

22:05

Sjors Provoost Well, because it lets you do relative time locks. So that means that if you're opening a channel or closing a channel, whatever, you can say, well, the other side can, or if you're making a change inside the channel, you can say the other side can get my coins if they give me a pre-image of the hash. And if they don't give me a pre-image of the hash, I'm going to, after two weeks, I'm going to take my coins back. So it's basically a way to do a quick escrow where you say, either give me the pre-image so I can take the coins or I'm going to take the money back. Or so you can take the coins or I can take the money back.

22:38

Aaron van Wirdum Wasn't it the case that under...

22:40

Sjors Provoost The hash time lock contract, basically.

22:43

Aaron van Wirdum Yeah, wasn't it the case that under CLTV, Lightning channels could only be open for a predetermined amount of time?

22:51

Sjors Provoost Yeah, the problem is...

22:52

Aaron van Wirdum Like a year or something?

22:52

Sjors Provoost Exactly. If you don't use relative locks, you have to decide in advance... Basically, for everything in the channel, what's going to happen? You have to put actual deadlines in it. So by relative times, you get a lot more flexibility.

23:03

Aaron van Wirdum Yeah, you can leave the channel open indefinitely, essentially.

23:06

Sjors Provoost Yes.

23:06

Aaron van Wirdum If you want to.

23:07

Sjors Provoost Exactly.

23:08

Aaron van Wirdum Yeah, okay.

23:09

Sjors Provoost I think with absolute lock times, if my memory serves, what you would do is you would... The first time you make a transaction inside Lightning, because you're basically trading transactions with your counterparty, and you don't publish them on the blockchain. But those transactions, every time you change the channel, have to change a bit. And so I think without relative lock times, you would pick a date in the future, you'd say the year 2100, and then you would do one transaction, and you'd say, well, this one I can drop on the chain until the year 2100. But this new state that we've done or we agreed on, I can drop that on the chain until the year 2099. And then we do another one and say, no, I can drop this on the chain until 2098. And that way, the last state is the first thing you can put in the blockchain. But it's kind of tedious because you have to pick a final date and you want to pick that very far in the future. So you can do lots of transactions. But then if you want to close the channel, you have to wait 100 years. So that was the problem with absolute times.

24:03

Aaron van Wirdum Right. So that's why we got CheckSequenceVerify since 2016. All right.

24:09

Sjors Provoost And again, that wasn't enough for Lightning because Lightning also needed SegWit to be practical. But it's definitely useful.

24:18

Aaron van Wirdum Okay. So we started with nLockTime. Then we had CLTV in 2015. Then we had CSV in 2016. What's the next time lock?

24:26

Sjors Provoost There is no next time lock.

24:28

Aaron van Wirdum Is it, Sjors?

24:29

Sjors Provoost I think so, unless I missed something.

24:31

Aaron van Wirdum Okay, and there was a bug you wanted to mention. There was something going on with CLTV and CSV.

24:38

Sjors Provoost Yeah, so the folks at Blockstream seem to have discovered this bug, and they discovered it while working on Miniscript. And we've done an episode about Miniscript, so we won't talk about it here. But basically, you want to be very careful that you do not put a time and a height in the same script. Either a relative time and relative height or an absolute time and an absolute height. Don't combine those two.

25:05

Aaron van Wirdum You can't use them both. You have to pick.

25:07

Sjors Provoost Yeah, you can't use them both. So that means you can have a script like... Let's first say what you cannot do. You cannot have a script that says this coin can only be spent after block 700,000 and after the year 2023.

25:23

Aaron van Wirdum Yeah, or to name another example, you can't make like a multisig where you say... Alice can spend this after this year. Bob can spend it after this height. Right? If it's two out of two, two different.

25:39

Sjors Provoost No, if it's both conditions, you can't do it. But what you're describing here sounds more like an either or.

25:44

Aaron van Wirdum I said a two out of two.

25:46

Sjors Provoost Two out of two. So they both have to.

25:48

Aaron van Wirdum Yes. And then they can't use difference. Yeah. It can't be the case that one of them has to use CLTV and the other has to use CSV. Whatever construction you want to come up with.

26:00

Sjors Provoost It's not about combining CSV and CLTV. It's not about combining relative and absolute locks. It's about combining times and heights.

26:08

Aaron van Wirdum Oh, regardless of whether it's CLTV or CSV. You can't combine time. Okay.

26:13

Sjors Provoost Well, I don't know. You might be able to use a time with a CLTV and then use a height with the nSequence.

26:21

Aaron van Wirdum Okay, we're obviously getting into the weeds now.

26:24

Sjors Provoost You don't want to do it for one, and the reason is pretty simple.

26:27

Aaron van Wirdum I should just let you talk.

26:28

Sjors Provoost Yeah, if you have a constraint that says, don't spend this after block 700,000, well, that 700,000 is expressed as a number, just 700,000. So you're saying height must be higher than 700,000. That's really what you're telling the blockchain. And then if you're saying it has to be after a certain date, well, then it has to be higher than... 100 million or whatever 500 million

26:54

Aaron van Wirdum I… guess that if you're using nSequence for… is this the problem? If you're using nSequence for both so this is CSV related then?

27:05

Sjors Provoost Yeah I think my guess is that they both work the same way but I haven't checked that.

27:09

Aaron van Wirdum If you're using nSequence for both but nSequence can only be interpreted in one way then clearly you [unclear] satisfy both conditions. That must be the problem right?

27:18

Sjors Provoost Yeah but the way I explained it would not work so dear editor we're gonna quickly look this up. Yeah, dear editor, we're going to explain it again. So the reason... I'm not exactly sure where to splice this in, but basically…

27:46

Aaron van Wirdum Just splice it in wherever you think is best. Sorry about this.

27:49

Sjors Provoost So the reason you can't combine a timestamp and a height difference is that if you're saying it has to be after six blocks, that means that the number that you're looking for is higher than six, but also lower than 500 million, because it has to be a height that you're comparing to. But if you're saying it has to be after a certain date, well, then the number must be higher than 500 million because it has to be a date. And so that [unclear] both be true. You cannot have an nSequence that is higher than 500 million, but also lower than 500 million. So now you have actually put your coins in a place where they can never leave.

28:27

Aaron van Wirdum Yeah.

28:27

Sjors Provoost And this can be quite deceptive because the script, if you read it manually, it might look fine, but it's not.

28:32

Aaron van Wirdum Yeah. The nSequence can only be... Interpreted in one of two ways so if you need to interpret it in both ways to satisfy transaction then you have a problem yep yeah that's clear enough.

28:48

Sjors Provoost Okay yeah I think that's all.

28:51

Aaron van Wirdum I have one more question before we stop. Your last question. So I noticed I happen to know that nowadays, so the very first thing that we discussed was nLockTime. And so nowadays, a lot of transactions, or at least Bitcoin Core does this, for example, standard adds nLockTime to every transaction they make. And then I think the nLockTime is basically just the current block or a very recent block anyways. Do you know the details or why this is?

29:24

Sjors Provoost Yes, I believe it sets it to the next block. But I'm not sure. Yeah, my understanding from reading the wiki is that it has to do with something called fee-sniping. And I believe that means is that you don't want to create a situation where, let's say, the block reward is very low. So most blocks produce only zero satoshis in subsidy because we're in the year 2100. And I put a transaction on the chain that pays a million dollars in fees maybe some miner wants to rewind that block and also take the million dollars in fees and I guess you can limit the damage by setting the height because at least the miner can only go back one block and not infinite blocks. But now I guess I'm just guessing what the reasoning was there.

30:02

Aaron van Wirdum Yeah no that sounds about right to me. Okay well Sjors, in that case I think we've basically explained nLockTime. We've explained all time locks, actually.

30:13

Sjors Provoost We've explained all the time locks.

30:14

Aaron van Wirdum And now we're going to struggle to find a topic for next episode at some point.

30:19

Sjors Provoost Exactly. Thank you for listening to Bitcoin,

30:21

Aaron van Wirdum Explained.