コード例 #1
0
ファイル: interface_zmq_grana.py プロジェクト: granapay/grana
 def validate_recovered_sig(request_id, msg_hash):
     # Make sure the recovered sig exists by RPC
     rpc_recovered_sig = self.get_recovered_sig(request_id, msg_hash)
     # Validate hashrecoveredsig
     zmq_recovered_sig_hash = bytes_to_hex_str(self.receive(ZMQPublisher.hash_recovered_sig).read(32))
     assert_equal(zmq_recovered_sig_hash, msg_hash)
     # Validate rawrecoveredsig
     zmq_recovered_sig_raw = CRecoveredSig()
     zmq_recovered_sig_raw.deserialize(self.receive(ZMQPublisher.raw_recovered_sig))
     assert_equal(zmq_recovered_sig_raw.llmqType, rpc_recovered_sig['llmqType'])
     assert_equal(uint256_to_string(zmq_recovered_sig_raw.quorumHash), rpc_recovered_sig['quorumHash'])
     assert_equal(uint256_to_string(zmq_recovered_sig_raw.id), rpc_recovered_sig['id'])
     assert_equal(uint256_to_string(zmq_recovered_sig_raw.msgHash), rpc_recovered_sig['msgHash'])
     assert_equal(bytes_to_hex_str(zmq_recovered_sig_raw.sig), rpc_recovered_sig['sig'])
コード例 #2
0
    def test_recovered_signature_publishers(self):
        def validate_recovered_sig(request_id, msg_hash):
            # Make sure the recovered sig exists by RPC
            rpc_recovered_sig = self.get_recovered_sig(request_id, msg_hash)
            # Validate hashrecoveredsig
            zmq_recovered_sig_hash = bytes_to_hex_str(
                self.receive(ZMQPublisher.hash_recovered_sig).read(32))
            assert_equal(zmq_recovered_sig_hash, msg_hash)
            # Validate rawrecoveredsig
            zmq_recovered_sig_raw = CRecoveredSig()
            zmq_recovered_sig_raw.deserialize(
                self.receive(ZMQPublisher.raw_recovered_sig))
            assert_equal(zmq_recovered_sig_raw.llmqType,
                         rpc_recovered_sig['llmqType'])
            assert_equal(uint256_to_string(zmq_recovered_sig_raw.quorumHash),
                         rpc_recovered_sig['quorumHash'])
            assert_equal(uint256_to_string(zmq_recovered_sig_raw.id),
                         rpc_recovered_sig['id'])
            assert_equal(uint256_to_string(zmq_recovered_sig_raw.msgHash),
                         rpc_recovered_sig['msgHash'])
            assert_equal(bytes_to_hex_str(zmq_recovered_sig_raw.sig),
                         rpc_recovered_sig['sig'])

        recovered_sig_publishers = [
            ZMQPublisher.hash_recovered_sig, ZMQPublisher.raw_recovered_sig
        ]
        self.log.info("Testing %d recovered signature publishers" %
                      len(recovered_sig_publishers))
        # Subscribe to recovered signature messages
        self.subscribe(recovered_sig_publishers)
        # Generate a ChainLock and make sure this leads to valid recovered sig ZMQ messages
        rpc_last_block_hash = self.nodes[0].generate(1)[0]
        self.wait_for_chainlocked_block_all_nodes(rpc_last_block_hash)
        height = self.nodes[0].getblockcount()
        rpc_request_id = hash256(
            ser_string(b"clsig") + struct.pack("<I", height))[::-1].hex()
        validate_recovered_sig(rpc_request_id, rpc_last_block_hash)
        # Sign an arbitrary and make sure this leads to valid recovered sig ZMQ messages
        sign_id = uint256_to_string(random.getrandbits(256))
        sign_msg_hash = uint256_to_string(random.getrandbits(256))
        for mn in self.get_quorum_masternodes(self.quorum_hash):
            mn.node.quorum("sign", self.quorum_type, sign_id, sign_msg_hash)
        validate_recovered_sig(sign_id, sign_msg_hash)
        # Unsubscribe from recovered signature messages
        self.unsubscribe(recovered_sig_publishers)
