5

In bitcoin, each transaction has an nLockTime integer to specify the earliest allowed block number/time that the transaction can be added to the blockchain. In addition, each transaction input has an nSequence integer that could theoretically be used to update transactions and know which is the most recent (although this functionality is currently disabled).

But is there a way to broadcast a transaction which is final and can be added to the blockchain immediately, but also make it so that its outputs cannot be spent until a certain block number/time? It seems like this would be a useful feature. For example, if I want to give my inheritance to be made available at the time my grandson/granddaughter turns 18, I don't think there is any way to do that in bitcoin except have someone hold the funds and give them to them at the time. Or if I wanted to give someone an allowance, I could just send funds at once for 3 months or so, and they would just show up in the son/daughter's wallet on a weekly basis.

So, just to double check, there's no way to do something like this in bitcoin, is there? Are there any security risks by allowing transactions like this? If there really isn't any way to do this, then maybe it's something to add to the hard fork wishlist.

If there is no way to do this with Bitcoin right now, is it because there is a serious flaw with such a system where an UTXO could be added to the blockchain that is not YET spendable?

I can think of two ways that such a thing might be implemented.

  • Supplement the bitcoin scripting language with OP_BLOCKINDEX and OP_BLOCKTIME opcodes, which just push the corresponding value onto the stack. These values would have to come from the block that spends the UTXO, though, not from the the block that included the transaction that created the UTXO. This would mean that any transaction outputs with these OP codes could not be spent with 0 confirmations, because these OPs would have no meaning in this context. (This method possibly adds too much complexity to the situation)
  • Or, similar to the nSequence field, we could add an extra few bytes to each output to denote when an output can be spent (block number/time). If not provided, it can be assumed to be 0.
6

No, there isn't currently any way to do what you describe without using a third-party oracle.

Yes, you may be able to do this relatively soon. A soft fork has been proposed to introduce a OP_CHECKLOCKTIMEVERIFY op code` (CLTV), and what what I can tell it has strong support from the core dev team (but note that soft forks require miner support for implementation).

As Nick says, previous attempts were rejected because they proposed pushing the current block's height or time on to the stack like this:

<pubkey>       checksigverify  block           <data>    equalverify
<your pubkey>  compare to sig  current height  1000000   Only spend in block 1,000,000

Again, elaborating on what Nick said, the example transaction above would be valid in block 1,000,000---but if there was a chain reorganization, it might not be included in the new block 1,000,000 and so any transactions depending on it would be invalid.

The CLTV op code avoids this two ways. First, it use the nLockTime value from the spending transaction rather than the block height or block header time value. Since a transaction can only be included in a block if its nLockTime is equal to or greater than the current block height/time, this achieves the primary goal of allowing UTXOs that can't be spent until a particular time.

The other thing CLTV does is check values directly rather than pushing data to the stack. This allows it to only implement a greater-than-or-equal-to check, so the transaction is always spendable after the specified height/time.

My guess is that the soft fork process to introduce CLTV will begin with Bitcoin Core 0.11, possibly sometime around July 2015. (But, really, the core devs are unlikely to spend much time on CLTV until 0.10 gets released around January, so don't count on it.)

  • I wasn't aware of this change. +1 – Nick ODell Nov 21 '14 at 18:01
  • Thanks David, this is really helpful. I'm going to read more about OP_CHECKLOCKTIMEVERIFY. I'm still a little confused, though, how can nLockTime be used both for determining the soonest point that a transaction can be added to the blockchain and for determining the soonest time it can be spent? Will nLockTime lose its old functionality and be replaced with the new? It can't take on two values at once... – morsecoder Nov 21 '14 at 20:48
  • @StephenM347 Read the part where it says "nLockTime value from the spending transaction". So TX1/Output0 uses CLTV in its scriptPubKey to lock the UTXO until block 1,000,000. TX2 has a nLockTime >= 1,000,000 and it includes an input spending TX1/Output0. Thus no change in current nLockTime behavior is necessary. – David A. Harding Nov 21 '14 at 20:55
  • I think I see now, CLTV makes it so that it the UTXO can only be spent with transactions that have nLockTime greater than some number which is specified in the scriptPubKey, and the current functionality of bitcoin already makes it so that transactions can't be included in the blockchain before the nLockTime block/time. Thanks! – morsecoder Nov 22 '14 at 15:50
2

I'm unable to find the bitcointalk thread/github issue discussing this, but a block index opcode was considered and rejected.

The reason (IIRC) is that it's important that if a transaction does not get into a block, it can still be included in another block. It would be very surprising if a transaction was reversed because the block it was in became extinct, and the block that replaced it had a timestamp of ten seconds later.

Of course, you could mitigate this by detecting when an incoming payment has one of the time/block dependent opcodes in it. The next problem you need to solve is that someone could make a time-dependent transaction, then spend one of those outputs with a normal transaction. It would look like a normal transaction to the person you sent it to, but it would actually depend on a transaction that could become invalid if included in a different block.

None of these problems are unsolvable, but without a compelling use-case, they're not worth the complexity. In the example you give, the same thing could be accomplished by putting your private key in a safety deposit box and willing its contents to your grandson.

Also, your problem can kind-of be solved with nLockTime. You can create a transaction sending your Bitcoins to an address controlled by your grandson; set the nLockTime to expire at a certain date; and destroy the private key signing that transaction. The problem with this is that the transaction is not kept on the blockchain. Also, your grandson had better not lose that private key. :)

Commenters, please chime in if you can find where this was discussed.

  • +1 for the work around with nLockTime. It still would necessarily create a single point of failure, though, where as if you could send to a Multisig, you could eliminate that. What do you mean by "someone could make a time-dependent ... with a normal transaction."? It's late, and there are a lot ins/outs/transactions being referenced in that sentence. – morsecoder Nov 21 '14 at 6:28
  • 1
    On a related note - my grandfather left me a one thousand dollar Confederate war bond. Perhaps you should leave them something more likely to hold its value. ;) – Nick ODell Nov 21 '14 at 6:29
  • if you could send to a Multisig, you could eliminate that True. What do you mean Sorry, that wasn't very clear. Is it better now? – Nick ODell Nov 21 '14 at 6:33
  • ntimelock set to x > 0 will not be processed until x blocks after the Txn's block height, although in practice apparently 2 hours (12 blocks) is the ideal cutoff time. This is because if you want to rescind the transaction, a new Tx needs to be formed to divert the Bitcoins from the time locked output address to a new output (ie so when ntimelock expires, the Tx will fail because the inputs are spent. This is all from memory though so I'm not confident enough to make it an answer yet – Wizard Of Ozzie Nov 21 '14 at 11:59
  • Transactions don't have a block height until they're included - nLockTime refers to a block index or a unix timestamp - see the protocol spec. Also, transaction replacement is not enabled. – Nick ODell Nov 21 '14 at 18:00
1

The other answers here are currently outdated because OP_CSV and OP_CHECKLOCKTIMEVERIFY were adopted by the network, both of which provide ways to do construct locked outputs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.