Author

Topic: Some nLockTime and transaction hash calculation questions (Read 1151 times)

legendary
Activity: 1428
Merit: 1093
Core Armory Developer
That's perfect, thanks!  I'm realizing that, while I don't have the C++ skills to understand much of the client architecture, I can decipher snippets like this (if I know where to find  them).

Quote
You aren't allowed to have a transaction that depends on a non-final transaction (see the IsFinal() check). So you can't use them in contracts.

Not all contracts are executed directly through the blockchain.  Some of them may involve handing another party a partially signed transaction, and letting them sign and broadcast it under whatever conditions are called for.  If the transaction hash can keep changing unpredictably, then it seems then this isn't feasible at all, regardless of whether the network would allow it (loosely speaking).

legendary
Activity: 1526
Merit: 1129
From the source:

Code:
    // Check for conflicts with in-memory transactions
    CTransaction* ptxOld = NULL;
    for (int i = 0; i < vin.size(); i++)
    {
        COutPoint outpoint = vin[i].prevout;
        if (mapNextTx.count(outpoint))
        {
            // Disable replacement feature for now
            return false;

            // Allow replacing with a newer version of the same transaction
            if (i != 0)
                return false;
            ptxOld = mapNextTx[outpoint].ptx;
            if (ptxOld->IsFinal())
                return false;
            if (!IsNewerThan(*ptxOld))
                return false;
            for (int i = 0; i < vin.size(); i++)
            {
                COutPoint outpoint = vin[i].prevout;
                if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
                    return false;
            }
            break;
        }
    }

In English, a transaction is considered a candidate for replacement of another transaction if the first input connects to the same output. If the new tx does not replace the old tx, it is a  double spend and thus invalid.

You aren't allowed to have a transaction that depends on a non-final transaction (see the IsFinal() check). So you can't use them in contracts.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
It looks like this question was never answered, and I still want to know how this works.  If a tx uses nLockTime, it allows the tx to be replaced with higher sequence numbers up until the locktime.  But won't these replacement transactions have different hashes than the original?  If so, how can the client/network know which transaction is being replaced other than trying to match up TxOuts being spent?  Presumably the TxOuts could change, which makes this even more unreliable.  And of course, some of the more complex contracts might actually have future transactions based on a previous transaction with a locktime, which would have a changing hash...

legendary
Activity: 1526
Merit: 1129
If all the TxIns can be signed by one entity then there's little point in issuing an nLockTime transaction as they can issue arbitrary revisions until the time expires. They could get equivalent functionality by not issuing the transaction or not constructing it until it's needed.
Is this correct?

There are uses for locked transactions outside of contracts, for instance to set up recurring payments/subscriptions. If you don't want your wallet software to be constantly running/online, it might be helpful. I think it's unclear whether this will ever be done in practice.

Quote
Transactions involving nLockTime are used in forming various sorts of contracts some of which involve creating and signing transactions spending incompletely signed transactions.

Which contracts are you thinking of? In the deposits example, the half signed transaction is not Tx1 but Tx2. Tx1 is created by the user to start the negotiation process and does not change after that.

I just noticed that the following paragraph I wrote about security-funding assurance contracts is indeed impossible to do:

Quote
The incentive transactions are broadcast before the assurance contract. They are considered to be orphan transactions because their referenced input (the contract) hasn’t been seen yet by the network, but pre-broadcasting them lets pledgers know what they are signing for and prevents the entrepreneur stealing the coins. Once the contract is broadcast, the orphan transactions become valid and can be claimed by miners once their block number is reached.

... for the reasons you state. But that is not really essential to the idea.

It's possible there are other bugs that page, ie things which are unimplementable, we won't know for sure until somebody actually does it. Eg, CHECKMULTISIG has a bug that requires a workaround, fortunately not a complicated one, but the Contracts page doesn't mention it because none of them have ever been tried in practice.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I'm not up to par with my understanding of the nlocktime field, but what does "replacement" mean in this context?  We say the tx can be replaced, but if it's expected to have the exact same hash as the original transaction, it can only be replaced with an identical copy of itself, which isn't very useful. 

From what I understand, you have to increment the sequence numbers on the TxIn in order to issue replacement transactions.  Regardless of signatures, this would change the Tx hash as well.  Although I don't understand how this is implemented, it sounds like the protocol expects the tx hash to change when nlocktime/nsequence fields are utilized.
sr. member
Activity: 416
Merit: 277
The idea of using nLockTime is to have a transaction which can be replaced but which, if no replacement is provided, will change into a normal transaction once the time has expired.

If all the TxIns can be signed by one entity then there's little point in issuing an nLockTime transaction as they can issue arbitrary revisions until the time expires. They could get equivalent functionality by not issuing the transaction or not constructing it until it's needed.
Is this correct?

Transactions involving nLockTime are used in forming various sorts of contracts some of which involve creating and signing transactions spending incompletely signed transactions. Transactions are identified by their hashes and in order to spend a transaction, you have to know its hash. It follows therefore that for these contracts to work, the process of signing a transaction must not change its hash. To do this, when calculating a transaction's hash, the signatures for the txins must be removed, zeroed out or otherwise rendered constant. I believe that this does not occur at the moment.
Code:
uint256 CTransaction::GetHash() const{return SerializeHash(*this);}

Now three possibilities exist: (neglect that they are not mutually exclusive)
1) I'm mistaken in my understanding or logic.
2) The contracts mentioned above which need to construct transactions spending unsigned transactions are not intended to be possible.
3) The current hash calculation is incompatible with the above contracts and needs to change at some point.
Which is it?

ByteCoin
Jump to: