- Locking of transactions can be done
Yes, with some caveats. One of the caveats is that the mechanism (nLockTime) was not designed for the application you have in mind. Even the terminology is backwards. In the documentation of the original feature, which was meant to enable multi-party contracts, a "locked" transaction is one that
can be included in the blockchain (and therefore re-spent). Whereas you are obviously interested in "locking" Bitcoins to
prevent them from being spent.
Another caveat is that "locked" Bitcoin transactions are stored in the memory pool, which is not exactly the most reliable place.
- It is possible to spend the coins you have locked, but it will result in your previously locked transaction being invalidated, for double spending reasons
This is another caveat. It is possible to spend "locked" coins by creating a replacement TX and mining it yourself:
nodes will accept them and hold them in their memory pool (and thus drop conflicting transactions)
...
If you want to replace a time-locked transaction, you're going to have to mine it yourself, or go find a miner to agree to help you. Once a replacement is mined (or even just a regular transaction spending one of the inputs), all nodes holding the time-locked tx will see the conflict and drop the one in their memory pool.
The easy way to avoid this is to set the sequence number to the maximum value and prevent replacements, BUT you can't do that because:
if all the inputs have a UINT_MAX sequence number then lockTime is ignored.
The hard way to work around this limitation is to create a transaction with multiple inputs from different parties, such that they would have to collude in order to replace the transaction and spend the "locked" coins.
- a procedure called "isfinal" in the bitcoin code is broken
For the purpose of this application, yeah basically. But it's not clear that it's possible to "fix" it without breaking the original purpose of nLockTime. So, we're limited to the work-around mentioned.
This bug report was opened because I neglected to set the sequence number on the first test transaction and created some confusion when it didn't work the way I expected. But that's the code in question.