1#!/usr/bin/env python3
2
3from test_framework.test_framework import BitcoinTestFramework
4from test_framework.util import *
5from test_framework.script import *
6from test_framework.mininode import *
7from test_framework.address import *
8from test_framework.qtum import *
9
10class QtumDivergenceDosTest(BitcoinTestFramework):
11    def set_test_params(self):
12        self.setup_clean_chain = True
13        self.num_nodes = 1
14        self.extra_args = [[]]
15
16    def skip_test_if_missing_module(self):
17        self.skip_if_no_wallet()
18
19    def submit_block_with_txs(self, txs):
20        tip = self.node.getblock(self.node.getbestblockhash())
21        block = create_block(int(tip['hash'], 16), create_coinbase(tip['height']+1), tip['time']+1)
22        block.hashStateRoot = int(tip['hashStateRoot'], 16)
23        block.hashUTXORoot = int(tip['hashUTXORoot'], 16)
24        if txs:
25            address = self.node.gettxout(hex(txs[0].vin[0].prevout.hash)[2:].zfill(64), txs[0].vin[0].prevout.n)['scriptPubKey']['addresses'][0]
26            haddress = hex_str_to_bytes(p2pkh_to_hex_hash(address))
27            block.vtx[0].vout.append(CTxOut(100, CScript([OP_DUP, OP_HASH160, haddress, OP_EQUALVERIFY, OP_CHECKSIG])))
28            if len(txs) > 1:
29                txs[-1].vout[0].scriptPubKey = CScript([OP_DUP, OP_HASH160, haddress, OP_EQUALVERIFY, OP_CHECKSIG])
30
31        block.vtx += txs
32        for tx in block.vtx:
33            tx.rehash()
34        block.hashMerkleRoot = block.calc_merkle_root()
35        block.solve()
36        assert_equal(self.node.submitblock(bytes_to_hex_str(block.serialize())), 'incorrect-transactions-or-hashes-block')
37
38
39    def too_few_txs_test(self):
40        # Run it many times so we can trigger out of bounds segfaults with a high probability
41        tx = CTransaction()
42        tx.vin = [make_vin(self.node, COIN)]
43        tx.vout = [CTxOut(COIN-40000000, scriptPubKey=CScript([b"\x04", CScriptNum(100000), CScriptNum(QTUM_MIN_GAS_PRICE), hex_str_to_bytes("00"), hex_str_to_bytes(self.contract_address), OP_CALL]))]
44        tx = rpc_sign_transaction(self.node, tx)
45        tx.rehash()
46        self.submit_block_with_txs([tx])
47
48    def different_but_same_number_aal_txs_test(self):
49        # Run it many times so we can trigger out of bounds segfaults with a high probability
50        tx1 = CTransaction()
51        tx1.vin = [make_vin(self.node, COIN // 10)]
52        tx1.vout = [CTxOut(1, scriptPubKey=CScript([b"\x04", CScriptNum(100000), CScriptNum(QTUM_MIN_GAS_PRICE), hex_str_to_bytes("00"), hex_str_to_bytes(self.contract_address), OP_CALL]))]
53        tx1 = rpc_sign_transaction(self.node, tx1)
54        tx1.rehash()
55
56        tx2 = CTransaction()
57        tx2.nVersion = 2
58        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), scriptSig=CScript([OP_SPEND]), nSequence=0xffffffff)]
59        tx2.vout = [CTxOut(0, scriptPubKey=CScript([OP_DUP, OP_HASH160, hex_str_to_bytes("00"*19)+b"\x01", OP_EQUALVERIFY, OP_CHECKSIG]))]
60        tx2.rehash()
61        self.submit_block_with_txs([tx1, tx2])
62
63
64    def too_many_txs_test(self):
65        # Run it many times so we can trigger out of bounds segfaults with a high probability
66        tx1 = CTransaction()
67        tx1.vin = [make_vin(self.node, COIN // 10)]
68        tx1.vout = [CTxOut(1, scriptPubKey=CScript([b"\x04", CScriptNum(100000), CScriptNum(QTUM_MIN_GAS_PRICE), hex_str_to_bytes("00"), hex_str_to_bytes(self.contract_address), OP_CALL]))]
69        tx1 = rpc_sign_transaction(self.node, tx1)
70        tx1.rehash()
71
72        tx2 = CTransaction()
73        tx2.nVersion = 2
74        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), scriptSig=CScript([OP_SPEND]), nSequence=0xffffffff)]
75        tx2.vout = [CTxOut(0, scriptPubKey=CScript([b"\x00", CScriptNum(0), CScriptNum(0), hex_str_to_bytes("00"), hex_str_to_bytes(self.contract_address), OP_CALL]))]
76        tx2.rehash()
77
78        tx3 = CTransaction()
79        tx2.nVersion = 2
80        tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), scriptSig=CScript([OP_SPEND]))]
81        tx3.vout = [CTxOut(0, scriptPubKey=CScript([OP_DUP, OP_HASH160, hex_str_to_bytes("00"*19)+b"\x00", OP_EQUALVERIFY, OP_CHECKSIG]))]
82        tx3.rehash()
83        self.submit_block_with_txs([tx1, tx2, tx3])
84
85    def run_test(self):
86        self.node = self.nodes[0]
87        self.node.generate(500+COINBASE_MATURITY)
88        """
89        pragma solidity ^0.4.24;
90        contract Ballot {
91            function() payable public {
92                while(true){}
93            }
94        }
95        """
96        bytecode = "6080604052348015600f57600080fd5b50603d80601d6000396000f30060806040525b600115600f576005565b0000a165627a7a72305820046fe704d7206dd7bd828449504709b4786e72b5b8cb47633add96fec4d343410029"
97        self.contract_address = self.node.createcontract(bytecode)['address']
98        self.node.generate(1)
99        self.too_few_txs_test()
100        self.different_but_same_number_aal_txs_test()
101        self.too_many_txs_test()
102
103if __name__ == '__main__':
104    QtumDivergenceDosTest().main()
105