Author

Topic: Creating CHECKLOCKTIMEVERIFY transactions from the QT GUI (Read 1501 times)

legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
And sure enough - I had screwed up the endian so using: 02ff00 works as expected. Smiley
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
Hmm... I see - I think I got tricked by endian again (man I hate that Satoshi had to confuse everything with that).

Thanks - I will check my code again tomorrow to see if I can get it working properly.
legendary
Activity: 1470
Merit: 1030
Here's what I've got - note it is on an altchain, so probably won't be valid for other reasons - but maybe it has what you're looking for?


22:08:16

decoderawtransaction 0100000002b060c651aa2c0a8b4a31c99690541dc45441f7c6f5dd1594603fd4f1ba03c98000000 000484730440220766c0aa5e056698a98ac79f14348c942ccaa6c46c8d475f2be07ef5b725413db 02207e1b5ed292c0f24e221d7c2bf40eb8330bca29044e9513948f627337b9fd056001feffffffe fc64d6c28b169424697539942b6a29f2de9f1ed7676b44cdcc64f340654b2ca0000000048473044 0220385c78536e80a919220d30c3543170f070bd52428cd5e54a14be9752b4058c6302201d32f31 75ffd256b345fb2143af3b2f8cb98bc5e152c85c7a22f7b3eff93f19501feffffff02b525f60500 0000001e02ff00b17576a914c83b25caf55db50ce976f35a37bf476dde5abd3688acf828f805000 000001976a9149c6ecc38cfb2f36070ba25ffd4e90a83969ef88e88ac45000000


22:08:16

{
"txid" : "ebfc9a16c90c011e532bd7ff901eda4d60470362354fedd68bf069aad777f453",
"version" : 1,
"locktime" : 69,
"vin" : [
{
"txid" : "80c903baf1d43f609415ddf5c6f74154c41d549096c9314a8b0a2caa51c660b0",
"vout" : 0,
"scriptSig" : {
"asm" : "30440220766c0aa5e056698a98ac79f14348c942ccaa6c46c8d475f2be07ef5b725413db02207e1 b5ed292c0f24e221d7c2bf40eb8330bca29044e9513948f627337b9fd056001",
"hex" : "4730440220766c0aa5e056698a98ac79f14348c942ccaa6c46c8d475f2be07ef5b725413db02207 e1b5ed292c0f24e221d7c2bf40eb8330bca29044e9513948f627337b9fd056001"
},
"sequence" : 4294967294
},
{
"txid" : "cab25406344fc6dc4cb47676edf1e92d9fa2b642995397464269b1286c4dc6ef",
"vout" : 0,
"scriptSig" : {
"asm" : "30440220385c78536e80a919220d30c3543170f070bd52428cd5e54a14be9752b4058c6302201d3 2f3175ffd256b345fb2143af3b2f8cb98bc5e152c85c7a22f7b3eff93f19501",
"hex" : "4730440220385c78536e80a919220d30c3543170f070bd52428cd5e54a14be9752b4058c6302201 d32f3175ffd256b345fb2143af3b2f8cb98bc5e152c85c7a22f7b3eff93f19501"
},
"sequence" : 4294967294
}
],
"vout" : [
{
"value" : 1.00017589,
"n" : 0,
"scriptPubKey" : {
"asm" : "255 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 c83b25caf55db50ce976f35a37bf476dde5abd36 OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "02ff00b17576a914c83b25caf55db50ce976f35a37bf476dde5abd3688ac",
"reqSigs" : 1,
"type" : "checklocktimeverify",
"addresses" : [
"HQmrPMp7QU6gAQmaSh8v37JfCv8dDdqxLB"
]
}
},
{
"value" : 1.00149496,
"n" : 1,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 9c6ecc38cfb2f36070ba25ffd4e90a83969ef88e OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a9149c6ecc38cfb2f36070ba25ffd4e90a83969ef88e88ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"HLnGXdc3yDBEyRJRRW4vsLdU2bAa1kmEaJ"
]
}
}
]
}
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
Have you actually been able to issue a CLTV redeem using the block number 255 (using "-regest")?

My test for 127 worked perfectly but as I said when I tried 255 it failed (because of a negative value) so I then changed the 0xff to become 0x00ff (adding one to the length of the stack input of course) but it then gave me an error about the value not being minimal.

If you could show me a raw tx that works with block 255 CLTV I'd appreciate it (maybe I was making some other silly mistake when I was testing such as confusing endian).

Although for the purposes of the software I've written unix timestamps are fine I would like to work out how to also do block numbers correctly.
legendary
Activity: 1470
Merit: 1030
Hmm, care to elaborate? I'd much rather use the block numbers.

In testing with -regtest I tried to use block #255 but simply could not get it to accept the number (it complained either due to being negative or it being too big if I added the leading zero byte).

If you are able to work out how to do that correctly then please post here if you don't mind.


Update - I couldn't reproduce a problem with 255 - seems the relevant functions seem to output the same number that is put in - here's the code I was using to verify -

                for (int i=0;i<50000;i++){
                    scriptPubKey = GetTimeLockScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get(),i);
                    vector vch1;
                    CScript::const_iterator pc1 = scriptPubKey.begin();
                    opcodetype opcode1;
                    scriptPubKey.GetOp(pc1, opcode1, vch1);
                    int b = CScriptNum(vch1, true, 5).getint();
                    if(i!=b){
                        LogPrintf("Problem %d %d",i,b);
                    }
                }


