Created
May 1, 2015 17:18
-
-
Save morcos/61084ac8a33363278638 to your computer and use it in GitHub Desktop.
RPC test for mempool only CLTV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
# Copyright (c) 2015 The Bitcoin Core developers | |
# Distributed under the MIT software license, see the accompanying | |
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
# | |
# Test CLTV code | |
# | |
from test_framework import BitcoinTestFramework | |
from bitcoinrpc.authproxy import JSONRPCException | |
from util import * | |
from mininode import CTransaction | |
from blocktools import create_coinbase, create_block | |
from binascii import hexlify, unhexlify | |
import cStringIO | |
import time | |
RPC_VERIFY_REJECTED = -26 | |
class CLTVTest(BitcoinTestFramework): | |
def setup_chain(self): | |
print("Initializing test directory "+self.options.tmpdir) | |
initialize_chain_clean(self.options.tmpdir, 1) | |
def setup_network(self): | |
self.nodes = [] | |
self.is_network_split = False | |
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-relaypriority=0"])) | |
def run_test(self): | |
# Construct a CLTV P2SH | |
P2SH = "2NCJq1yiHGpUHKxm2fnPPXJYMmhEX22pm5h" # P2SH of "105 OP_CHECKLOCKTIMEVERIFY OP_DROP" | |
# Associated ScriptSig to spend the P2SH | |
# 6 bytes of OP_TRUE and push 4-byte redeem script of "105 OP_CHECKLOCKTIMEVERIFY OP_DROP" | |
SCRIPT_SIG = "0651040169b175" | |
# Mine 100 blocks so we can spend block at height 1 in next block which will be height 101 | |
self.nodes[0].generate(100) | |
assert(self.nodes[0].getblockcount() == 100) | |
# Get the coinbase txid of block at height 1 and create a | |
# transaction spending that to our script | |
coinbase_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0] | |
inputs = [{ "txid" : coinbase_txid, "vout" : 0 }] | |
outputs = { P2SH : 50 } | |
rawtx = self.nodes[0].createrawtransaction(inputs, outputs) | |
signresult = self.nodes[0].signrawtransaction(rawtx) | |
txid = self.nodes[0].sendrawtransaction(signresult["hex"]) | |
# Mine this transaction | |
self.nodes[0].generate(1) | |
# Construct a spending transaction | |
inputs = [{ "txid" : txid, "vout" : 0}] | |
new_address = self.nodes[0].getnewaddress() | |
outputs = { new_address : 50 } | |
rawtx = self.nodes[0].createrawtransaction(inputs, outputs) | |
# Decompose the transaction so we can hand modify | |
## version + #txin + txout hash + txout index | |
part1_tx = rawtx[0:8] + rawtx[8:10] + rawtx[10:74] + rawtx[74:82] | |
## ScriptSig(0 len) + sequence | |
# unused rawtx[82:84] + rawtx[84:92] | |
part2_tx = rawtx[92:-8] | |
## locktime | |
# unused rawtx[-8:] | |
# Modify sequence and insert our scriptSig | |
# We can now create different tx's by appending different locktimes | |
seq = "00000000" | |
mod_tx = part1_tx + SCRIPT_SIG + seq + part2_tx | |
# Construct a valid spending transaction | |
valid_tx = mod_tx + "69000000" | |
# Try to spend it too early | |
try: | |
self.nodes[0].sendrawtransaction(valid_tx) | |
raise AssertionError("Transaction shouldn't have been accepted, locktime in the future") | |
except JSONRPCException as e: | |
assert (e.error['code'] == RPC_VERIFY_REJECTED) | |
# Construct a transaction with low enough lock time that should fail CLTV | |
cltv_fail_tx = mod_tx + "65000000" | |
try: | |
self.nodes[0].sendrawtransaction(cltv_fail_tx) | |
raise AssertionError("Transaction shouldn't have been accepted, CLTV script fails") | |
except JSONRPCException as e: | |
assert (e.error['code'] == RPC_VERIFY_REJECTED) | |
# Verify that this is a only a standardness failure | |
# by submitting cltv_fail_tx in a block | |
assert(self.nodes[0].getblockcount() == 101) | |
# Create a CTransaction with cltv_fail_tx | |
t = CTransaction() | |
t.deserialize(cStringIO.StringIO(unhexlify(cltv_fail_tx))) | |
t.rehash() | |
# Create a CBlock which contains that transaction | |
hashprev = int("0x" + self.nodes[0].getbestblockhash() + "L", 0) | |
block = create_block(hashprev, create_coinbase(101), time.time()+100) | |
block.nVersion = 3 | |
block.vtx.append(t) | |
block.hashMerkleRoot = block.calc_merkle_root() | |
block.rehash() | |
block.solve() | |
# Submit the block and verify it's accepted | |
blockhex = hexlify(block.serialize()) | |
self.nodes[0].submitblock(blockhex) | |
assert(self.nodes[0].getblockcount() == 102) | |
# Invalidate that block, and verify transaction isn't added to mempool | |
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) | |
assert(len(self.nodes[0].getrawmempool()) == 0) | |
assert(self.nodes[0].getblockcount() == 101) | |
# Mine to block 105, valid_tx should be accepted to mempool now | |
self.nodes[0].generate(4) | |
assert(self.nodes[0].getblockcount() == 105) | |
self.nodes[0].sendrawtransaction(valid_tx) | |
assert(len(self.nodes[0].getrawmempool()) == 1) | |
if __name__ == '__main__': | |
CLTVTest().main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment