Beispiel #1
0
    def create_and_sign_tx(self, node, in_count, out_count, in_size, out_size,
                           min_confirmations, spam):

        utx = self.create_utxos_value100000(node, in_count, in_size,
                                            min_confirmations)
        sum_values_sats = 0
        assert (len(utx.vout) == in_count)
        tx = CTransaction()
        for i in range(in_count):
            u = utx.vout[i]
            sum_values_sats = sum_values_sats + u.nValue
            tx.vin.append(
                CTxIn(
                    COutPoint(
                        uint256_from_str(hex_str_to_bytes(utx.hash)[::-1]), i),
                    b''))

            flags = bytes(
                bytearray(
                    [SIGHASH_NONE | SIGHASH_ANYONECANPAY | SIGHASH_FORKID]))
            adjust = len(
                bytes_to_hex_str(flags)) + 1  # plus one for one OP_HOP

            while True:
                scriptSig = CScript(
                    [bytes(bytearray([OP_NOP]) * (spam - adjust)) + flags])
                tx.vin[-1].scriptSig = scriptSig

                if len(scriptSig) > spam:
                    adjust = adjust + 1
                    continue
                elif len(scriptSig) < spam:
                    adjust = adjust - 1
                    continue

                break

        assert (len(tx.vin) == in_count)

        x = out_size // out_count
        x_rest = out_size % out_count

        check_size = 0

        for i in range(out_count):

            if i == out_count - 1:
                x = x_rest + x

            scriptPubKey = CScript([OP_NOP] * (x - 1) + [OP_TRUE])
            check_size = check_size + len(scriptPubKey)

            amount = sum_values_sats // (out_count - i)
            tx.vout.append(CTxOut(amount, scriptPubKey))
            sum_values_sats = sum_values_sats - amount

        assert (check_size == out_size)
        tx.rehash()
        return ToHex(tx)
Beispiel #2
0
    def gbt_submitblock(self, nu5_active):
        node = self.node
        mempool_tx_list = node.getrawmempool()

        gbt = node.getblocktemplate()

        # make sure no transactions were left out (or added)
        assert_equal(len(mempool_tx_list), len(gbt['transactions']))
        assert_equal(set(mempool_tx_list), set([tx['hash'] for tx in gbt['transactions']]))

        prevhash = int(gbt['previousblockhash'], 16)
        nTime = gbt['mintime']
        nBits = int(gbt['bits'], 16)

        if nu5_active:
            blockcommitmentshash = int(gbt['defaultroots']['blockcommitmentshash'], 16)
        else:
            blockcommitmentshash = int(gbt['defaultroots']['chainhistoryroot'], 16)
            assert 'blockcommitmentshash' not in gbt['defaultroots']
        # Confirm that the legacy fields match this default value.
        assert_equal(blockcommitmentshash, int(gbt['blockcommitmentshash'], 16))
        assert_equal(blockcommitmentshash, int(gbt['lightclientroothash'], 16))
        assert_equal(blockcommitmentshash, int(gbt['finalsaplingroothash'], 16))

        f = BytesIO(hex_str_to_bytes(gbt['coinbasetxn']['data']))
        coinbase = CTransaction()
        coinbase.deserialize(f)
        coinbase.calc_sha256()
        assert_equal(coinbase.hash, gbt['coinbasetxn']['hash'])
        assert_equal(coinbase.auth_digest_hex, gbt['coinbasetxn']['authdigest'])

        block = create_block(prevhash, coinbase, nTime, nBits, blockcommitmentshash)

        # copy the non-coinbase transactions from the block template to the block
        for gbt_tx in gbt['transactions']:
            f = BytesIO(hex_str_to_bytes(gbt_tx['data']))
            tx = CTransaction()
            tx.deserialize(f)
            tx.calc_sha256()
            assert_equal(tx.auth_digest_hex, node.getrawtransaction(tx.hash, 1)['authdigest'])
            block.vtx.append(tx)
        block.hashMerkleRoot = int(gbt['defaultroots']['merkleroot'], 16)
        assert_equal(block.hashMerkleRoot, block.calc_merkle_root(), "merkleroot")
        assert_equal(len(block.vtx), len(gbt['transactions']) + 1, "number of transactions")
        assert_equal(block.hashPrevBlock, int(gbt['previousblockhash'], 16), "prevhash")
        if nu5_active:
            assert_equal(uint256_from_str(block.calc_auth_data_root()), int(gbt['defaultroots']['authdataroot'], 16))
        else:
            assert 'authdataroot' not in gbt['defaultroots']
        block.solve()
        block.calc_sha256()

        submitblock_reply = node.submitblock(codecs.encode(block.serialize(), 'hex_codec'))
        assert_equal(None, submitblock_reply)
        assert_equal(block.hash, node.getbestblockhash())
        # Wait until the wallet has been notified of all blocks, so that it doesn't try to
        # double-spend transparent coins in subsequent test phases.
        self.sync_all()