コード例 #3
0
 def test_chainlock_publishers(self):
     chain_lock_publishers = [
         ZMQPublisher.hash_chain_lock, ZMQPublisher.raw_chain_lock,
         ZMQPublisher.raw_chain_lock_sig
     ]
     self.log.info("Testing %d ChainLock publishers" %
                   len(chain_lock_publishers))
     # Subscribe to ChainLock messages
     self.subscribe(chain_lock_publishers)
     # Generate ChainLock
     generated_hash = self.nodes[0].generate(1)[0]
     self.wait_for_chainlocked_block_all_nodes(generated_hash)
     rpc_best_chain_lock = self.nodes[0].getbestchainlock()
     rpc_best_chain_lock_hash = rpc_best_chain_lock["blockhash"]
     rpc_best_chain_lock_sig = rpc_best_chain_lock["signature"]
     assert_equal(generated_hash, rpc_best_chain_lock_hash)
     rpc_chain_locked_block = self.nodes[0].getblock(
         rpc_best_chain_lock_hash)
     rpc_chain_lock_height = rpc_chain_locked_block["height"]
     rpc_chain_lock_hash = rpc_chain_locked_block["hash"]
     assert_equal(generated_hash, rpc_chain_lock_hash)
     # Validate hashchainlock
     zmq_chain_lock_hash = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_chain_lock).read(32))
     assert_equal(zmq_chain_lock_hash, rpc_best_chain_lock_hash)
     # Validate rawchainlock
     zmq_chain_locked_block = CBlock()
     zmq_chain_locked_block.deserialize(
         self.receive(ZMQPublisher.raw_chain_lock))
     assert (zmq_chain_locked_block.is_valid())
     assert_equal(zmq_chain_locked_block.hash, rpc_chain_lock_hash)
     # Validate rawchainlocksig
     zmq_chain_lock_sig_stream = self.receive(
         ZMQPublisher.raw_chain_lock_sig)
     zmq_chain_locked_block = CBlock()
     zmq_chain_locked_block.deserialize(zmq_chain_lock_sig_stream)
     assert (zmq_chain_locked_block.is_valid())
     zmq_chain_lock = msg_clsig()
     zmq_chain_lock.deserialize(zmq_chain_lock_sig_stream)
     assert_equal(zmq_chain_lock.height, rpc_chain_lock_height)
     assert_equal(uint256_to_string(zmq_chain_lock.blockHash),
                  rpc_chain_lock_hash)
     assert_equal(zmq_chain_locked_block.hash, rpc_chain_lock_hash)
     assert_equal(bytes_to_hex_str(zmq_chain_lock.sig),
                  rpc_best_chain_lock_sig)
     # Unsubscribe from ChainLock messages
     self.unsubscribe(chain_lock_publishers)
コード例 #4
0
    def mine_block(self,
                   node,
                   vtx=[],
                   miner_address=None,
                   mn_payee=None,
                   mn_amount=None,
                   use_mnmerkleroot_from_tip=False,
                   expected_error=None):
        bt = node.getblocktemplate()
        height = bt['height']
        tip_hash = bt['previousblockhash']

        tip_block = node.getblock(tip_hash)

        coinbasevalue = bt['coinbasevalue']
        if miner_address is None:
            miner_address = self.nodes[0].getnewaddress()
        if mn_payee is None:
            if isinstance(bt['masternode'], list):
                mn_payee = bt['masternode'][0]['payee']
            else:
                mn_payee = bt['masternode']['payee']
        # we can't take the masternode payee amount from the template here as we might have additional fees in vtx

        # calculate fees that the block template included (we'll have to remove it from the coinbase as we won't
        # include the template's transactions
        bt_fees = 0
        for tx in bt['transactions']:
            bt_fees += tx['fee']

        new_fees = 0
        for tx in vtx:
            in_value = 0
            out_value = 0
            for txin in tx.vin:
                txout = node.gettxout(uint256_to_string(txin.prevout.hash),
                                      txin.prevout.n, False)
                in_value += int(txout['value'] * COIN)
            for txout in tx.vout:
                out_value += txout.nValue
            new_fees += in_value - out_value

        # fix fees
        coinbasevalue -= bt_fees
        coinbasevalue += new_fees

        if mn_amount is None:
            realloc_info = get_bip9_status(self.nodes[0], 'realloc')
            realloc_height = 99999999
            if realloc_info['status'] == 'active':
                realloc_height = realloc_info['since']
            mn_amount = get_masternode_payment(height, coinbasevalue,
                                               realloc_height)
        miner_amount = coinbasevalue - mn_amount

        outputs = {miner_address: str(Decimal(miner_amount) / COIN)}
        if mn_amount > 0:
            outputs[mn_payee] = str(Decimal(mn_amount) / COIN)

        coinbase = FromHex(CTransaction(),
                           node.createrawtransaction([], outputs))
        coinbase.vin = create_coinbase(height).vin

        # We can't really use this one as it would result in invalid merkle roots for masternode lists
        if len(bt['coinbase_payload']) != 0:
            cbtx = FromHex(CCbTx(version=1), bt['coinbase_payload'])
            if use_mnmerkleroot_from_tip:
                if 'cbTx' in tip_block:
                    cbtx.merkleRootMNList = int(
                        tip_block['cbTx']['merkleRootMNList'], 16)
                else:
                    cbtx.merkleRootMNList = 0
            coinbase.nVersion = 3
            coinbase.nType = 5  # CbTx
            coinbase.vExtraPayload = cbtx.serialize()

        coinbase.calc_sha256()

        block = create_block(int(tip_hash, 16), coinbase)
        block.vtx += vtx

        # Add quorum commitments from template
        for tx in bt['transactions']:
            tx2 = FromHex(CTransaction(), tx['data'])
            if tx2.nType == 6:
                block.vtx.append(tx2)

        block.hashMerkleRoot = block.calc_merkle_root()
        block.solve()
        result = node.submitblock(ToHex(block))
        if expected_error is not None and result != expected_error:
            raise AssertionError(
                'mining the block should have failed with error %s, but submitblock returned %s'
                % (expected_error, result))
        elif expected_error is None and result is not None:
            raise AssertionError('submitblock returned %s' % (result))
コード例 #5
0
 def test_governance_publishers(self):
     governance_publishers = [
         ZMQPublisher.hash_governance_object,
         ZMQPublisher.raw_governance_object,
         ZMQPublisher.hash_governance_vote, ZMQPublisher.raw_governance_vote
     ]
     self.log.info("Testing %d governance publishers" %
                   len(governance_publishers))
     # Subscribe to governance messages
     self.subscribe(governance_publishers)
     # Create a proposal and submit it to the network
     proposal_rev = 1
     proposal_time = int(time.time())
     proposal_data = {
         "type": 1,  # GOVERNANCE_OBJECT_PROPOSAL
         "name": "Test",
         "start_epoch": proposal_time,
         "end_epoch": proposal_time + 60,
         "payment_amount": 5,
         "payment_address": self.nodes[0].getnewaddress(),
         "url": "https://xazab.org"
     }
     proposal_hex = ''.join(
         format(x, '02x') for x in json.dumps(proposal_data).encode())
     collateral = self.nodes[0].gobject("prepare", "0", proposal_rev,
                                        proposal_time, proposal_hex)
     self.wait_for_instantlock(collateral, self.nodes[0])
     self.nodes[0].generate(6)
     self.sync_blocks()
     rpc_proposal_hash = self.nodes[0].gobject("submit", "0", proposal_rev,
                                               proposal_time, proposal_hex,
                                               collateral)
     # Validate hashgovernanceobject
     zmq_governance_object_hash = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_governance_object).read(32))
     assert_equal(zmq_governance_object_hash, rpc_proposal_hash)
     zmq_governance_object_raw = CGovernanceObject()
     zmq_governance_object_raw.deserialize(
         self.receive(ZMQPublisher.raw_governance_object))
     assert_equal(zmq_governance_object_raw.nHashParent, 0)
     assert_equal(zmq_governance_object_raw.nRevision, proposal_rev)
     assert_equal(zmq_governance_object_raw.nTime, proposal_time)
     assert_equal(json.loads(zmq_governance_object_raw.vchData.decode()),
                  proposal_data)
     assert_equal(zmq_governance_object_raw.nObjectType,
                  proposal_data["type"])
     assert_equal(zmq_governance_object_raw.masternodeOutpoint.hash,
                  COutPoint().hash)
     assert_equal(zmq_governance_object_raw.masternodeOutpoint.n,
                  COutPoint().n)
     # Vote for the proposal and validate the governance vote message
     map_vote_outcomes = {0: "none", 1: "yes", 2: "no", 3: "abstain"}
     map_vote_signals = {
         0: "none",
         1: "funding",
         2: "valid",
         3: "delete",
         4: "endorsed"
     }
     self.nodes[0].gobject("vote-many", rpc_proposal_hash,
                           map_vote_signals[1], map_vote_outcomes[1])
     rpc_proposal_votes = self.nodes[0].gobject('getcurrentvotes',
                                                rpc_proposal_hash)
     # Validate hashgovernancevote
     zmq_governance_vote_hash = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_governance_vote).read(32))
     assert (zmq_governance_vote_hash in rpc_proposal_votes)
     # Validate rawgovernancevote
     zmq_governance_vote_raw = CGovernanceVote()
     zmq_governance_vote_raw.deserialize(
         self.receive(ZMQPublisher.raw_governance_vote))
     assert_equal(uint256_to_string(zmq_governance_vote_raw.nParentHash),
                  rpc_proposal_hash)
     rpc_vote_parts = rpc_proposal_votes[zmq_governance_vote_hash].split(
         ':')
     rpc_outpoint_parts = rpc_vote_parts[0].split('-')
     assert_equal(
         uint256_to_string(zmq_governance_vote_raw.masternodeOutpoint.hash),
         rpc_outpoint_parts[0])
     assert_equal(zmq_governance_vote_raw.masternodeOutpoint.n,
                  int(rpc_outpoint_parts[1]))
     assert_equal(zmq_governance_vote_raw.nTime, int(rpc_vote_parts[1]))
     assert_equal(map_vote_outcomes[zmq_governance_vote_raw.nVoteOutcome],
                  rpc_vote_parts[2])
     assert_equal(map_vote_signals[zmq_governance_vote_raw.nVoteSignal],
                  rpc_vote_parts[3])
     # Unsubscribe from governance messages
     self.unsubscribe(governance_publishers)
コード例 #6
0
 def test_instantsend_publishers(self):
     instantsend_publishers = [
         ZMQPublisher.hash_tx_lock, ZMQPublisher.raw_tx_lock,
         ZMQPublisher.raw_tx_lock_sig,
         ZMQPublisher.hash_instantsend_doublespend,
         ZMQPublisher.raw_instantsend_doublespend
     ]
     self.log.info("Testing %d InstantSend publishers" %
                   len(instantsend_publishers))
     # Subscribe to InstantSend messages
     self.subscribe(instantsend_publishers)
     # Initialize test node
     self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
     network_thread_start()
     self.nodes[0].p2p.wait_for_verack()
     # Make sure all nodes agree
     self.wait_for_chainlocked_block_all_nodes(
         self.nodes[0].getbestblockhash())
     # Create two raw TXs, they will conflict with each other
     rpc_raw_tx_1 = self.create_raw_tx(self.nodes[0], self.nodes[0], 1, 1,
                                       100)
     rpc_raw_tx_2 = self.create_raw_tx(self.nodes[0], self.nodes[0], 1, 1,
                                       100)
     # Send the first transaction and wait for the InstantLock
     rpc_raw_tx_1_hash = self.nodes[0].sendrawtransaction(
         rpc_raw_tx_1['hex'])
     self.wait_for_instantlock(rpc_raw_tx_1_hash, self.nodes[0])
     # Validate hashtxlock
     zmq_tx_lock_hash = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_tx_lock).read(32))
     assert_equal(zmq_tx_lock_hash, rpc_raw_tx_1['txid'])
     # Validate rawtxlock
     zmq_tx_lock_raw = CTransaction()
     zmq_tx_lock_raw.deserialize(self.receive(ZMQPublisher.raw_tx_lock))
     assert (zmq_tx_lock_raw.is_valid())
     assert_equal(zmq_tx_lock_raw.hash, rpc_raw_tx_1['txid'])
     # Validate rawtxlocksig
     zmq_tx_lock_sig_stream = self.receive(ZMQPublisher.raw_tx_lock_sig)
     zmq_tx_lock_tx = CTransaction()
     zmq_tx_lock_tx.deserialize(zmq_tx_lock_sig_stream)
     assert (zmq_tx_lock_tx.is_valid())
     assert_equal(zmq_tx_lock_tx.hash, rpc_raw_tx_1['txid'])
     zmq_tx_lock = msg_islock()
     zmq_tx_lock.deserialize(zmq_tx_lock_sig_stream)
     assert_equal(uint256_to_string(zmq_tx_lock.txid), rpc_raw_tx_1['txid'])
     # Try to send the second transaction. This must throw an RPC error because it conflicts with rpc_raw_tx_1
     # which already got the InstantSend lock.
     assert_raises_rpc_error(-26, "tx-txlock-conflict",
                             self.nodes[0].sendrawtransaction,
                             rpc_raw_tx_2['hex'])
     # Validate hashinstantsenddoublespend
     zmq_double_spend_hash2 = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_instantsend_doublespend).read(32))
     zmq_double_spend_hash1 = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_instantsend_doublespend).read(32))
     assert_equal(zmq_double_spend_hash2, rpc_raw_tx_2['txid'])
     assert_equal(zmq_double_spend_hash1, rpc_raw_tx_1['txid'])
     # Validate rawinstantsenddoublespend
     zmq_double_spend_tx_2 = CTransaction()
     zmq_double_spend_tx_2.deserialize(
         self.receive(ZMQPublisher.raw_instantsend_doublespend))
     assert (zmq_double_spend_tx_2.is_valid())
     assert_equal(zmq_double_spend_tx_2.hash, rpc_raw_tx_2['txid'])
     zmq_double_spend_tx_1 = CTransaction()
     zmq_double_spend_tx_1.deserialize(
         self.receive(ZMQPublisher.raw_instantsend_doublespend))
     assert (zmq_double_spend_tx_1.is_valid())
     assert_equal(zmq_double_spend_tx_1.hash, rpc_raw_tx_1['txid'])
     # No islock notifications when tx is not received yet
     self.nodes[0].generate(1)
     rpc_raw_tx_3 = self.create_raw_tx(self.nodes[0], self.nodes[0], 1, 1,
                                       100)
     islock = self.create_islock(rpc_raw_tx_3['hex'])
     self.test_node.send_islock(islock)
     # Validate NO hashtxlock
     time.sleep(1)
     try:
         self.receive(ZMQPublisher.hash_tx_lock, zmq.NOBLOCK)
         assert (False)
     except zmq.ZMQError:
         # this is expected
         pass
     # Now send the tx itself
     self.test_node.send_tx(FromHex(msg_tx(), rpc_raw_tx_3['hex']))
     self.wait_for_instantlock(rpc_raw_tx_3['txid'], self.nodes[0])
     # Validate hashtxlock
     zmq_tx_lock_hash = bytes_to_hex_str(
         self.receive(ZMQPublisher.hash_tx_lock).read(32))
     assert_equal(zmq_tx_lock_hash, rpc_raw_tx_3['txid'])
     # Drop test node connection
     self.nodes[0].disconnect_p2ps()
     # Unsubscribe from InstantSend messages
     self.unsubscribe(instantsend_publishers)