Exemple #1
0
    def generate_test_instance(self, pubkeystring, scriptsigstring):

        chainHeight = self.nodes[0].getblockcount()
        t_now = int(time.time())
        print "Called at height = {}, delta_t = {}".format(
            chainHeight,
            (t_now + MAX_FUTURE_BLOCK_TIME_LOCAL - self.block_time))
        if self.block_time > (t_now + MAX_FUTURE_BLOCK_TIME_LOCAL - 100):
            delta = self.block_time - t_now - MAX_FUTURE_BLOCK_TIME_LOCAL + 100
            print "\n...waiting {} secs not to overtake node time --------------\n".format(
                delta)
            time.sleep(delta)

        scriptpubkey = ParseScript(pubkeystring)
        scriptsig = ParseScript(scriptsigstring)

        test = TestInstance(sync_every_block=False)
        test_build = TestBuilder()
        test_build.create_credit_tx(scriptpubkey, chainHeight + 1)
        test_build.create_spend_tx(scriptsig)
        test_build.rehash()

        block = create_block(self.tip, test_build.tx1, self.block_time,
                             get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block.solve()
        self.tip = block.sha256
        test.blocks_and_transactions = [[block, True]]

        for i in xrange(100):
            block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                                 self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            self.block_time += 1
            block.solve()
            self.tip = block.sha256
            test.blocks_and_transactions.append([block, True])
            if ((i + 1) % 10) == 0:
                print "... {} blocks created".format(i + 1)

        block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                             self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block.vtx.append(test_build.tx2)
        block.hashMerkleRoot = block.calc_merkle_root()
        block.rehash()
        block.solve()
        test.blocks_and_transactions.append([block, None])
        return test
Exemple #2
0
    def get_tests(self):
        self.tip = int("0x" + self.nodes[0].getbestblockhash() + "L", 0)
        #self.block_time = 1333230000  # before the BIP16 switchover

        # We had better start from old times otherwise we will overtake node current time with block timing sooner or later
        # But can not be too old a time (i.e genesis) otherwise the node goes in IBD state and does not inv anything

        self.block_time = int(time.time()) - MAX_TIP_AGE + 100
        chainHeight = 0
        '''
        Create a new block with an anyone-can-spend coinbase
        '''
        block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                             self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block.solve()
        self.tip = block.sha256
        yield TestInstance(objects=[[block, True]])
        '''
        Build out to 100 blocks total, maturing the coinbase.
        '''
        test = TestInstance(objects=[],
                            sync_every_block=False,
                            sync_every_tx=False)
        for i in xrange(100):
            b = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                             self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            b.solve()
            test.blocks_and_transactions.append([b, True])
            self.tip = b.sha256
            self.block_time += 1
            if ((i + 1) % 10) == 0:
                print "... {} blocks created".format(i + 1)
        yield test
        ''' Iterate through script tests. '''
        print "Iterate through script tests..."
        counter = 0
        for script_test in self.scripts.get_records():

            print "{}) blockchain (h={}) ".format(
                counter, self.nodes[0].getblockcount())

            assert (
                self.nodes[0].getblockcount() == self.nodes[1].getblockcount())

            # can not invalidate more than 100 blocks ---> assert hit
            #if bcnt > 101:
            #    self.nodes[0].invalidateblock(self.nodes[0].getblockhash(102))
            #    self.nodes[1].invalidateblock(self.nodes[1].getblockhash(102))

            self.tip = int("0x" + self.nodes[0].getbestblockhash() + "L", 0)

            [scriptsig, scriptpubkey, flags] = script_test[0:3]
            flags = ParseScriptFlags(flags)

            # We can use block time to determine whether the nodes should be
            # enforcing BIP16.
            #
            # We intentionally let the block time grow by 1 each time.
            # This forces the block hashes to differ between tests, so that
            # a call to invalidateblock doesn't interfere with a later test.
            #if (flags & SCRIPT_VERIFY_P2SH):
            #    self.block_time = 1333238400 + counter # Advance to enforcing BIP16
            #else:
            #    self.block_time = 1333230000 + counter # Before the BIP16 switchover

            print "Script test: [%s]" % script_test

            yield self.generate_test_instance(scriptpubkey, scriptsig)
            counter += 1
Exemple #3
0
 def create_credit_tx(self, scriptPubKey, height):
     # self.tx1 is a coinbase transaction, modeled after the one created by script_tests.cpp
     # This allows us to reuse signatures created in the unit test framework.
     self.tx1 = create_coinbase_h(height)
     self.tx1.vout[0].scriptPubKey = scriptPubKey
     self.tx1.rehash()
Exemple #4
0
    def get_tests(self):
        if self.tip is None:
            self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
        self.block_time = int(time.time())+1

        chainHeight = 0

        '''
        Create a new block with an anyone-can-spend coinbase
        '''
        block = create_block(self.tip, create_coinbase_h(chainHeight+1), self.block_time)
        chainHeight += 1
        self.block_time += 1
        block.solve()
        # Save the coinbase for later
        self.block1 = block
        self.tip = block.sha256
        yield TestInstance([[block, True]])

        '''
        Now we need that block to mature so we can spend the coinbase.
        '''
        test = TestInstance(sync_every_block=False)
        for i in xrange(100):
            block = create_block(self.tip, create_coinbase_h(chainHeight+1), self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            block.solve()
            self.tip = block.sha256
            self.block_time += 1
            test.blocks_and_transactions.append([block, True])
        yield test

        '''
        Now we use merkle-root malleability to generate an invalid block with
        same blockheader.
        Manufacture a block with 3 transactions (coinbase, spend of prior
        coinbase, spend of that spend).  Duplicate the 3rd transaction to 
        leave merkle root and blockheader unchanged but invalidate the block.
        '''
        block2 = create_block(self.tip, create_coinbase_h(chainHeight+1), self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1

        # chr(81) is OP_TRUE
        tx1 = create_transaction(self.block1.vtx[0], 0, chr(81), 4*100000000)
        tx2 = create_transaction(tx1, 0, chr(81), 4*100000000)

        block2.vtx.extend([tx1, tx2])
        block2.hashMerkleRoot = block2.calc_merkle_root()
        block2.rehash()
        block2.solve()
        orig_hash = block2.sha256
        block2_orig = copy.deepcopy(block2)

        # Mutate block 2
        block2.vtx.append(tx2)
        assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root())
        assert_equal(orig_hash, block2.rehash())
        assert(block2_orig.vtx != block2.vtx)

        self.tip = block2.sha256
        yield TestInstance([[block2, False], [block2_orig, True]])

        '''
        Make sure that a totally screwed up block is not valid.
        '''
        block3 = create_block(self.tip, create_coinbase_h(chainHeight+1), self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block3.vtx[0].vout[0].nValue = 100*100000000 # Too high!
        block3.vtx[0].sha256=None
        block3.vtx[0].calc_sha256()
        block3.hashMerkleRoot = block3.calc_merkle_root()
        block3.rehash()
        block3.solve()

        yield TestInstance([[block3, False]])
Exemple #5
0
    def get_tests(self):
        if self.tip is None:
            self.tip = int("0x" + self.nodes[0].getbestblockhash() + "L", 0)
        self.block_time = int(time.time()) + 1

        chainHeight = 0

        def get_chaintip_subsidy_amount():
            best_hash = self.nodes[0].getbestblockhash()
            cb_txid = self.nodes[0].getblock(best_hash)['tx'][0]
            cb_tx = self.nodes[0].getrawtransaction(cb_txid, 1)
            subsidy = Decimal("0.0")
            for x in cb_tx['vout']:
                subsidy += x['value']
            print " CB amount = {}".format(subsidy)
            return subsidy

        print "---> Create a new block with an anyone-can-spend coinbase"

        block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                             self.block_time)
        chainHeight += 1
        self.block_time += 1
        block.solve()
        # Save the coinbase for later
        self.block1 = block
        self.tip = block.sha256
        yield TestInstance([[block, True]])

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        cb_subsidy_pre_halving = get_chaintip_subsidy_amount()

        test = TestInstance(sync_every_block=False)
        print "---> We need that block to mature so we can spend the coinbase: creating 100 blocks"

        test = TestInstance(sync_every_block=False)
        for i in xrange(100):
            block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                                 self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            block.solve()
            self.tip = block.sha256
            self.block_time += 1
            test.blocks_and_transactions.append([block, True])
            if ((i + 1) % 10) == 0:
                print "... {} blocks created".format(i + 1)
        yield test

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        print "---> Go beyond the fork that introduces other shares of coinbase for supernodes/securenodes, that is h=105 in regtest."

        test = TestInstance(sync_every_block=False)
        for i in xrange(10):
            block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                                 self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            block.solve()
            self.tip = block.sha256
            self.block_time += 1
            test.blocks_and_transactions.append([block, True])
            if ((i + 1) % 10) == 0:
                print "... {} blocks created".format(i + 1)
        yield test

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        print "---> Now we go beyond the next fork point setting a new subsidy share distribution"

        test = TestInstance(sync_every_block=False)
        for i in xrange(100):
            block = create_block(self.tip, create_coinbase_h(chainHeight + 1),
                                 self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            block.solve()
            self.tip = block.sha256
            self.block_time += 1
            test.blocks_and_transactions.append([block, True])
            if ((i + 1) % 10) == 0:
                print "... {} blocks created".format(i + 1)
        yield test

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        print "---> Now we go at the brink of the halving height (set to {})".format(
            SUBS_HALV_INTERVAL)
        test = TestInstance(sync_every_block=False)
        num_of_bl = SUBS_HALV_INTERVAL - self.nodes[0].getblockcount() - 1
        for i in xrange(num_of_bl):
            block = create_block(
                self.tip, create_coinbase_h(chainHeight + 1,
                                            SUBS_HALV_INTERVAL),
                self.block_time, get_nBits(chainHeight))
            chainHeight += 1
            block.solve()
            #print " {}) block.nBits = {}".format(i, block.nBits)
            self.tip = block.sha256
            self.block_time += 1
            test.blocks_and_transactions.append([block, True])
            if ((i + 1) % 10) == 0:
                print "... {} blocks created".format(i + 1)
        yield test

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        # check we still have full cb subsidy
        cb_subsidy = get_chaintip_subsidy_amount()
        assert_equal(cb_subsidy, cb_subsidy_pre_halving)

        print "---> Make sure that a block with pre-halving subsidy is rejected."
        block3 = create_block(
            self.tip,
            create_coinbase_h(
                chainHeight + 1,
                SUBS_HALV_INTERVAL + 1  #force not trigger halving
            ),
            self.block_time,
            get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block3.solve()

        yield TestInstance([[block3, False]])

        assert_equal(self.nodes[0].getblockcount(), chainHeight - 1)
        chainHeight -= 1

        print "---> Make sure that a block with too high a miner rewarding after halving is rejected."
        block3 = create_block(
            self.tip, create_coinbase_h(chainHeight + 1, SUBS_HALV_INTERVAL),
            self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block3.vtx[0].vout[0].nValue *= 1.5  # Too high!
        block3.vtx[0].sha256 = None
        block3.vtx[0].calc_sha256()
        block3.hashMerkleRoot = block3.calc_merkle_root()
        block3.rehash()
        block3.solve()

        yield TestInstance([[block3, False]])

        assert_equal(self.nodes[0].getblockcount(), chainHeight - 1)
        chainHeight -= 1

        print "---> Make sure that a block with a correctly halved cb is accepted."
        block3 = create_block(
            self.tip, create_coinbase_h(chainHeight + 1, SUBS_HALV_INTERVAL),
            self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block3.solve()
        self.tip = block3.sha256

        yield TestInstance([[block3, True]])

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        # check we have the expected halved cb subsidy
        cb_subsidy_post_halving = get_chaintip_subsidy_amount()
        assert_equal(cb_subsidy_post_halving,
                     cb_subsidy_pre_halving * Decimal("0.5"))

        print "---> Make sure that a block with a miner rewarding less than expected is NOT rejected."
        block3 = create_block(
            self.tip, create_coinbase_h(chainHeight + 1, SUBS_HALV_INTERVAL),
            self.block_time, get_nBits(chainHeight))
        chainHeight += 1
        self.block_time += 1
        block3.vtx[0].vout[0].nValue *= 0.5
        block3.vtx[0].sha256 = None
        block3.vtx[0].calc_sha256()
        block3.hashMerkleRoot = block3.calc_merkle_root()
        block3.rehash()
        block3.solve()
        self.tip = block3.sha256

        yield TestInstance([[block3, True]])

        # check testnode and zend node are synced
        assert_equal(self.nodes[0].getblockcount(), chainHeight)
        assert_equal(int("0x" + self.nodes[0].getbestblockhash(), 0), self.tip)

        # check we have the expected less-than halved cb subsidy
        cb_subsidy = get_chaintip_subsidy_amount()
        assert (cb_subsidy < cb_subsidy_pre_halving * Decimal("0.5"))
Exemple #6
0
    def run_test(self):
        # Setup the p2p connections and start up the network thread.
        test_node = TestNode()  # connects to node0 (not whitelisted)
        white_node = TestNode()  # connects to node1 (whitelisted)

        connections = []
        connections.append(
            NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
        connections.append(
            NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node))
        test_node.add_connection(connections[0])
        white_node.add_connection(connections[1])

        NetworkThread().start()  # Start up network handling in another thread

        # Test logic begins here
        test_node.wait_for_verack()
        white_node.wait_for_verack()

        # 1. Have both nodes mine a block (leave IBD)
        [n.generate(1) for n in self.nodes]
        tips = [int("0x" + n.getbestblockhash() + "L", 0) for n in self.nodes]

        # 2. Send one block that builds on each tip.
        # This should be accepted.
        blocks_h2 = []  # the height 2 blocks on each node's chain
        block_time = time.time() + 1
        for i in xrange(2):
            blocks_h2.append(
                create_block(tips[i], create_coinbase_h(2), block_time))
            blocks_h2[i].solve()
            block_time += 1
        test_node.send_message(msg_block(blocks_h2[0]))
        white_node.send_message(msg_block(blocks_h2[1]))

        [x.sync_with_ping() for x in [test_node, white_node]]
        assert_equal(self.nodes[0].getblockcount(), 2)
        assert_equal(self.nodes[1].getblockcount(), 2)
        print "First height 2 block accepted by both nodes"

        # 3. Send another block that builds on the original tip.
        blocks_h2f = []  # Blocks at height 2 that fork off the main chain
        for i in xrange(2):
            blocks_h2f.append(
                create_block(tips[i], create_coinbase_h(2),
                             blocks_h2[i].nTime + 1))
            blocks_h2f[i].solve()
        test_node.send_message(msg_block(blocks_h2f[0]))
        white_node.send_message(msg_block(blocks_h2f[1]))

        [x.sync_with_ping() for x in [test_node, white_node]]
        for x in self.nodes[0].getchaintips():
            if x['hash'] == blocks_h2f[0].hash:
                assert_equal(x['status'], "headers-only")

        for x in self.nodes[1].getchaintips():
            if x['hash'] == blocks_h2f[1].hash:
                assert_equal(x['status'], "valid-headers")

        print "Second height 2 block accepted only from whitelisted peer"

        # 4. Now send another block that builds on the forking chain.
        blocks_h3 = []
        for i in xrange(2):
            blocks_h3.append(
                create_block(blocks_h2f[i].sha256, create_coinbase_h(3),
                             blocks_h2f[i].nTime + 1))
            blocks_h3[i].solve()
        test_node.send_message(msg_block(blocks_h3[0]))
        white_node.send_message(msg_block(blocks_h3[1]))

        [x.sync_with_ping() for x in [test_node, white_node]]
        # Since the earlier block was not processed by node0, the new block
        # can't be fully validated.
        for x in self.nodes[0].getchaintips():
            if x['hash'] == blocks_h3[0].hash:
                assert_equal(x['status'], "headers-only")

        # But this block should be accepted by node0 since it has more work.
        try:
            self.nodes[0].getblock(blocks_h3[0].hash)
            print "Unrequested more-work block accepted from non-whitelisted peer"
        except:
            raise AssertionError(
                "Unrequested more work block was not processed")

        # Node1 should have accepted and reorged.
        assert_equal(self.nodes[1].getblockcount(), 3)
        print "Successfully reorged to length 3 chain from whitelisted peer"

        # 4b. Now mine 288 more blocks and deliver; all should be processed but
        # the last (height-too-high) on node0.  Node1 should process the tip if
        # we give it the headers chain leading to the tip.
        tips = blocks_h3
        headers_message_1 = msg_headers()
        headers_message_2 = msg_headers()
        all_blocks = []  # node0's blocks
        for j in xrange(2):
            chainHeight = 3
            for i in xrange(288):
                next_block = create_block(tips[j].sha256,
                                          create_coinbase_h(chainHeight + 1),
                                          tips[j].nTime + 1,
                                          get_nBits(chainHeight))
                next_block.solve()
                chainHeight += 1
                if j == 0:
                    test_node.send_message(msg_block(next_block))
                    all_blocks.append(next_block)
                else:
                    # we can not send more than zend::MAX_HEADERS_RESULTS=160 to a zend node
                    if len(headers_message_1.headers) < 160:
                        headers_message_1.headers.append(
                            CBlockHeader(next_block))
                    else:
                        headers_message_2.headers.append(
                            CBlockHeader(next_block))
                tips[j] = next_block
                if ((i + 1) % 10) == 0:
                    print "... {} blocks created".format(i + 1)

        time.sleep(2)
        for x in all_blocks:
            try:
                self.nodes[0].getblock(x.hash)
                if x == all_blocks[287]:
                    raise AssertionError(
                        "Unrequested block too far-ahead should have been ignored"
                    )
            except:
                if x == all_blocks[287]:
                    print "Unrequested block too far-ahead not processed"
                else:
                    raise AssertionError(
                        "Unrequested block with more work should have been accepted"
                    )

        headers_message_2.headers.pop()  # Ensure the last block is unrequested
        white_node.send_message(
            headers_message_1)  # Send headers leading to tip
        white_node.send_message(
            headers_message_2)  # Send headers leading to tip
        white_node.send_message(msg_block(tips[1]))  # Now deliver the tip
        try:
            white_node.sync_with_ping()
            self.nodes[1].getblock(tips[1].hash)
            print "Unrequested block far ahead of tip accepted from whitelisted peer"
        except:
            raise AssertionError(
                "Unrequested block from whitelisted peer not accepted")

        # 5. Test handling of unrequested block on the node that didn't process
        # Should still not be processed (even though it has a child that has more
        # work).
        test_node.send_message(msg_block(blocks_h2f[0]))

        # Here, if the sleep is too short, the test could falsely succeed (if the
        # node hasn't processed the block by the time the sleep returns, and then
        # the node processes it and incorrectly advances the tip).
        # But this would be caught later on, when we verify that an inv triggers
        # a getdata request for this block.
        test_node.sync_with_ping()
        assert_equal(self.nodes[0].getblockcount(), 2)
        print "Unrequested block that would complete more-work chain was ignored"

        # 6. Try to get node to request the missing block.
        # Poke the node with an inv for block at height 3 and see if that
        # triggers a getdata on block 2 (it should if block 2 is missing).
        with mininode_lock:
            # Clear state so we can check the getdata request
            test_node.last_getdata = None
            test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))

        test_node.sync_with_ping()
        with mininode_lock:
            getdata = test_node.last_getdata

        # Check that the getdata includes the right block
        assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
        print "Inv at tip triggered getdata for unprocessed block"

        # 7. Send the missing block for the third time (now it is requested)
        test_node.send_message(msg_block(blocks_h2f[0]))

        test_node.sync_with_ping()
        assert_equal(self.nodes[0].getblockcount(), 290)
        print "Successfully reorged to longer chain from non-whitelisted peer"

        [c.disconnect_node() for c in connections]