Bitcoin Forum
May 05, 2024, 09:43:22 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Creating CHECKLOCKTIMEVERIFY transactions from the QT GUI  (Read 1486 times)
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 19, 2016, 11:09:24 AM
 #1

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://bitcointalk.org/index.php?topic=1317918.0

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,

Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
Activity + Trust + Earned Merit == The Most Recognized Users on Bitcointalk
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1714902202
Hero Member
*
Offline Offline

Posts: 1714902202

View Profile Personal Message (Offline)

Ignore
1714902202
Reply with quote  #2

1714902202
Report to moderator
1714902202
Hero Member
*
Offline Offline

Posts: 1714902202

View Profile Personal Message (Offline)

Ignore
1714902202
Reply with quote  #2

1714902202
Report to moderator
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 19, 2016, 11:13:11 AM
 #2

I have done quite a bit of work with CLTV recently: https://bitcointalk.org/index.php?topic=598860.msg13435766#msg13435766

Feel free to PM me to discuss your ideas.

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 20, 2016, 05:13:58 AM
 #3

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;


Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 20, 2016, 05:18:05 AM
 #4

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).

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 20, 2016, 05:26:02 AM
 #5

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?

Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 20, 2016, 05:34:16 AM
 #6

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

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 20, 2016, 05:50:46 AM
 #7

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.

Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 20, 2016, 06:04:30 AM
 #8

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.

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 20, 2016, 06:15:51 AM
 #9

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<unsigned char>& 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);
    }

Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 20, 2016, 06:22:14 AM
 #10

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.

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 28, 2016, 01:35:05 PM
 #11

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<unsigned char> 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;
}

Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 28, 2016, 01:41:36 PM
 #12

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.

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
FreeTrade (OP)
Legendary
*
Offline Offline

Activity: 1428
Merit: 1030



View Profile
January 28, 2016, 03:11:04 PM
 #13

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"
]
}
}
]
}

Membercoin - Layer 1 Coin used for the member.cash decentralized social network.
10% Interest On All Balances. Browser and Solo Mining. 100% Distributed to Users and Developers.
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 28, 2016, 03:39:37 PM
 #14

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.

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
CIYAM
Legendary
*
Offline Offline

Activity: 1890
Merit: 1075


Ian Knowles - CIYAM Lead Developer


View Profile WWW
January 29, 2016, 09:06:18 AM
 #15

And sure enough - I had screwed up the endian so using: 02ff00 works as expected. Smiley

With CIYAM anyone can create 100% generated C++ web applications in literally minutes.

GPG Public Key | 1ciyam3htJit1feGa26p2wQ4aw6KFTejU
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!