Beispiel #3
0
def SignatureHashForkId(script, txTo, inIdx, hashtype, amount):

    hashPrevouts = 0
    hashSequence = 0
    hashOutputs = 0

    if not (hashtype & SIGHASH_ANYONECANPAY):
        serialize_prevouts = bytes()
        for i in txTo.vin:
            serialize_prevouts += i.prevout.serialize()
        hashPrevouts = uint256_from_str(hash256(serialize_prevouts))

    if (not (hashtype & SIGHASH_ANYONECANPAY)
            and (hashtype & 0x1f) != SIGHASH_SINGLE
            and (hashtype & 0x1f) != SIGHASH_NONE):
        serialize_sequence = bytes()
        for i in txTo.vin:
            serialize_sequence += struct.pack("<I", i.nSequence)
        hashSequence = uint256_from_str(hash256(serialize_sequence))

    if ((hashtype & 0x1f) != SIGHASH_SINGLE
            and (hashtype & 0x1f) != SIGHASH_NONE):
        serialize_outputs = bytes()
        for o in txTo.vout:
            serialize_outputs += o.serialize()
        hashOutputs = uint256_from_str(hash256(serialize_outputs))
    elif ((hashtype & 0x1f) == SIGHASH_SINGLE and inIdx < len(txTo.vout)):
        serialize_outputs = txTo.vout[inIdx].serialize()
        hashOutputs = uint256_from_str(hash256(serialize_outputs))

    ss = bytes()
    ss += struct.pack("<i", txTo.nVersion)
    ss += ser_uint256(hashPrevouts)
    ss += ser_uint256(hashSequence)
    ss += txTo.vin[inIdx].prevout.serialize()
    ss += ser_string(script)
    ss += struct.pack("<q", amount)
    ss += struct.pack("<I", txTo.vin[inIdx].nSequence)
    ss += ser_uint256(hashOutputs)
    ss += struct.pack("<i", txTo.nLockTime)
    ss += struct.pack("<I", hashtype)

    return hash256(ss)
Beispiel #4
0
    def run_test(self):
        # Set up test nodes.
        # - test_nodes[0] will only request v4 transactions
        # - test_nodes[1] will only request v5 transactions
        # - test_nodes[2] will test invalid v4 request using MSG_WTXID
        # - test_nodes[3] will test invalid v5 request using MSG_TX
        test_nodes = []
        connections = []

        for i in range(4):
            test_nodes.append(TestNode())
            connections.append(
                NodeConn('127.0.0.1',
                         p2p_port(0),
                         self.nodes[0],
                         test_nodes[i],
                         protocol_version=NU5_PROTO_VERSION))
            test_nodes[i].add_connection(connections[i])

        NetworkThread().start()  # Start up network handling in another thread
        [x.wait_for_verack() for x in test_nodes]

        net_version = self.nodes[0].getnetworkinfo()["protocolversion"]
        if net_version < NU5_PROTO_VERSION:
            # Sending a getdata message containing a MSG_WTX CInv message type
            # results in a reject message.
            self.verify_invalid_cinv(
                test_nodes[0],
                connections[0],
                5,
                "Negotiated protocol version does not support CInv message type MSG_WTX",
            )

            # Sending a getdata message containing an invalid CInv message type
            # results in a reject message.
            self.verify_invalid_cinv(test_nodes[1], connections[1], 0xffff,
                                     "Unknown CInv message type")

            print(
                "Node's block index is not NU5-aware, skipping remaining tests"
            )
            return

        # Load funds into the Sprout address
        sproutzaddr = self.nodes[0].z_getnewaddress('sprout')
        result = self.nodes[2].z_shieldcoinbase("*", sproutzaddr, 0)
        wait_and_assert_operationid_status(self.nodes[2], result['opid'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Activate NU5. Block height after this is 210.
        self.nodes[0].generate(9)
        self.sync_all()

        # Add v4 transaction to the mempool.
        node1_taddr = self.nodes[1].getnewaddress()
        opid = self.nodes[0].z_sendmany(sproutzaddr, [{
            'address': node1_taddr,
            'amount': 1,
        }])
        v4_txid = uint256_from_str(
            hex_str_to_bytes(
                wait_and_assert_operationid_status(self.nodes[0], opid))[::-1])

        # Add v5 transaction to the mempool.
        v5_txid = self.nodes[0].sendtoaddress(node1_taddr, 1, "", "", True)
        v5_tx = self.nodes[0].getrawtransaction(v5_txid, 1)
        assert_equal(v5_tx['version'], 5)
        v5_txid = uint256_from_str(hex_str_to_bytes(v5_txid)[::-1])
        v5_auth_digest = uint256_from_str(
            hex_str_to_bytes(v5_tx['authdigest'])[::-1])

        # Wait for the mempools to sync.
        self.sync_all()

        #
        # inv
        #

        # On a mempool request, nodes should return an inv message containing:
        # - the v4 tx, with type MSG_TX.
        # - the v5 tx, with type MSG_WTX.
        for testnode in test_nodes:
            self.verify_inv(testnode, [
                self.cinv_for(v4_txid),
                self.cinv_for(v5_txid, v5_auth_digest),
            ])

        #
        # getdata
        #

        # We can request a v4 transaction with MSG_TX.
        self.send_data_message(test_nodes[0], v4_txid)
        self.verify_last_tx(test_nodes[0], v4_txid)

        # We can request a v5 transaction with MSG_WTX.
        self.send_data_message(test_nodes[1], v5_txid, v5_auth_digest)
        self.verify_last_tx(test_nodes[1], v5_txid, v5_auth_digest)

        # Requesting with a different authDigest results in a notfound.
        self.send_data_message(test_nodes[1], v5_txid, 1)
        self.verify_last_notfound(test_nodes[1], v5_txid, 1)

        # Requesting a v4 transaction with MSG_WTX causes a disconnect.
        self.send_data_message(test_nodes[2], v4_txid, (1 << 256) - 1)
        self.verify_disconnected(test_nodes[2])

        # Requesting a v5 transaction with MSG_TX causes a disconnect.
        self.send_data_message(test_nodes[3], v5_txid)
        self.verify_disconnected(test_nodes[3])

        # Sending a getdata message containing an invalid CInv message type
        # results in a reject message.
        self.verify_invalid_cinv(test_nodes[0], connections[0], 0xffff,
                                 "Unknown CInv message type")

        [c.disconnect_node() for c in connections]
        self.log_stderr.close()
block.rehash()

# Get the difficulty on the BStash chain
hex_bits = aux['bits']
nBits = struct.unpack(">I", hex_str_to_bytes(hex_bits))[0]
target = uint256_from_compact(nBits)

# Construct BCash block
block_ser = b""
block_ser += struct.pack("<i", block.nVersion)
block_ser += ser_uint256(block.hashPrevBlock)
block_ser += ser_uint256(block.hashMerkleRoot)
block_ser += struct.pack("<I", block.nTime)
block_ser += struct.pack("<I", block.nBits)
block_ser_final = block_ser + struct.pack("<I", block.nNonce)
hash_result = uint256_from_str(hash256(block_ser_final))

print("Starting mining, difficulty:{}".format(hex_bits))
i = 0
start_time = time.time()
maxnonce = 2**32
block.nNonce = 0
nNonce = 0
while hash_result > target:
    nNonce += 1
    if nNonce >= maxnonce:
        print("Finished mining:{} per sec".format(nNonce /
                                                  (time.time() - start_time)))
        sys.exit()
    hash_result = uint256_from_str(
        hash256(block_ser + struct.pack("<I", nNonce)))
Beispiel #6
0
    def create_utxos_value100000(self, node, utxo_count, utxo_size,
                                 min_confirmations):

        utxos = []
        addr = node.getnewaddress()

        # create some confirmed UTXOs
        for i in range(utxo_count):
            txid = node.sendtoaddress(addr, self.utxo_test_bsvs)
            tx = FromHex(CTransaction(), node.getrawtransaction(txid))
            tx.rehash()
            utxos.append(tx)

        node.generate(1)

        # Convert those utxos to new UTXO's in one single transaction that anyone can spend
        tx = None
        fee = 0

        for _ in range(2):  # firs iteration is to calculate the fee
            tx = CTransaction()
            amount = self.utxo_test_sats
            check_size = 0
            for u in utxos:

                # Each UTXO will have two outputs, one for change and another one
                # amounting to roughly 10000 satoshis
                for i in range(len(u.vout)):
                    uu = u.vout[i]
                    if uu.nValue <= self.utxo_test_sats and uu.nValue > self.utxo_test_sats // 2:
                        tx.vin.append(
                            CTxIn(
                                COutPoint(
                                    uint256_from_str(
                                        hex_str_to_bytes(u.hash)[::-1]), i),
                                b''))
                        break

                adjust = 2
                scriptPubKey = CScript([OP_DROP] +
                                       ([OP_NOP] *
                                        ((utxo_size // utxo_count) - adjust)) +
                                       [OP_TRUE])

                if len(tx.vin) == utxo_count:
                    amount = amount - fee

                    while True:
                        scriptPubKey = CScript([OP_DROP] + ([OP_NOP] * (
                            (utxo_size // utxo_count) - adjust)) + [OP_TRUE])

                        if check_size + len(scriptPubKey) > utxo_size:
                            adjust = adjust + 1
                            continue
                        elif check_size + len(scriptPubKey) < utxo_size:
                            adjust = adjust - 1
                            continue
                        break

                check_size = check_size + len(scriptPubKey)
                tx.vout.append(CTxOut(amount, scriptPubKey))

            assert (len(tx.vout) == utxo_count)
            assert (check_size == utxo_size)

            # sign and send transaction
            txHex = node.signrawtransaction(ToHex(tx))['hex']
            tx = FromHex(CTransaction(), txHex)
            tx.rehash()
            tx_size = len(ToHex(tx))
            fee = int(self.blockmintxfee_sats * tx_size / 1000)

        node.sendrawtransaction(ToHex(tx))

        if min_confirmations > 0:
            node.generate(min_confirmations)

        return tx