Beispiel #1
0
 def add_output_to_coinstake(self, block, value, peer=1):
     coinstake = block.vtx[1]
     if not hasattr(self, 'DUMMY_KEY'):
         self.init_dummy_key()
     coinstake.vout.append(
         CTxOut(value * COIN, CScript([self.DUMMY_KEY.get_pubkey(), OP_CHECKSIG])))
     coinstake.vout[1].nValue -= value * COIN
     # re-sign coinstake
     prevout = COutPoint()
     prevout.deserialize_uniqueness(BytesIO(block.prevoutStake))
     coinstake.vin[0] = CTxIn(prevout)
     stake_tx_signed_raw_hex = self.nodes[peer].signrawtransaction(
         bytes_to_hex_str(coinstake.serialize()))['hex']
     block.vtx[1] = CTransaction()
     block.vtx[1].from_hex(stake_tx_signed_raw_hex)
     # re-sign block
     block.hashMerkleRoot = block.calc_merkle_root()
     block.rehash()
     block.re_sign_block()
Beispiel #2
0
    def fake_stake(self,
                   staking_utxo_list,
                   nHeight=-1,
                   fDoubleSpend=False):
        """ General method to create, send and test the spam blocks
        :param    staking_utxo_list:  (string list) utxos to use for staking
                  nHeight:            (int, optional) height of the staked block.
                                        Used only for fork chain. In main chain it's current height + 1
                  fDoubleSpend:       (bool) if true, stake input is double spent in block.vtx
        :return:
        """
        def get_prev_modifier(prevBlockHash):
            prevBlock = self.nodes[1].getblock(prevBlockHash)
            if prevBlock['height'] > 250:
                return prevBlock['stakeModifier']
            return "0"

        # Get block number, block time and prevBlock hash and modifier
        currHeight = self.nodes[1].getblockcount()
        isMainChain = (nHeight == -1)
        chainName = "main" if isMainChain else "forked"
        nTime = self.mocktime
        if isMainChain:
            nHeight = currHeight + 1
        prevBlockHash = self.nodes[1].getblockhash(nHeight - 1)
        prevModifier = get_prev_modifier(prevBlockHash)
        nTime += (nHeight - currHeight) * 60

        # New block hash, coinstake input and list of txes
        bHash = None
        stakedUtxo = None

        # For each test, send three blocks.
        # On main chain they are all the same height.
        # On fork chain, send three blocks where both the second and third block sent,
        # are built on top of the first one.
        for i in range(3):
            fMustBeAccepted = (not isMainChain and i != 1)
            block_txes = []

            # update block number and prevBlock hash on second block sent on forked chain
            if not isMainChain and i == 1:
                nHeight += 1
                nTime += 60
                prevBlockHash = bHash
                prevModifier = get_prev_modifier(prevBlockHash)

            stakeInputs = self.get_prevouts(1, staking_utxo_list, False, nHeight - 1)
            # Update stake inputs for second block sent on forked chain (must stake the same input)
            if not isMainChain and i == 1:
                stakeInputs = self.get_prevouts(1, [stakedUtxo], False, nHeight-1)

            # Make spam txes sending the inputs to DUMMY_KEY in order to test double spends
            if fDoubleSpend:
                spending_prevouts = self.get_prevouts(1, staking_utxo_list)
                block_txes = self.make_txes(1, spending_prevouts, self.DUMMY_KEY.get_pubkey())

            # Stake the spam block
            block = self.stake_block(1, 7, nHeight, prevBlockHash, prevModifier, "0", stakeInputs,
                                     nTime, "", block_txes, fDoubleSpend)
            # Log stake input
            prevout = COutPoint()
            prevout.deserialize_uniqueness(BytesIO(block.prevoutStake))
            self.log.info("Staked input: [%s...-%s]" % ('{:x}'.format(prevout.hash)[:12], prevout.n))

            # Try submitblock and check result
            self.log.info("Trying to send block [%s...] with height=%d" % (block.hash[:16], nHeight))
            var = self.nodes[1].submitblock(bytes_to_hex_str(block.serialize()))
            sleep(1)
            if (not fMustBeAccepted and var not in [None, "rejected"]):
                raise AssertionError("Error, block submitted (%s) in %s chain" % (var, chainName))
            elif (fMustBeAccepted and var != "inconclusive"):
                raise AssertionError("Error, block not submitted (%s) in %s chain" % (var, chainName))
            self.log.info("Done. Updating context...")

            # Sync and check block hash
            bHash = block.hash
            self.checkBlockHash(bHash, fMustBeAccepted)

            # Update curr block data
            stakedUtxo = [x for x in staking_utxo_list if COutPoint(
                int(x['txid'], 16), x['vout']).serialize_uniqueness() == block.prevoutStake][0]

            # Remove the used coinstake input (except before second block on fork chain)
            if isMainChain or i != 0:
                staking_utxo_list.remove(stakedUtxo)

        self.log.info("All blocks sent")