CScript GetTimeLockScriptForDestination(const CTxDestination& dest, const int64_t smallInt)
{
    CScript script;
    script.clear();
    script << CScriptNum(smallInt) << OP_CHECKLOCKTIMEVERIFY << OP_DROP;
    boost::apply_visitor(CScriptVisitor(&script), dest);
    return script;
}
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
I shall - on a first glance, i'd guess the problem migh be here -

const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);

----

Yes - my guess is that this code is not working as intended.
legendary
Activity: 1470
Merit: 1030
Hmm, care to elaborate? I'd much rather use the block numbers.

In testing with -regtest I tried to use block #255 but simply could not get it to accept the number (it complained either due to being negative or it being too big if I added the leading zero byte).

If you are able to work out how to do that correctly then please post here if you don't mind.


I shall - on a first glance, i'd guess the problem migh be here -

const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);

----

    explicit CScriptNum(const std::vector& vch, bool fRequireMinimal,
                        const size_t nMaxNumSize = nDefaultMaxNumSize)
    {
        if (vch.size() > nMaxNumSize) {
            throw scriptnum_error("script number overflow");
        }
        if (fRequireMinimal && vch.size() > 0) {
            // Check that the number is encoded with the minimum possible
            // number of bytes.
            //
            // If the most-significant-byte - excluding the sign bit - is zero
            // then we're not minimal. Note how this test also rejects the
            // negative-zero encoding, 0x80.
            if ((vch.back() & 0x7f) == 0) {
                // One exception: if there's more than one byte and the most
                // significant bit of the second-most-significant-byte is set
                // it would conflict with the sign bit. An example of this case
                // is +-255, which encode to 0xff00 and 0xff80 respectively.
                // (big-endian).
                if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
                    throw scriptnum_error("non-minimally encoded script number");
                }
            }
        }
        m_value = set_vch(vch);
    }
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
Hmm, care to elaborate? I'd much rather use the block numbers.

In testing with -regtest I tried to use block #255 but simply could not get it to accept the number (it complained either due to being negative or it being too big if I added the leading zero byte).

If you are able to work out how to do that correctly then please post here if you don't mind.
legendary
Activity: 1470
Merit: 1030
The CLTV value is an unsigned 32 bit integer (little endian) - when the value is large enough it is treated as a Unix time stamp and I would recommend only using that approach (as I found an issue trying to use the block number approach).

Hmm, care to elaborate? I'd much rather use the block numbers.

If we were looking at putting in the current time (approximately) then it would be this: 101c9f56

Many thanks.
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
Thanks, yes - that's exactly what I'm looking for - so put together it's 

*script << smallInt << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;

Any idea on what the type or format of 'smallInt' should be?

The CLTV value is an unsigned 32 bit integer (little endian) - when the value is large enough it is treated as a Unix time stamp and I would recommend only using that approach (as I found an issue trying to use the block number approach).

If we were looking at putting in the current time (approximately) then it would be this: 101c9f56
legendary
Activity: 1470
Merit: 1030
It basically comes down to how you want to do the script (apart from the CLTV itself).

With what you have posted above I think you will need an OP_DUP before the OP_HASH160 (assuming you are wanting what otherwise would be a normal looking Bitcoin tx redeem).


Thanks, yes - that's exactly what I'm looking for - so put together it's 

*script << smallInt << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;

Any idea on what the type or format of 'smallInt' should be?
legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
It basically comes down to how you want to do the script (apart from the CLTV itself).

With what you have posted above I think you will need an OP_DUP before the OP_HASH160 (assuming you are wanting what otherwise would be a normal looking Bitcoin tx redeem).
legendary
Activity: 1470
Merit: 1030
Okay - tracked it down to CScriptVisitor . . .

now, based on Peter Todd's python example I've got -


        *script << smallInt << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(keyID) << OP_CHECKSIG;

but I don't understand Bitcoin script well. Wondering if it shouldn't be more like

        *script << smallInt << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;

legendary
Activity: 1890
Merit: 1086
Ian Knowles - CIYAM Lead Developer
I have done quite a bit of work with CLTV recently: https://bitcointalksearch.org/topic/m.13435766

Feel free to PM me to discuss your ideas.
legendary
Activity: 1470
Merit: 1030
I'm working on an altcoin that will rely heavily on CHECKLOCKTIMEVERIFY - it allows users to earn interest on their balances if they tie them up for a set number of blocks using CHECKLOCKTIMEVERIFY.

More details -
https://bitcointalksearch.org/topic/ann-hodl-5-interest-no-staking-req-term-deposits-10-solo-mining-1317918

I want to implement this in the QT GUI, but I'm having a devil of a time trying to create a CHECKLOCKTIMEVERIFY transaction. I just can't find where the scriptpubkey for standard transactions is created when sending coins. I want to find that so that I can create a CLTV transaction instead. Can anyone provide code or point me to the right place in the codebase.

I'm posting this here because I think it'll be useful to Bitcoin to have a project testing CLTV functionality before it becomes available for Bitcoin users.

Many thanks,
Jump to: