Пример #1
0
    def run_test(self):
        '''
        Create a few SCs specifying related configurations for the custom fields that a cert must set; during
        this phase, different versions of cmd for SC creation are tested.
        Send some certificate with custom fields configured accordingly to the SC they refer.
        Along the test execution, some negative test is also performed.
        JSON representation of scinfo as well as tx/cert are checked for expected contents too.
        '''

        # network topology: (0)--(1)

        # Read the huge bit vector from file
        with open(
                os.path.dirname(os.path.abspath(__file__)) +
                "/../zen/test_data/16_GB_bitvector.bz2", "rb") as f:
            BIT_VECTOR_BUF_HUGE = binascii.hexlify(f.read())

        mark_logs("Node 1 generates 2 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params('sc1')
        constant1 = generate_random_field_element_hex()

        amount = Decimal("1.0")
        fee = 0.000025

        #-------------------------------------------------------
        bad_obj = {"a": 1, "b": 2}
        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'vFieldElementCertificateFieldConfig': bad_obj,
            'toaddress': "abcd",
            'amount': amount,
            'fee': fee,
            'wCertVk': vk
        }

        mark_logs(
            "\nNode 1 create SC with wrong vFieldElementCertificateFieldConfig obj in input (expecting failure...)",
            self.nodes, DEBUG_MODE)
        try:
            self.nodes[1].sc_create(cmdInput)
            assert_true(False)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true("not an array" in errorString)
Пример #2
0
        self.nodes[0].generate(1)
        self.sync_all()

        block = self.nodes[0].getblock('423')
        self.verify_roots(block)

        #Test getblockmerkleroots with a sc-creation
        print("######## Test getblockmerkleroots with a sc-creation ########")

        self.nodes[0].generate(108)
        self.sync_all()

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': 123,
            'toaddress': "dada",
            'amount': 3.0,
            'wCertVk': vk,
            'customData': "bb" * 1024,
            'constant': constant
        }
        ret = self.nodes[0].sc_create(cmdInput)
        scid = ret['scid']
        self.sync_all()
        self.nodes[0].sendtoaddress(tAddr, 1.0)
        self.nodes[0].generate(1)
Пример #3
0
class SCStaleFtAndMbtrTest(BitcoinTestFramework):
    alert_filename = None

    def setup_chain(self, split=False):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)
        self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
        with open(self.alert_filename, 'w'):
            pass  # Just open then close to create zero-length file

    def setup_network(self, split=False):
        self.nodes = []

        extra_args=[
            ['-scproofqueuesize=0', '-logtimemicros=1',
             '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net', '-debug=bench',
             '-blockprioritysize=100',
             '-blockmaxsize=%d'%BLK_MAX_SZ,
             '-blocksforscfeecheck=%d'%NUM_BLOCK_FOR_SC_FEE_CHECK]
        ] * NUMB_OF_NODES

        # override options for 4th miner node, no limits on sizes so it can mine all tx that are in mempool, no matter
        # what fee or prios they have
        extra_args[NUMB_OF_NODES-1]=['-scproofqueuesize=0', '-logtimemicros=1',
             '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net', '-debug=bench',
             '-blockminsize=%d'%BLK_MIN_SZ,
             '-blocksforscfeecheck=%d'%NUM_BLOCK_FOR_SC_FEE_CHECK]

        self.nodes = start_nodes(NUMB_OF_NODES, self.options.tmpdir, extra_args)

        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 2, 3)
        self.is_network_split = split
        self.sync_all()

    def run_test(self):

        def flood_mempool():
            mark_logs("Creating many txes...", self.nodes, DEBUG_MODE)
            tot_num_tx = 0
            tot_tx_sz = 0
            taddr_node1 = self.nodes[0].getnewaddress()

            fee = Decimal('0.001')

            # there are a few coinbase utxo now matured
            listunspent = self.nodes[0].listunspent()
            print "num of utxo: ", len(listunspent)

            while True:
                if len(listunspent) <= tot_num_tx:
                    # all utxo have been spent
                    self.sync_all()
                    break

                utxo = listunspent[tot_num_tx]
                change = utxo['amount'] - Decimal(fee)
                raw_inputs  = [ {'txid' : utxo['txid'], 'vout' : utxo['vout']}]
                raw_outs    = { taddr_node1: change }
                try:
                    raw_tx = self.nodes[0].createrawtransaction(raw_inputs, raw_outs)
                    signed_tx = self.nodes[0].signrawtransaction(raw_tx)
                    tx = self.nodes[0].sendrawtransaction(signed_tx['hex'])
                except JSONRPCException, e:
                    errorString = e.error['message']
                    print "Send raw tx failed with reason {}".format(errorString)
                    assert(False)

                tot_num_tx += 1
                hexTx = self.nodes[0].getrawtransaction(tx)
                sz = len(hexTx)//2
                tot_tx_sz += sz

                if tot_tx_sz > 5*EPOCH_LENGTH*BLK_MAX_SZ:
                    self.sync_all()
                    break

            print "tot tx   = {}, tot sz = {} ".format(tot_num_tx, tot_tx_sz)

        def get_sc_fee_min_max_value(scFeesList):
            m_min = Decimal('1000000000.0')
            f_min = Decimal('1000000000.0')
            m_max = Decimal('0.0')
            f_max = Decimal('0.0')
            for i in scFeesList:
                f_min = min(f_min, i['forwardTxScFee'])
                m_min = min(m_min, i['mbtrTxScFee'])
                f_max = max(f_max, i['forwardTxScFee'])
                m_max = max(m_max, i['mbtrTxScFee'])
            return f_min, m_min, f_max, m_max

        '''
        This test checks that FT and McBTR txes are not evicted from mempool until the numbers of blocks 
        set by the constant defined in the base code (and overriden here by the -blocksforscfeecheck zend option)
        are connected to the active chain.
        In order to verify it, two null-fee and low-prio txes are sent to the mempool with a FT and a Mbtr, a large number
        of high-fee/high prio txes are added too, and the miners have a small block capacity, so that the former pair is never 
        mined, while SC epochs increase evolving active certificates. 
        After a node restart, this pattern is repeated but this time the txes are mined before they are evicted from the mempool.
        '''

        FT_SC_FEES=[Decimal('0.001'),   # creation of the SC
                    Decimal('0.002'),   # fwd tx amount
                    Decimal('0.003'),   # cert ep=0, q=1
                    Decimal('0.004'),   # cert ep=0, q=2
                    Decimal('0.005'),   # cert ep=1
                    Decimal('0.006'),   # cert ep=2
                    Decimal('0.007'),   # cert ep=3
                    Decimal('0.008')]   # cert ep=4

        MBTR_SC_FEES=[Decimal('0.011'),  # creation of the SC
                      Decimal('0.011'),  # mbtr tx sc fee, we can also have the same value of creation
                      Decimal('0.033'),  # cert ep=0, q=1
                      Decimal('0.044'),  # cert ep=0, q=2
                      Decimal('0.055'),  # cert ep=1
                      Decimal('0.066'),  # cert ep=2
                      Decimal('0.077'),  # cert ep=3
                      Decimal('0.088')]  # cert ep=4

        # This is a hack for having certs always selected first by miner
        # via the rpc cmd prioritisetransaction
        prio_delta = Decimal(1.0E16)
        fee_delta  = 0 # in zats

        # network topology: (0)--(1)--(2)--(3)

        mark_logs("Node 0 generates 310 blocks", self.nodes, DEBUG_MODE)
        blocks = self.nodes[0].generate(310)
        self.sync_all()

        mark_logs("Node 1 generates 110 blocks", self.nodes, DEBUG_MODE)
        blocks = self.nodes[1].generate(110)
        self.sync_all()

        # Sidechain parameters
        withdrawalEpochLength = EPOCH_LENGTH
        address = "dada"
        creation_amount = Decimal("5.0")
        custom_data = ""
        mbtrRequestDataLength = 1

        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk_tag = "sc1"
        vk = mcTest.generate_params(vk_tag)
        constant = generate_random_field_element_hex()
        cswVk  = ""
        feCfg = []
        bvCfg = []


        # ---------------------------------------------------------------------------------------
        # Node 1 - Create a valid sidechain
        mark_logs("\nNode 1 creates a new sidechain", self.nodes, DEBUG_MODE)

        errorString = ""
        ftScFee   = FT_SC_FEES[0]
        mbtrScFee = MBTR_SC_FEES[0]
        cmdInput = {
            "version": 0,
            "withdrawalEpochLength": withdrawalEpochLength,
            "toaddress": address,
            "amount": creation_amount,
            "wCertVk": vk,
            "constant": constant,
            'customData': custom_data,
            'wCeasedVk': cswVk,
            'vFieldElementCertificateFieldConfig': feCfg,
            'vBitVectorCertificateFieldConfig': bvCfg,
            'forwardTransferScFee': ftScFee,
            'mainchainBackwardTransferScFee': mbtrScFee,
            'mainchainBackwardTransferRequestDataLength': mbtrRequestDataLength
        }


        try:
            ret = self.nodes[1].sc_create(cmdInput)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString,self.nodes,DEBUG_MODE)
            assert_true(False)
Пример #4
0
        try:
            txFT = self.nodes[2].sc_send(forwardTransferOuts, { "fee": 0.0})
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString,self.nodes,DEBUG_MODE)
            assert_true(False)

        self.sync_all()
        mark_logs("txFT={}, scFee={}".format(txFT, ftScFee), self.nodes, DEBUG_MODE)
        assert_true(txFT in self.nodes[0].getrawmempool())

        # ---------------------------------------------------------------------------------------
        mark_logs("\nNode 3 creates a tx with an MBTR output", self.nodes, DEBUG_MODE)

        errorString = ""
        fe1 = generate_random_field_element_hex()
        mc_dest_addr1 = self.nodes[3].getnewaddress()
        mbtrOuts = [{'vScRequestData':[fe1], 'scFee':Decimal(mbtrScFee), 'scid':scid, 'mcDestinationAddress':mc_dest_addr1}]

        try:
            txMbtr = self.nodes[3].sc_request_transfer(mbtrOuts, { "fee": 0.0})
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString,self.nodes,DEBUG_MODE)
            assert_true(False)

        self.sync_all()
        mark_logs("txMbtr={}, scFee={}".format(txMbtr, mbtrScFee), self.nodes, DEBUG_MODE)
        assert_true(txMbtr in self.nodes[0].getrawmempool())

        # ---------------------------------------------------------------------------------------
    def run_test(self):
        '''
        Verify that the async proof verifier for sidechain proofs works as expected.
        '''

        # Prepare some coins
        self.nodes[0].generate(MINIMAL_SC_HEIGHT / 2 + 1)
        self.sync_all()

        # Generate some coins on node 2
        self.nodes[2].generate(MINIMAL_SC_HEIGHT / 2 + 1)
        self.sync_all()

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_epoch_len = EPOCH_LENGTH
        sc_cr_amount = Decimal('12.00000000')

        cert_mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        csw_mc_test = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        vk = cert_mc_test.generate_params("sc")
        csw_vk = csw_mc_test.generate_params("sc")
        constant = generate_random_field_element_hex()

        sc_cr = []
        sc_cr.append({
            "version": 0,
            "epoch_length": sc_epoch_len,
            "amount": sc_cr_amount,
            "address": sc_address,
            "wCertVk": vk,
            "wCeasedVk": csw_vk,
            "constant": constant
        })

        rawtx = self.nodes[0].createrawtransaction([], {}, [], sc_cr)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sig_raw_tx = self.nodes[0].signrawtransaction(funded_tx['hex'])
        final_raw_tx = self.nodes[0].sendrawtransaction(sig_raw_tx['hex'])
        self.sync_all()

        decoded_tx = self.nodes[1].getrawtransaction(final_raw_tx, 1)
        scid = decoded_tx['vsc_ccout'][0]['scid']
        scid_swapped = swap_bytes(scid)
        mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE)

        # Advance one epoch
        mark_logs("\nLet 1 epoch pass by...", self.nodes, DEBUG_MODE)

        cert1, epoch_number = advance_epoch(cert_mc_test, self.nodes[0],
                                            self.sync_all, scid, "sc",
                                            constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for SC epoch {} {}".format(epoch_number, cert1),
            self.nodes, DEBUG_MODE)

        # Check that the certificate is in the mempool
        mark_logs("Check certificate is in mempool...", self.nodes, DEBUG_MODE)
        assert_true(cert1 in self.nodes[0].getrawmempool())
        assert_true(cert1 in self.nodes[1].getrawmempool())

        # Generate blocks to reach the next epoch
        mark_logs("\nLet another epoch pass by...", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(sc_epoch_len)
        self.sync_all()

        # Check that the certificate is not in the mempool anymore
        mark_logs("Check certificate is not in mempool anymore...", self.nodes,
                  DEBUG_MODE)
        assert_false(cert1 in self.nodes[0].getrawmempool())
        assert_false(cert1 in self.nodes[1].getrawmempool())

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], sc_epoch_len)
        cert_quality = 1
        cert_fee = Decimal("0.00001")
        ft_fee = 0
        mbtr_fee = 0

        # Manually create a certificate with invalid proof to test the ban mechanism
        # mark_logs("\nTest the node ban mechanism by sending a certificate with invalid proof", self.nodes, DEBUG_MODE)

        # Create an invalid proof by providing the wrong epoch_number
        proof = cert_mc_test.create_test_proof("sc", scid_swapped,
                                               epoch_number + 1, cert_quality,
                                               mbtr_fee, ft_fee,
                                               epoch_cum_tree_hash, constant,
                                               [], [])

        try:
            # The send_certificate call must be ok since the proof verification is disabled on node 2
            invalid_cert = self.nodes[2].sc_send_certificate(
                scid, epoch_number, cert_quality, epoch_cum_tree_hash, proof,
                [], ft_fee, mbtr_fee, cert_fee)
        except JSONRPCException, e:
            error_string = e.error['message']
            print "Send certificate failed with reason {}".format(error_string)
            assert (False)
    def run_test(self):
        '''
        Create 2 SCs and let them cease after 2 epochs. Create a tx with 5 csw inputs for each of the SCs and send it over the network.
        Verify that it is accepted in the mempool and that another tx with a further csw input is not accepted due to mempool limit reached.
        Mine a block that includes the tx in the mempool and verify that resending the previously rejected tx this time is succesful.
        Mine another block and then disconnect both last blocks from active chain in all nodes.
        Verify that only the last tx is included in the mempool, not the first (big) one.
        '''

        # network topology: (0)--(1)--(2)

        mark_logs("Node 0 generates 310 blocks", self.nodes, DEBUG_MODE)
        blocks = self.nodes[0].generate(310)
        self.sync_all()

        mark_logs("Node 1 generates 110 blocks", self.nodes, DEBUG_MODE)
        blocks = self.nodes[1].generate(110)
        self.sync_all()

        # Sidechain parameters
        withdrawalEpochLength = EPOCH_LENGTH
        address = "dada"
        creation_amount = Decimal("50.0")
        custom_data = ""
        mbtrRequestDataLength = 1

        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        certVk1 = certMcTest.generate_params("sc1")
        certVk2 = certMcTest.generate_params("sc2")
        cswVk1 = cswMcTest.generate_params("sc1")
        cswVk2 = cswMcTest.generate_params("sc2")
        constant1 = generate_random_field_element_hex()
        constant2 = generate_random_field_element_hex()

        feCfg = []
        bvCfg = []

        ftScFee = Decimal('0.01')
        mbtrScFee = Decimal('0.02')

        # ---------------------------------------------------------------------------------------
        # Node 1 - Create a valid sidechain
        mark_logs("\nNode 0 creates 2 sidechains", self.nodes, DEBUG_MODE)
        cmdInput = {
            "version": 0,
            "withdrawalEpochLength": withdrawalEpochLength,
            "toaddress": address,
            "amount": creation_amount,
            "wCertVk": certVk1,
            "constant": constant1,
            'customData': custom_data,
            'wCeasedVk': cswVk1,
            'vFieldElementCertificateFieldConfig': feCfg,
            'vBitVectorCertificateFieldConfig': bvCfg,
            'forwardTransferScFee': ftScFee,
            'mainchainBackwardTransferScFee': mbtrScFee,
            'mainchainBackwardTransferRequestDataLength': mbtrRequestDataLength
        }

        try:
            ret = self.nodes[0].sc_create(cmdInput)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)
    def run_test(self):
        '''
        Create a SC, advance two epochs, move to the limit of the safe guard and then split the network. 
        One network part sends a certificate to keep the sidechain alive and then generates two blocks.
        The other network part generates one block, theny sends a CSW.
        When the network is joined, verify that the SC is alive and that the CSW transaction has been
        removed from mempool.
        '''

        # prepare some coins
        self.nodes[3].generate(1)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 3)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_epoch_len = EPOCH_LENGTH
        sc_cr_amount = Decimal('12.00000000')

        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        vk = certMcTest.generate_params("sc1")
        cswVk = cswMcTest.generate_params("csw1")
        constant = generate_random_field_element_hex()

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': sc_epoch_len,
            'amount': sc_cr_amount,
            'toaddress': sc_address,
            'wCertVk': vk,
            'wCeasedVk': cswVk,
            'constant': constant,
            'mainchainBackwardTransferRequestDataLength': 1
        }

        res = self.nodes[0].sc_create(cmdInput)
        tx = res['txid']
        scid = res['scid']
        self.sync_all()
        mark_logs("tx {} created SC {}".format(tx, scid), self.nodes,
                  DEBUG_MODE)

        # advance two epochs
        mark_logs("\nLet 2 epochs pass by...", self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid, "sc1",
                                           constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for epoch {} {}".format(epoch_number, cert),
            self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid, "sc1",
                                           constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for epoch {} {}l".format(epoch_number, cert),
            self.nodes, DEBUG_MODE)

        ceas_height = self.nodes[0].getscinfo(
            scid, False, False)['items'][0]['ceasingHeight']
        numbBlocks = ceas_height - self.nodes[0].getblockcount(
        ) + sc_epoch_len - 1
        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        mark_logs(
            "\nNode0 generates {} block reaching the sg for the next epoch".
            format(numbBlocks), self.nodes, DEBUG_MODE)
        self.nodes[0].generate(numbBlocks)
        self.sync_all()
        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        #============================================================================================
        mark_logs("\nSplit network", self.nodes, DEBUG_MODE)
        self.split_network()
        mark_logs("The network is split: 0-1-2 .. 3", self.nodes, DEBUG_MODE)

        # Network part 0-1-2
        print "------------------"

        mark_logs("\nNTW part 1) Node2 sends a certificate", self.nodes,
                  DEBUG_MODE)
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[2], sc_epoch_len)

        bt_amount = Decimal("5.0")
        addr_node1 = self.nodes[1].getnewaddress()
        quality = 10
        scid_swapped = str(swap_bytes(scid))

        proof = certMcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                             quality, MBTR_SC_FEE, FT_SC_FEE,
                                             epoch_cum_tree_hash, constant,
                                             [addr_node1], [bt_amount])

        amount_cert = [{"address": addr_node1, "amount": bt_amount}]
        try:
            cert_bad = self.nodes[2].sc_send_certificate(
                scid, epoch_number, quality, epoch_cum_tree_hash, proof,
                amount_cert, 0, 0, 0.01)
        except JSONRPCException, e:
            errorString = e.error['message']
            print "Send certificate failed with reason {}".format(errorString)
            assert (False)
Пример #8
0
    def run_test(self):
        '''
        Test that a backward transfer amount under its dust threshold is not accepted in the mempool.
        Since this dust threshold depends on minrelaytxfee and this is an optional zend flag, test that 
        a node with a different value set behaves correctly and the network is not affected (no forks happen)
        '''

        mark_logs("Node 1 generates 2 block",self.nodes,DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT-2),self.nodes,DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT-2)
        self.sync_all()

        #generate wCertVk and constant
        mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mc_test.generate_params('sc1')
        constant = generate_random_field_element_hex()

        # create SC
        #------------------------------------------------------------------------------------------------------------
        cmd_input = {
            'version': 0,
            'toaddress': "abcd",
            'amount': 1.0,
            'wCertVk': vk,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'constant': constant
        }

        mark_logs("\nNode 1 create SC", self.nodes, DEBUG_MODE)
        try:
            res = self.nodes[1].sc_create(cmd_input)
            scid = res['scid']
            pprint.pprint(res)
            self.sync_all()
        except JSONRPCException as e:
            error_string = e.error['message']
            mark_logs(error_string,self.nodes,DEBUG_MODE)
            assert_true(False)

        mark_logs("\nNode 0 generates 1 block", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()

        scid_swapped = str(swap_bytes(scid))
        addr_node2   = self.nodes[2].getnewaddress()

        # this amount is next to the border of the dust (54 zat, according to mintxrelayfee default value) but it is sufficiently big not to be refused
        bwt_amount = Decimal('0.00000060')
        bwt_cert = [{"address": addr_node2, "amount": bwt_amount}, {"address": addr_node2, "amount": bwt_amount}]
        bwt_amount_array = [bwt_amount, bwt_amount]
        addr_array = [addr_node2, addr_node2]
        q = 10

        bl_list = []
        # advance some epoch and send a small backward transfer via a certificate for any epoch
        for i in range(3):

            if i == 1:
                # On the second loop, connect a fourth node from scratch with a greater mintxrelayfee, which would make the
                # node mempool reject the cert, and check this option does not prevent the chain update anyway
                mark_logs("Connecting a new Node3 with a greater -mintxrelayfee", self.nodes, DEBUG_MODE)
                self.nodes.append(start_node(
                    3, self.options.tmpdir , extra_args=[
                        '-logtimemicros=1', '-debug=cert', '-debug=sc', '-debug=py', '-debug=mempool',
                        '-allowdustoutput=0', '-minrelaytxfee='+str(CUSTOM_FEE_RATE_ZEN_PER_KBYTE)]))

                connect_nodes_bi(self.nodes, 2, 3)
                self.sync_all()

            mark_logs("\nAdvance epoch...", self.nodes, DEBUG_MODE)
            self.nodes[0].generate(EPOCH_LENGTH - 1)
            self.sync_all()
            epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], EPOCH_LENGTH)

            mark_logs("Node 1 sends a cert with a bwd transfers of {} coins to Node2".format(bwt_amount), self.nodes, DEBUG_MODE)
            #==============================================================
            proof = mc_test.create_test_proof(
                "sc1", scid_swapped, epoch_number, q, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash,
                constant, addr_array, bwt_amount_array)

            try:
                cert = self.nodes[1].sc_send_certificate(scid, epoch_number, q,
                    epoch_cum_tree_hash, proof, bwt_cert, FT_SC_FEE, MBTR_SC_FEE)
            except JSONRPCException as e:
                error_string = e.error['message']
                print ("Send certificate failed with reason {}".format(error_string))
                assert_true(False)

            sync_blocks(self.nodes[0:2])
            sync_mempools(self.nodes[0:2])

            mark_logs("cert = {}".format(cert), self.nodes, DEBUG_MODE)

            if i == 1:
                # check that the certificate has ben accepted by Node0 but not by Node3 wich has a greater mintxrelayfee
                mp0 = self.nodes[0].getrawmempool()
                mp3 = self.nodes[3].getrawmempool()
                assert_true(cert in mp0)
                assert_false(cert in mp3)

            mark_logs("\nNode 0 generates 1 block", self.nodes, DEBUG_MODE)
            bl_last = self.nodes[0].generate(1)[-1]
            bl_list.append(bl_last)
            self.sync_all()

        # dust amont for a cert backward transfer is 54 Zat using the 100 Zat/Kbyte default mintxrelayfee rate
        # check that no certificates with dust amount can be sent via any command type
        dust_amount = Decimal("0.00000053")
        bwt_cert = [{"address": addr_node2, "amount": dust_amount}]
        bwt_amount_array = [dust_amount]
        addr_array = [addr_node2]
        quality = 0
        proof = mc_test.create_test_proof(
            "sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE,
            epoch_cum_tree_hash, constant, addr_array, bwt_amount_array)

        utx, change = get_spendable(self.nodes[0], CERT_FEE)
        raw_inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        raw_outs    = { self.nodes[0].getnewaddress() : change }
        raw_bwt_outs = {addr_node2: dust_amount}

        raw_params = {
            "scid": scid,
            "quality": quality,
            "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash,
            "scProof": proof,
            "withdrawalEpochNumber": epoch_number
        }
        raw_cert = []
        cert = []

        try:
            raw_cert    = self.nodes[0].createrawcertificate(raw_inputs, raw_outs, raw_bwt_outs, raw_params)
            signed_cert = self.nodes[0].signrawtransaction(raw_cert)
            mark_logs("Node 0 sends a raw cert with a bwd transfers of {} coins to Node2 ... expecting failure".format(dust_amount), self.nodes, DEBUG_MODE)
            cert = self.nodes[0].sendrawtransaction(signed_cert['hex'])
            assert False
        except JSONRPCException as e:
            error_string = e.error['message']
            print ("======> " + error_string)

        try:
            mark_logs("Node 0 sends a cert with a bwd transfers of {} coins to Node2 ... expecting failure".format(dust_amount), self.nodes, DEBUG_MODE)
            cert = self.nodes[0].sc_send_certificate(scid, epoch_number, q,
                epoch_cum_tree_hash, proof, bwt_cert, FT_SC_FEE, MBTR_SC_FEE)
            assert False
        except JSONRPCException as e:
            error_string = e.error['message']
            print ("======> " + error_string)

        bal = self.nodes[2].getbalance()
        utx = self.nodes[2].listunspent()
        print ("Node2 balance = {}".format(bal))
        assert_equal(bal, 2*bwt_amount)

        # the dust threshold for a bwt (54 Zat) is lower than the one for a standard output due to the replay protection
        # extension in the pub script (63 Zat). As a result we can not spend exactly one UTXOs coming from backward transfer
        # otherwise we would create a dust output.
        mark_logs("Node2 tries to spent one utxo from bwt sending {} coins to Node0 ... expecting failure".format(utx[0]['amount']), self.nodes, DEBUG_MODE)
        # try spending one utxo
        inputs  = [ {'txid' : utx[0]['txid'], 'vout' : utx[0]['vout']}]
        outputs = { self.nodes[0].getnewaddress() : utx[0]['amount'] }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx   = self.nodes[2].signrawtransaction(rawtx)

        error_string = ""
        try:
            rawtx   = self.nodes[2].sendrawtransaction(rawtx['hex'])
            assert False
        except JSONRPCException as e:
            error_string = e.error['message']
            print (error_string)

        # we can spend a pair of them instead
        mark_logs("Node2 tries to spent both utxo from bwt sending {} coins to Node0".format(bal), self.nodes, DEBUG_MODE)
        # try spending two utxos
        inputs  = [ {'txid' : utx[0]['txid'], 'vout' : utx[0]['vout']}, {'txid' : utx[1]['txid'], 'vout' : utx[1]['vout']}]
        outputs = { self.nodes[0].getnewaddress() : bal }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx   = self.nodes[2].signrawtransaction(rawtx)

        error_string = ""
        try:
            rawtx   = self.nodes[2].sendrawtransaction(rawtx['hex'])
        except JSONRPCException as e:
            error_string = e.error['message']
            print (error_string)
            assert False

        print ("tx = {}".format(rawtx))

        sync_blocks(self.nodes[0:2])
        sync_mempools(self.nodes[0:2])
        # just to be sure tx is propagated
        time.sleep(2)

        mark_logs("Node 2 generates 1 block", self.nodes, DEBUG_MODE)
        self.nodes[2].generate(1)
        self.sync_all()

        mark_logs("\nChecking persistance stopping and restarting nodes", self.nodes, DEBUG_MODE)
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False)
Пример #9
0
    def run_test(self):

        #amounts
        creation_amount = Decimal("50")
        bwt_amount = Decimal("5")
        tAddr1 = self.nodes[1].getnewaddress()
        node1Addr = self.nodes[1].validateaddress(tAddr1)['address']

        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT),
                  self.nodes, DEBUG_MODE)

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'toaddress': "dada",
            'amount': creation_amount,
            'wCertVk': vk,
            'constant': constant
        }

        ret = self.nodes[0].sc_create(cmdInput)
        creating_tx = ret['txid']
        scid = ret['scid']
        scid_swapped = str(swap_bytes(scid))
        mark_logs(
            "Node 1 created the SC spending {} coins via tx {}.".format(
                creation_amount, creating_tx), self.nodes, DEBUG_MODE)
        self.sync_all()

        decoded_tx = self.nodes[0].getrawtransaction(creating_tx, 1)
        assert_equal(scid, decoded_tx['vsc_ccout'][0]['scid'])
        mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE)

        mark_logs("Node0 confirms Sc creation generating 1 block", self.nodes,
                  DEBUG_MODE)
        sc_creation_block_hash = self.nodes[0].generate(1)[0]
        sc_creation_block = self.nodes[0].getblock(sc_creation_block_hash)
        self.sync_all()

        #Advance for 1 Epoch
        mark_logs("Advance for 1 Epoch", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(EPOCH_LENGTH)
        self.sync_all()

        #Mine Certificate 1 with quality = 5
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 5
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount])

        amount_cert_1 = [{"address": node1Addr, "amount": bwt_amount}]

        mark_logs("Mine Certificate 1 with quality = {}...".format(quality),
                  self.nodes, DEBUG_MODE)

        cert1 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_1, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)
        self.sync_all()

        maturityHeight = sc_creation_block["height"] + (
            EPOCH_LENGTH * 2) + EPOCH_LENGTH * 0.2 - 1

        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(len(addressmempool), 1)
        assert_equal(addressmempool[0]['txid'], cert1)
        assert_equal(addressmempool[0]['satoshis'], float(bwt_amount) * 1e8)
        assert_equal(addressmempool[0]['address'], tAddr1)
        assert_equal(addressmempool[0]['outstatus'],
                     TOP_QUALITY_CERT_BACKWARD_TRANSFER)

        self.nodes[0].generate(1)
        self.sync_all()

        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(addressmempool, [])
        ####### Test getaddresstxids ########
        addresstxids = self.nodes[1].getaddresstxids({"addresses": [tAddr1]})
        assert_equal(len(addresstxids), 1)
        assert_equal(addresstxids[0], cert1)
        ####### Test getaddressbalance ########
        addressbalance = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]})
        addressbalanceWithImmature = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]}, True)
        assert_equal(addressbalance["balance"], 0)
        assert_equal(addressbalance["immature"], to_satoshis(bwt_amount))
        assert_equal(addressbalance["received"], 0)
        assert_equal(addressbalanceWithImmature["balance"],
                     to_satoshis(bwt_amount))
        assert_equal(addressbalanceWithImmature["immature"],
                     to_satoshis(bwt_amount))
        assert_equal(addressbalanceWithImmature["received"],
                     to_satoshis(bwt_amount))
        ####### Test getaddressutxo ########
        addressutxo = self.nodes[1].getaddressutxos({"addresses": [tAddr1]})
        assert_equal(len(addressutxo), 0)
        addressutxoWithImmature = self.nodes[1].getaddressutxos(
            {"addresses": [tAddr1]}, True)
        assert_equal(len(addressutxoWithImmature), 1)
        assert_true(addressutxoWithImmature[0]["backwardTransfer"])
        assert_false(addressutxoWithImmature[0]["mature"])
        assert_equal(addressutxoWithImmature[0]["maturityHeight"],
                     maturityHeight)
        assert_equal(addressutxoWithImmature[0]["satoshis"],
                     to_satoshis(bwt_amount))
        currentHeight = self.nodes[0].getblockcount()
        assert_equal(addressutxoWithImmature[0]["blocksToMaturity"],
                     maturityHeight - currentHeight)

        #Add to mempool Certificate 2 with quality = 7
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 7
        bwt_amount2 = Decimal("7")
        mark_logs(
            "Add to mempool Certificate 2 with quality = {}...".format(
                quality), self.nodes, DEBUG_MODE)
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount2])

        amount_cert_2 = [{"address": node1Addr, "amount": bwt_amount2}]

        cert2 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_2, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)
        self.sync_all()

        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(len(addressmempool), 1)
        assert_equal(addressmempool[0]['txid'], cert2)
        assert_equal(addressmempool[0]['satoshis'], float(bwt_amount2) * 1e8)
        assert_equal(addressmempool[0]['address'], tAddr1)
        assert_equal(addressmempool[0]['outstatus'],
                     TOP_QUALITY_CERT_BACKWARD_TRANSFER)

        quality = 9
        bwt_amount3 = Decimal("9")
        mark_logs(
            "Add to mempool Certificate 3 with quality = {}...".format(
                quality), self.nodes, DEBUG_MODE)
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount3])

        amount_cert_3 = [{"address": node1Addr, "amount": bwt_amount3}]

        cert3 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_3, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)
        self.sync_all()

        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(len(addressmempool), 2)
        assert_equal(addressmempool[0]['txid'], cert2)
        assert_equal(addressmempool[0]['satoshis'], float(bwt_amount2) * 1e8)
        assert_equal(addressmempool[0]['address'], tAddr1)
        assert_equal(addressmempool[0]['outstatus'],
                     LOW_QUALITY_CERT_BACKWARD_TRANSFER)

        assert_equal(addressmempool[1]['txid'], cert3)
        assert_equal(addressmempool[1]['satoshis'], float(bwt_amount3) * 1e8)
        assert_equal(addressmempool[1]['address'], tAddr1)
        assert_equal(addressmempool[1]['outstatus'],
                     TOP_QUALITY_CERT_BACKWARD_TRANSFER)

        self.nodes[0].generate(1)
        self.sync_all()

        ####### Test getaddresstxids ########
        addresstxids = self.nodes[1].getaddresstxids({"addresses": [tAddr1]})
        assert_equal(len(addresstxids), 3)
        assert_true(cert1 in addresstxids and cert2 in addresstxids
                    and cert3 in addresstxids)
        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(len(addressmempool), 0)
        ####### Test getaddressbalance ########
        addressbalance = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]})
        addressbalanceWithImmature = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]}, True)
        assert_equal(addressbalance["balance"], 0)
        assert_equal(addressbalance["immature"], to_satoshis(bwt_amount3))
        assert_equal(addressbalance["received"], 0)
        assert_equal(addressbalanceWithImmature["balance"],
                     to_satoshis(bwt_amount3))
        assert_equal(addressbalanceWithImmature["immature"],
                     to_satoshis(bwt_amount3))
        assert_equal(addressbalanceWithImmature["received"],
                     to_satoshis(bwt_amount3))
        ####### Test getaddressutxo ########
        addressutxo = self.nodes[1].getaddressutxos({"addresses": [tAddr1]})
        addressutxoWithImmature = self.nodes[1].getaddressutxos(
            {"addresses": [tAddr1]}, True)
        assert_equal(len(addressutxo), 0)
        assert_equal(len(addressutxoWithImmature), 1)
        assert_true(addressutxoWithImmature[0]["backwardTransfer"])
        assert_false(addressutxoWithImmature[0]["mature"])
        assert_equal(addressutxoWithImmature[0]["maturityHeight"],
                     maturityHeight)
        assert_equal(addressutxoWithImmature[0]["satoshis"],
                     to_satoshis(bwt_amount3))
        currentHeight = self.nodes[0].getblockcount()
        assert_equal(addressutxoWithImmature[0]["blocksToMaturity"],
                     maturityHeight - currentHeight)

        # Split the network: (0) / (1)
        mark_logs("\nSplit network", self.nodes, DEBUG_MODE)
        self.split_network()
        mark_logs("The network is split: 0 / 1", self.nodes, DEBUG_MODE)

        #Mine a block with Certificate 4 with quality = 11 and Certificate 5 with quality = 13
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 11
        bwt_amount4 = Decimal("11")
        mark_logs(
            "Create a Certificate 4 with quality = {}...".format(quality),
            self.nodes, DEBUG_MODE)
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount4])

        amount_cert_4 = [{"address": node1Addr, "amount": bwt_amount4}]

        cert4 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_4, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)

        quality = 13
        bwt_amount5 = Decimal("13")
        mark_logs("Create a Certificat 5 with quality = {}...".format(quality),
                  self.nodes, DEBUG_MODE)
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount5])

        amount_cert_5 = [{"address": node1Addr, "amount": bwt_amount5}]

        cert5 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_5, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)

        lastBlock = self.nodes[0].generate(1)[0]

        # Checking the network chain tips
        mark_logs("\nChecking network chain tips...", self.nodes, DEBUG_MODE)
        print(self.nodes[0].getblockchaininfo()['blocks'])
        print(self.nodes[1].getblockchaininfo()['blocks'])

        assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 524)
        assert_equal(self.nodes[1].getblockchaininfo()['blocks'], 523)

        mark_logs("\nJoining network", self.nodes, DEBUG_MODE)
        self.join_network()
        mark_logs("\nNetwork joined", self.nodes, DEBUG_MODE)

        ####### Test getaddresstxids ########
        addresstxids = self.nodes[1].getaddresstxids({"addresses": [tAddr1]})
        assert_equal(len(addresstxids), 5)
        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(len(addressmempool), 0)
        ####### Test getaddressbalance ########
        addressbalance = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]})
        addressbalanceWithImmature = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]}, True)
        assert_equal(addressbalance["balance"], 0)
        assert_equal(addressbalance["immature"], to_satoshis(bwt_amount5))
        assert_equal(addressbalance["received"], 0)
        assert_equal(addressbalanceWithImmature["balance"],
                     to_satoshis(bwt_amount5))
        assert_equal(addressbalanceWithImmature["immature"],
                     to_satoshis(bwt_amount5))
        assert_equal(addressbalanceWithImmature["received"],
                     to_satoshis(bwt_amount5))
        ####### Test getaddressutxo ########
        addressutxo = self.nodes[1].getaddressutxos({"addresses": [tAddr1]})
        addressutxoWithImmature = self.nodes[1].getaddressutxos(
            {"addresses": [tAddr1]}, True)
        assert_equal(len(addressutxo), 0)
        assert_equal(len(addressutxoWithImmature), 1)
        assert_true(addressutxoWithImmature[0]["backwardTransfer"])
        assert_false(addressutxoWithImmature[0]["mature"])
        assert_equal(addressutxoWithImmature[0]["maturityHeight"],
                     maturityHeight)
        assert_equal(addressutxoWithImmature[0]["satoshis"],
                     to_satoshis(bwt_amount5))
        currentHeight = self.nodes[0].getblockcount()
        assert_equal(addressutxoWithImmature[0]["blocksToMaturity"],
                     maturityHeight - currentHeight)

        # Checking the network chain tips
        mark_logs("\nChecking network chain tips...", self.nodes, DEBUG_MODE)
        for i in range(0, NUMB_OF_NODES):
            assert_equal(self.nodes[i].getblockchaininfo()['blocks'], 524)

        mark_logs(
            "\nInvalidating the last block and checking RPC call results...",
            self.nodes, DEBUG_MODE)
        self.nodes[1].invalidateblock(lastBlock)
        ####### Test getaddressmempool ########
        addressmempool = self.nodes[1].getaddressmempool(
            {"addresses": [tAddr1]})
        assert_equal(len(addressmempool), 2)

        for i in range(0, len(addressmempool)):
            if (addressmempool[i]['txid'] == cert4):
                assert_equal(addressmempool[i]['txid'], cert4)
                assert_equal(addressmempool[i]['satoshis'],
                             float(bwt_amount4) * 1e8)
                assert_equal(addressmempool[i]['address'], tAddr1)
                assert_equal(addressmempool[i]['outstatus'],
                             LOW_QUALITY_CERT_BACKWARD_TRANSFER)
            else:
                assert_equal(addressmempool[i]['txid'], cert5)
                assert_equal(addressmempool[i]['satoshis'],
                             float(bwt_amount5) * 1e8)
                assert_equal(addressmempool[i]['address'], tAddr1)
                assert_equal(addressmempool[i]['outstatus'],
                             TOP_QUALITY_CERT_BACKWARD_TRANSFER)

        ####### Test getaddressbalance ########
        addressbalance = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]})
        addressbalanceWithImmature = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]}, True)
        assert_equal(addressbalance["balance"], 0)
        assert_equal(addressbalance["immature"], to_satoshis(bwt_amount3))
        assert_equal(addressbalance["received"], 0)
        assert_equal(addressbalanceWithImmature["balance"],
                     to_satoshis(bwt_amount3))
        assert_equal(addressbalanceWithImmature["immature"],
                     to_satoshis(bwt_amount3))
        assert_equal(addressbalanceWithImmature["received"],
                     to_satoshis(bwt_amount3))
        ####### Test getaddressutxo ########
        addressutxo = self.nodes[1].getaddressutxos({"addresses": [tAddr1]})
        addressutxoWithImmature = self.nodes[1].getaddressutxos(
            {"addresses": [tAddr1]}, True)
        assert_equal(len(addressutxo), 0)
        assert_equal(len(addressutxoWithImmature), 1)
        assert_true(addressutxoWithImmature[0]["backwardTransfer"])
        assert_false(addressutxoWithImmature[0]["mature"])
        assert_equal(addressutxoWithImmature[0]["maturityHeight"],
                     maturityHeight)
        assert_equal(addressutxoWithImmature[0]["satoshis"],
                     to_satoshis(bwt_amount3))
        currentHeight = self.nodes[1].getblockcount()
        assert_equal(addressutxoWithImmature[0]["blocksToMaturity"],
                     maturityHeight - currentHeight)

        # Generate blocks to reach maturity height (and also make sidechain cease)
        mark_logs("\nGenerating blocks to make the sidechain ceased...",
                  self.nodes, DEBUG_MODE)
        lastBlock = self.nodes[1].generate(int(maturityHeight -
                                               currentHeight))[-1]
        self.sync_all()

        mark_logs(
            "Checking that all the certificates are considered as not mature...",
            self.nodes, DEBUG_MODE)
        ####### Test getaddressbalance ########
        addressbalance = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]})
        addressbalanceWithImmature = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]}, True)
        # All the balances should be 0 since the sidechain is ceased and no BT has matured
        assert_equal(addressbalance["balance"], 0)
        assert_equal(addressbalance["immature"], 0)
        assert_equal(addressbalance["received"], 0)
        assert_equal(addressbalanceWithImmature["balance"], 0)
        assert_equal(addressbalanceWithImmature["immature"], 0)
        assert_equal(addressbalanceWithImmature["received"], 0)
        ####### Test getaddressutxo ########
        addressutxo = self.nodes[1].getaddressutxos({"addresses": [tAddr1]})
        addressutxoWithImmature = self.nodes[1].getaddressutxos(
            {"addresses": [tAddr1]}, True)
        assert_equal(len(addressutxo), 0)
        assert_equal(len(addressutxoWithImmature), 0)

        # Invalidate the last block to recover the sidechain from the "ceased" state and make
        # it "alive" again.
        mark_logs(
            "\nInvalidating the last block to make the sidechain alive again...",
            self.nodes, DEBUG_MODE)
        self.nodes[1].invalidateblock(lastBlock)

        mark_logs(
            "Checking that the certificates are restored as they were before the block revert...",
            self.nodes, DEBUG_MODE)
        ####### Test getaddressbalance ########
        addressbalance = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]})
        addressbalanceWithImmature = self.nodes[1].getaddressbalance(
            {"addresses": [tAddr1]}, True)
        assert_equal(addressbalance["balance"], 0)
        assert_equal(addressbalance["immature"], to_satoshis(bwt_amount5))
        assert_equal(addressbalance["received"], 0)
        assert_equal(addressbalanceWithImmature["balance"],
                     to_satoshis(bwt_amount5))
        assert_equal(addressbalanceWithImmature["immature"],
                     to_satoshis(bwt_amount5))
        assert_equal(addressbalanceWithImmature["received"],
                     to_satoshis(bwt_amount5))
        ####### Test getaddressutxo ########
        addressutxo = self.nodes[1].getaddressutxos({"addresses": [tAddr1]})
        addressutxoWithImmature = self.nodes[1].getaddressutxos(
            {"addresses": [tAddr1]}, True)
        assert_equal(len(addressutxo), 0)
        assert_equal(len(addressutxoWithImmature), 1)
        assert_true(addressutxoWithImmature[0]["backwardTransfer"])
        assert_false(addressutxoWithImmature[0]["mature"])
        assert_equal(addressutxoWithImmature[0]["maturityHeight"],
                     maturityHeight)
        assert_equal(addressutxoWithImmature[0]["satoshis"],
                     to_satoshis(bwt_amount5))
        currentHeight = self.nodes[1].getblockcount()
        assert_equal(addressutxoWithImmature[0]["blocksToMaturity"],
                     maturityHeight - currentHeight)

        ret = self.nodes[1].verifychain(4, 0)
        assert_equal(ret, True)
Пример #10
0
class CertMempoolCleanupSplit(BitcoinTestFramework):
    def setup_chain(self):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)

    def setup_network(self, split=False):
        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[[
                '-logtimemicros=1', '-scproofqueuesize=0', '-debug=sc',
                '-debug=py', '-debug=mempool', '-debug=net', '-debug=bench'
            ]] * NUMB_OF_NODES)

        if not split:
            # 2 and 3 are joint only if split==false
            connect_nodes_bi(self.nodes, 2, 3)
            sync_blocks(self.nodes[2:4])
            sync_mempools(self.nodes[2:4])

        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        self.is_network_split = split
        self.sync_all()

    def split_network(self):
        # Split the network of three nodes into nodes 0-1-2 and 3.
        assert not self.is_network_split
        disconnect_nodes(self.nodes[2], 3)
        disconnect_nodes(self.nodes[3], 2)
        self.is_network_split = True

    def join_network(self):
        # Join the (previously split) network pieces together: 0-1-2-3
        assert self.is_network_split
        connect_nodes_bi(self.nodes, 2, 3)
        connect_nodes_bi(self.nodes, 3, 2)
        time.sleep(2)
        self.is_network_split = False

    def run_test(self):
        '''
        Create a SC, advance two epochs, move to the limit of the safe guard and then split the network. 
        One network part sends a certificate to keep the sidechain alive and then generates two blocks.
        The other network part generates one block, theny sends a CSW.
        When the network is joined, verify that the SC is alive and that the CSW transaction has been
        removed from mempool.
        '''

        # prepare some coins
        self.nodes[3].generate(1)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 3)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_epoch_len = EPOCH_LENGTH
        sc_cr_amount = Decimal('12.00000000')

        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        vk = certMcTest.generate_params("sc1")
        cswVk = cswMcTest.generate_params("csw1")
        constant = generate_random_field_element_hex()

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': sc_epoch_len,
            'amount': sc_cr_amount,
            'toaddress': sc_address,
            'wCertVk': vk,
            'wCeasedVk': cswVk,
            'constant': constant,
            'mainchainBackwardTransferRequestDataLength': 1
        }

        res = self.nodes[0].sc_create(cmdInput)
        tx = res['txid']
        scid = res['scid']
        self.sync_all()
        mark_logs("tx {} created SC {}".format(tx, scid), self.nodes,
                  DEBUG_MODE)

        # advance two epochs
        mark_logs("\nLet 2 epochs pass by...", self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid, "sc1",
                                           constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for epoch {} {}".format(epoch_number, cert),
            self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid, "sc1",
                                           constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for epoch {} {}l".format(epoch_number, cert),
            self.nodes, DEBUG_MODE)

        ceas_height = self.nodes[0].getscinfo(
            scid, False, False)['items'][0]['ceasingHeight']
        numbBlocks = ceas_height - self.nodes[0].getblockcount(
        ) + sc_epoch_len - 1
        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        mark_logs(
            "\nNode0 generates {} block reaching the sg for the next epoch".
            format(numbBlocks), self.nodes, DEBUG_MODE)
        self.nodes[0].generate(numbBlocks)
        self.sync_all()
        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        #============================================================================================
        mark_logs("\nSplit network", self.nodes, DEBUG_MODE)
        self.split_network()
        mark_logs("The network is split: 0-1-2 .. 3", self.nodes, DEBUG_MODE)

        # Network part 0-1-2
        print "------------------"

        mark_logs("\nNTW part 1) Node2 sends a certificate", self.nodes,
                  DEBUG_MODE)
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[2], sc_epoch_len)

        bt_amount = Decimal("5.0")
        addr_node1 = self.nodes[1].getnewaddress()
        quality = 10
        scid_swapped = str(swap_bytes(scid))

        proof = certMcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                             quality, MBTR_SC_FEE, FT_SC_FEE,
                                             epoch_cum_tree_hash, constant,
                                             [addr_node1], [bt_amount])

        amount_cert = [{"address": addr_node1, "amount": bt_amount}]
        try:
            cert_bad = self.nodes[2].sc_send_certificate(
                scid, epoch_number, quality, epoch_cum_tree_hash, proof,
                amount_cert, 0, 0, 0.01)
        except JSONRPCException, e:
            errorString = e.error['message']
            print "Send certificate failed with reason {}".format(errorString)
            assert (False)
        sync_mempools(self.nodes[0:3])

        mark_logs("Check cert {} is in mempool".format(cert_bad), self.nodes,
                  DEBUG_MODE)
        assert_true(cert_bad in self.nodes[0].getrawmempool())

        mark_logs(
            "Generates two blocks to make the chain longer than sub-network 2",
            self.nodes, DEBUG_MODE)
        self.nodes[0].generate(2)

        print "Node0 Chain h = ", self.nodes[0].getblockcount()

        # Network part 2
        #------------------

        mark_logs(
            "\nNTW part 2) Node3 generates one block to cease the sidechain",
            self.nodes, DEBUG_MODE)
        self.nodes[3].generate(1)

        mark_logs("Check that the sidechain is ceased from node 3 perspective",
                  self.nodes, DEBUG_MODE)
        ret = self.nodes[3].getscinfo(scid, False, False)['items'][0]
        assert_equal(ret['state'], "CEASED")

        sc_bal = ret['balance']

        mark_logs("Node 3 creates a CSW transaction", self.nodes, DEBUG_MODE)

        csw_mc_address = self.nodes[3].getnewaddress()
        taddr = self.nodes[3].getnewaddress()
        sc_csw_amount = sc_bal
        null = generate_random_field_element_hex()
        actCertData = self.nodes[3].getactivecertdatahash(scid)['certDataHash']
        ceasingCumScTxCommTree = self.nodes[3].getceasingcumsccommtreehash(
            scid)['ceasingCumScTxCommTree']

        csw_proof = cswMcTest.create_test_proof("csw1", sc_csw_amount,
                                                str(scid_swapped), null,
                                                csw_mc_address,
                                                ceasingCumScTxCommTree,
                                                actCertData, constant)

        sc_csws = [{
            "amount": sc_csw_amount,
            "senderAddress": csw_mc_address,
            "scId": scid,
            "epoch": 0,
            "nullifier": null,
            "activeCertData": actCertData,
            "ceasingCumScTxCommTree": ceasingCumScTxCommTree,
            "scProof": csw_proof
        }]

        out_amount = sc_csw_amount / Decimal("2.0")
        sc_csw_tx_outs = {taddr: out_amount}
        rawtx = self.nodes[3].createrawtransaction([], sc_csw_tx_outs, sc_csws)
        funded_tx = self.nodes[3].fundrawtransaction(rawtx)
        sigRawtx = self.nodes[3].signrawtransaction(funded_tx['hex'])
        try:
            csw_bad = self.nodes[3].sendrawtransaction(sigRawtx['hex'])
            pprint.pprint(self.nodes[3].getrawtransaction(tx, 1))
            assert (False)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs("Send csw failed with reason {}".format(errorString),
                      self.nodes, DEBUG_MODE)
Пример #11
0
    def run_test(self):
        '''
        Test that the JSON result of the rpc command listsinceblock includes a matured certificate backward transfer even when:
        1) the input block range specified does not contain the block where such certificate has been mined.
        2) The certificate matures in one of the blocks of the specified range
        '''

        mark_logs("Node 1 generates 2 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT - 2),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 2)
        self.sync_all()

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params('sc1')
        constant = generate_random_field_element_hex()

        # create SC
        #------------------------------------------------------------------------------------------------------------
        cmdInput = {
            'version': 0,
            'toaddress': "abcd",
            'amount': 20.0,
            'wCertVk': vk,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'constant': constant
        }

        mark_logs("\nNode 1 create SC", self.nodes, DEBUG_MODE)
        try:
            res = self.nodes[1].sc_create(cmdInput)
            tx = res['txid']
            scid = res['scid']
            pprint.pprint(res)
            self.sync_all()
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)

        mark_logs("\nNode 0 generates 1 block", self.nodes, DEBUG_MODE)
        bl = self.nodes[0].generate(1)[-1]
        self.sync_all()

        item = self.nodes[0].getscinfo(scid)['items'][0]
        elen = item['withdrawalEpochLength']
        wlen = item['certSubmissionWindowLength']
        ch = item['createdAtBlockHeight']

        scid_swapped = str(swap_bytes(scid))

        q = 10
        blocks_d = {}
        block_heights_d = {}
        certs_d = {}
        mat_height_d = {}

        taddr1 = self.nodes[1].getnewaddress()
        taddr2 = self.nodes[2].getnewaddress()

        # advance some epochs and send a certificate for any of them
        for i in range(3):

            am_bwt1 = Decimal(i + 1) + Decimal('0.01')
            am_bwt2 = Decimal(i + 1) + Decimal('0.02')
            am_out = Decimal('0.001') * (i + 1)

            mark_logs("Advance epoch...", self.nodes, DEBUG_MODE)
            self.nodes[0].generate(EPOCH_LENGTH - 1)
            self.sync_all()
            epoch_number, epoch_cum_tree_hash = get_epoch_data(
                scid, self.nodes[0], EPOCH_LENGTH)

            mark_logs("Node 1 sends a cert", self.nodes, DEBUG_MODE)
            #==============================================================
            pkh_arr = []
            am_bwt_arr = []
            raw_bwt_outs = [{
                "address": taddr1,
                "amount": am_bwt1
            }, {
                "address": taddr2,
                "amount": am_bwt2
            }]
            for entry in raw_bwt_outs:
                pkh_arr.append(entry["address"])
                am_bwt_arr.append(entry["amount"])

            proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                             q, MBTR_SC_FEE, FT_SC_FEE,
                                             epoch_cum_tree_hash, constant,
                                             pkh_arr, am_bwt_arr)

            utx, change = get_spendable(self.nodes[1], CERT_FEE + am_out)
            raw_inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
            raw_outs = {taddr1: change, taddr2: am_out}

            raw_params = {
                "scid": scid,
                "quality": q,
                "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash,
                "scProof": proof,
                "withdrawalEpochNumber": epoch_number
            }

            # use the raw version of the command for having more than one standard output
            # -------------------------------------
            # vout 1: standard output (taddr1) - change
            # vout 2: standard output (taddr2)
            # vout 3: bwt (taddr1)
            # vout 3: bwt (taddr2)
            try:
                raw_cert = self.nodes[1].createrawcertificate(
                    raw_inputs, raw_outs, raw_bwt_outs, raw_params)
                signed_cert = self.nodes[1].signrawtransaction(raw_cert)
                certs_d[i] = self.nodes[1].sendrawtransaction(
                    signed_cert['hex'])
            except JSONRPCException as e:
                errorString = e.error['message']
                print("\n======> ", errorString)
                assert_true(False)

            self.sync_all()

            mark_logs("cert = {}".format(certs_d[i]), self.nodes, DEBUG_MODE)
            mat_height_d[i] = ch - 1 + (i + 2) * elen + wlen
            print("mat height = {}".format(mat_height_d[i]))

            mark_logs("Node 0 generates 1 block", self.nodes, DEBUG_MODE)
            bl = self.nodes[0].generate(1)[-1]
            self.sync_all()
            c = self.nodes[0].getblockcount()
            blocks_d[i] = bl
            block_heights_d[i] = c

        # the first of the 3 certificates has reached maturity and Node2 has a consistent balance
        bal = self.nodes[2].getbalance()
        print("Node2 balance = {}".format(bal))
        assert_equal(
            bal,
            Decimal('1.02') + Decimal('0.001') + Decimal('0.002') +
            Decimal('0.003'))

        mark_logs("Calling listsinceblock on Node2 for all transactions",
                  self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock("", 1, False, True)
        # pprint.pprint(ret)

        mat_block_hash = self.nodes[2].getblockhash(mat_height_d[0])
        # first cert is there and its backward transfer to Node2 is mature
        # we also have one ordinary output from this cert, and we should have no maturity info
        cert = certs_d[0]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['category'], 'receive')
                assert_equal(x['blockhash'], blocks_d[0])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['amount'], Decimal('1.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    assert_equal(x['maturityblockhash'], mat_block_hash)
                    found_bwt = True
                else:
                    assert_false('maturityblockhash' in x)
                    assert_equal(x['amount'], Decimal('0.001'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # cert 2 is there and is immature
        # we also have one ordinary output from this cert
        cert = certs_d[1]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[1])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('2.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.002'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # last cert is there and is immature
        # we also have one ordinary output from this cert
        cert = certs_d[2]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[2])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('3.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.003'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # calling the cmd targeting the block where the second certificate has been mined
        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(
                block_heights_d[1], blocks_d[1]), self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(blocks_d[1], 1, False, True)
        pprint.pprint(ret)

        cert = certs_d[0]
        # first cert is there, it is mature and it refers to the block where it matured
        # we should not see the standard output anymore
        mat_block_hash = self.nodes[2].getblockhash(mat_height_d[0])
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
                assert_equal(x['amount'], Decimal('1.02'))
                assert_equal(x['category'], 'receive')
                assert_equal(x['blockhash'], blocks_d[0])
                assert_equal(x['maturityblockhash'], mat_block_hash)
                assert_equal(x['isBackwardTransfer'], True)
        assert_true(found)

        # cert 2 is not there (since-block is not part of the range)
        cert = certs_d[1]
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
        assert_false(found)

        # last cert is there and is immature, we have also standard output
        cert = certs_d[2]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[2])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('3.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.003'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # calling the cmd targeting the block where the last certificate has been mined
        # There must be no certificates at all, since none of them is contained or matures in this block range
        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(
                block_heights_d[2], blocks_d[2]), self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(blocks_d[2], 1, False, True)
        assert_true(len(ret['transactions']) == 0)

        # reach the height of the second certificate and re-issue the command
        c = self.nodes[0].getblockcount()
        mark_logs("Node 0 generates {} block".format(mat_height_d[1] - c),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(mat_height_d[1] - c)
        self.sync_all()
        print("chain height = {}".format(self.nodes[0].getblockcount()))

        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(
                block_heights_d[2], blocks_d[2]), self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(blocks_d[2], 1, False, True)

        cert = certs_d[0]
        # first cert is not there
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
        assert_false(found)

        cert = certs_d[1]
        # second cert is there, it is mature and it refers to the block where it matured
        found = False
        mat_block_hash = self.nodes[2].getblockhash(mat_height_d[1])
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
                assert_equal(x['amount'], Decimal('2.02'))
                assert_equal(x['category'], 'receive')
                assert_equal(x['blockhash'], blocks_d[1])
                assert_equal(x['maturityblockhash'], mat_block_hash)
                assert_equal(x['isBackwardTransfer'], True)
        assert_true(found)

        cert = certs_d[2]
        # last cert is not there
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
        assert_false(found)

        # get the block before the one containing the last certificate
        h = block_heights_d[2] - 1
        bl = self.nodes[0].getblockhash(h)

        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(h, bl),
            self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(bl, 1, False, True)

        # last cert is there and is immature
        # we also have one ordinary output from this cert
        cert = certs_d[2]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[2])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('3.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.003'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # reach the height of the third certificate, that will make the SC cease, and re-issue the command
        c = self.nodes[0].getblockcount()
        mark_logs("Node 0 generates {} block".format(mat_height_d[2] - c),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(mat_height_d[2] - c)
        self.sync_all()
        print("chain height = {}".format(self.nodes[0].getblockcount()))

        ret = self.nodes[0].getscinfo(scid, False, False)['items'][0]
        assert_equal(ret['ceasingHeight'], mat_height_d[2])
        assert_equal(ret['state'], "CEASED")

        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(h, bl),
            self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(bl, 1, False, True)

        # last cert bwt is not there anymore as expected
        # but we still have one ordinary output from this cert
        cert = certs_d[2]
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
                assert_false('isBackwardTransfer' in x)
                assert_equal(x['blockhash'], blocks_d[2])
                assert_equal(x['category'], 'receive')
                assert_equal(x['amount'], Decimal('0.003'))
        assert_true(found)
Пример #12
0
    def run_test(self):

        #amounts
        creation_amount = Decimal("50")
        bwt_amount = Decimal("5")
        tAddr1 = self.nodes[1].getnewaddress()
        node1Addr = self.nodes[1].validateaddress(tAddr1)['address']
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        ########### Create the sidechain ##################
        print("########### Create the sidechain ##################")

        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        cmdInput = {
            "version": 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'toaddress': "dada",
            'amount': creation_amount,
            'wCertVk': vk,
            'constant': constant
        }

        ret = self.nodes[0].sc_create(cmdInput)
        creating_tx = ret['txid']
        scid = ret['scid']
        scid_swapped = str(swap_bytes(scid))
        self.sync_all()

        decoded_tx = self.nodes[0].getrawtransaction(creating_tx, 1)
        assert_equal(scid, decoded_tx['vsc_ccout'][0]['scid'])

        sc_creation_block_hash = self.nodes[0].generate(1)[0]
        sc_creation_block = self.nodes[0].getblock(sc_creation_block_hash)
        self.sync_all()

        #Advance for 1 Epoch
        self.nodes[0].generate(EPOCH_LENGTH)
        self.sync_all()

        ########### Mine Certificate 1 with quality = 5 ##################
        print(
            "########### Mine Certificate 1 with quality = 5 ##################"
        )

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 5
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount])

        amount_cert_1 = [{"address": node1Addr, "amount": bwt_amount}]

        self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                          epoch_cum_tree_hash, proof,
                                          amount_cert_1, FT_SC_FEE,
                                          MBTR_SC_FEE, CERT_FEE)
        self.sync_all()
        maturityHeight = sc_creation_block["height"] + (
            EPOCH_LENGTH * 2) + EPOCH_LENGTH * 0.2 - 1

        #Add to mempool Certificate 2 with quality = 7
        print(
            "########### Add to mempool Certificate 2 with quality = 7 ##################"
        )
        quality = 7
        bwt_amount2 = Decimal("7")
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount2])

        amount_cert_2 = [{"address": node1Addr, "amount": bwt_amount2}]

        self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                          epoch_cum_tree_hash, proof,
                                          amount_cert_2, FT_SC_FEE,
                                          MBTR_SC_FEE, CERT_FEE)
        self.sync_all()

        #Mine a block
        self.nodes[0].generate(1)
        self.sync_all()

        #Mine a block with a new Certificate 3 with quality = 8
        print(
            "########### Mine a block with a new Certificate 3 with quality = 8 ##################"
        )
        quality = 8
        bwt_amount3 = Decimal("7")
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount3])

        amount_cert_3 = [{"address": node1Addr, "amount": bwt_amount3}]

        cert3 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_3, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)
        self.sync_all()
        cert3_block = self.nodes[0].generate(1)[0]
        self.sync_all()

        #Advance of 1 epoch
        print("########### Advance of 1 epoch ##################")
        self.nodes[0].generate(116)
        self.sync_all()

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 9
        bwt_amount4 = Decimal("9")
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount4])

        amount_cert_4 = [{"address": node1Addr, "amount": bwt_amount4}]

        self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                          epoch_cum_tree_hash, proof,
                                          amount_cert_4, FT_SC_FEE,
                                          MBTR_SC_FEE, CERT_FEE)

        cert4_block = self.nodes[0].generate(1)[0]
        self.sync_all()

        #Enter in the next epoch
        new_epoch_block = self.nodes[0].generate(1)[0]
        self.sync_all()

        rpcCertBlock = self.nodes[0].getblock(cert3_block, 2)
        cert_3_json = {}
        for cert in rpcCertBlock['cert']:
            if (cert['txid'] == cert3):
                cert_3_json = cert
        assert_true(cert_3_json != {})
        tipHeight = self.nodes[0].getblockcount()

        #Test that we require -maturityheightindex=1 to run the getblockexpanded
        try:
            self.nodes[1].getblockexpanded("640")
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            print(errorString)
            assert ("maturityHeightIndex option not set: can not retrieve info"
                    in errorString)

        #Test that we see the certificate 3 but non the certificate 2 and 1
        for i in range(1, tipHeight + 1):
            rpcDataByHeight = self.nodes[0].getblockexpanded(str(i))
            rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded(
                str(i), 2)
            rpcDataByHash = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'])
            rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'], 2)

            if (rpcDataByHash['height'] >= MINIMAL_SC_HEIGHT):
                assert_true('matureCertificate' in rpcDataByHash)
                assert_true('matureCertificate' in rpcDataByHeight)
                assert_true('matureCertificate' in rpcDataByHashVerbosity)
                assert_true('matureCertificate' in rpcDataByHeightVerbosity)
                if (rpcDataByHash['height'] == int(maturityHeight)):
                    assert_equal(len(rpcDataByHash['matureCertificate']), 1)
                    assert_equal(len(rpcDataByHeight['matureCertificate']), 1)
                    assert_equal(rpcDataByHash['matureCertificate'][0], cert3)
                    assert_equal(rpcDataByHeight['matureCertificate'][0],
                                 cert3)
                    assert_equal(
                        len(rpcDataByHashVerbosity['matureCertificate']), 1)
                    assert_equal(
                        len(rpcDataByHeightVerbosity['matureCertificate']), 1)
                    assert_equal(
                        rpcDataByHashVerbosity['matureCertificate'][0],
                        cert_3_json)
                    assert_equal(
                        rpcDataByHeightVerbosity['matureCertificate'][0],
                        cert_3_json)
                else:
                    assert_equal(len(rpcDataByHash['matureCertificate']), 0)
                    assert_equal(len(rpcDataByHeight['matureCertificate']), 0)
                    assert_equal(
                        len(rpcDataByHashVerbosity['matureCertificate']), 0)
                    assert_equal(
                        len(rpcDataByHeightVerbosity['matureCertificate']), 0)
            else:
                assert_false('matureCertificate' in rpcDataByHash)
                assert_false('matureCertificate' in rpcDataByHeight)
                assert_false('matureCertificate' in rpcDataByHashVerbosity)
                assert_false('matureCertificate' in rpcDataByHeightVerbosity)

        self.nodes[0].invalidateblock(new_epoch_block)
        self.nodes[0].invalidateblock(cert4_block)
        self.nodes[1].invalidateblock(new_epoch_block)
        self.nodes[1].invalidateblock(cert4_block)
        assert_equal(self.nodes[0].getblockcount(), 639)
        assert_equal(self.nodes[1].getblockcount(), 639)

        self.nodes[0].clearmempool()
        self.nodes[1].clearmempool()
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        assert_equal(len(self.nodes[1].getrawmempool()), 0)
        self.sync_all()

        fake_block = self.nodes[0].generate(1)[0]
        self.sync_all()

        rpcDataByHeight = self.nodes[0].getblockexpanded("640")
        rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded("640", 2)
        rpcDataByHash = self.nodes[0].getblockexpanded(rpcDataByHeight['hash'])
        rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
            rpcDataByHeight['hash'], 2)
        assert_equal(len(rpcDataByHash['matureCertificate']), 0)
        assert_equal(len(rpcDataByHeight['matureCertificate']), 0)
        assert_equal(len(rpcDataByHashVerbosity['matureCertificate']), 0)
        assert_equal(len(rpcDataByHeightVerbosity['matureCertificate']), 0)

        self.nodes[0].invalidateblock(fake_block)
        self.nodes[1].invalidateblock(fake_block)

        self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                          epoch_cum_tree_hash, proof,
                                          amount_cert_4, FT_SC_FEE,
                                          MBTR_SC_FEE, CERT_FEE)
        self.nodes[0].generate(2)
        self.sync_all()

        rpcDataByHeight = self.nodes[0].getblockexpanded("640")
        rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded("640", 2)
        rpcDataByHash = self.nodes[0].getblockexpanded(rpcDataByHeight['hash'])
        rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
            rpcDataByHeight['hash'], 2)
        assert_equal(len(rpcDataByHash['matureCertificate']), 1)
        assert_equal(len(rpcDataByHeight['matureCertificate']), 1)
        assert_equal(len(rpcDataByHashVerbosity['matureCertificate']), 1)
        assert_equal(len(rpcDataByHeightVerbosity['matureCertificate']), 1)
        assert_equal(rpcDataByHashVerbosity['matureCertificate'][0],
                     cert_3_json)
        assert_equal(rpcDataByHeightVerbosity['matureCertificate'][0],
                     cert_3_json)
        assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['state'],
                     "ALIVE")

        #Let the sidechain cease
        self.nodes[0].generate(130)
        self.sync_all()

        assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['state'],
                     "CEASED")
        tipHeightCeased = self.nodes[0].getblockcount()

        for i in range(tipHeight, tipHeightCeased + 1):
            rpcDataByHeight = self.nodes[0].getblockexpanded(str(i))
            rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded(
                str(i), 2)
            rpcDataByHash = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'])
            rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'], 2)

            assert_equal(len(rpcDataByHash['matureCertificate']), 0)
            assert_equal(len(rpcDataByHeight['matureCertificate']), 0)
            assert_equal(len(rpcDataByHashVerbosity['matureCertificate']), 0)
            assert_equal(len(rpcDataByHeightVerbosity['matureCertificate']), 0)
Пример #13
0
class sc_block_partitions(BitcoinTestFramework):
    alert_filename = None

    def setup_chain(self, split=False):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)
        self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
        with open(self.alert_filename, 'w'):
            pass  # Just open then close to create zero-length file

    def setup_network(self, split=False):

        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[[
                '-logtimemicros=1', '-debug=py', '-debug=sc', '-debug=mempool',
                '-debug=cert', '-debug=bench',
                '-blockmaxsize=%d' % TEST_BLOCK_MAX_SIZE,
                '-blocktxpartitionmaxsize=%d' %
                TEST_BLOCK_TX_PARTITION_MAX_SIZE,
                '-blockprioritysize=%d' % TEST_BLOCK_PRIORITY_SIZE,
                '-scproofqueuesize=0'
            ]] * NUMB_OF_NODES)

        connect_nodes_bi(self.nodes, 0, 1)
        self.is_network_split = split
        self.sync_all()

    def run_test(self):
        '''
        Setup a node with a custom size for block size and tx partition size.
        Create a SC, advance epoch and create a bunch of certificates with progressive quality and high fee.
        Create also a number of txes with lower fee than certs and whose total size exceeds the tx partition size.
        - Check that the block is filled by high-fee certs and only the reminder of free space is taken up by txes
        - Check that only reserved block partition is occupied despite a greater block size
        '''
        def create_sc(cmdInput, node):
            try:
                res = node.sc_create(cmdInput)
                tx = res['txid']
                scid = res['scid']
            except JSONRPCException, e:
                errorString = e.error['message']
                mark_logs(errorString, self.nodes, DEBUG_MODE)
                assert_true(False)

            return tx, scid

        # network topology: (0)--(1)

        print "Miners have max block size = {}, max tx partition size = {}".format(
            TEST_BLOCK_MAX_SIZE, TEST_BLOCK_TX_PARTITION_MAX_SIZE)

        mark_logs("Node 1 generates {} block".format(100), self.nodes,
                  DEBUG_MODE)
        self.nodes[1].generate(100)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT - 100),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 100)
        self.sync_all()

        #generate Vks and constant
        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)

        certVk = certMcTest.generate_params('scs')

        constant = generate_random_field_element_hex()

        amount = 1.0

        #-------------------------------------------------------
        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'amount': amount,
            'fee': 0.0001,
            'constant': constant,
            'wCertVk': certVk,
            'toaddress': "cdcd",
        }

        tx, scid = create_sc(cmdInput, self.nodes[0])
        mark_logs("Created SC with scid={} via tx={}".format(scid, tx),
                  self.nodes, DEBUG_MODE)
        self.sync_all()

        # advance epoch
        self.nodes[0].generate(EPOCH_LENGTH)
        self.sync_all()
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)

        mark_logs("Creating certs...", self.nodes, DEBUG_MODE)
        proofs = []
        q = 10
        tot_num_cert = 0
        tot_cert_sz = 0
        scid_swapped = str(swap_bytes(scid))

        while True:
            t0 = time.time()
            proof = certMcTest.create_test_proof("scs", scid_swapped,
                                                 epoch_number,
                                                 (q + tot_num_cert),
                                                 MBTR_SC_FEE, FT_SC_FEE,
                                                 epoch_cum_tree_hash, constant,
                                                 [], [], [])
            assert_true(proof != None)
            t1 = time.time()
            print "...proof generated: {} secs".format(t1 - t0)
            proofs.append(proof)

            try:
                cert = self.nodes[0].sc_send_certificate(
                    scid, epoch_number, (q + tot_num_cert),
                    epoch_cum_tree_hash, proof, [], FT_SC_FEE, MBTR_SC_FEE,
                    CERT_FEE, "", [], [])
            except JSONRPCException, e:
                errorString = e.error['message']
                print "Send certificate failed with reason {}".format(
                    errorString)
                assert (False)
            self.sync_all()
            tot_num_cert += 1

            #mark_logs("cert={}".format(cert), self.nodes, DEBUG_MODE)
            hexCert = self.nodes[0].getrawtransaction(cert)
            tot_cert_sz += len(hexCert) // 2
            #print "sz=", len(hexCert)//2
            if tot_cert_sz > TEST_BLOCK_MAX_SIZE:
                break
Пример #14
0
    def run_test(self):
        '''
        This script is useful for the generation of json outputs to be stored in github:
        (https://github.com/HorizenOfficial/zen/tree/master/doc/json-examples)
        ---
        System calls to the zen-cli are used (instead for instance of json.dump()) in order to preserve the exact order 
        of the JSON keys as the one the user gets when sending rpc commands on the console.
        ---
        In order to enable the writing of the cmds output to a file please set the constant WRITE_OUTPUT_TO_FILE to 'True'
        and if needed, set the preferred path where to write to, in the constant JSON_FILES_FOLDER_PATH
        '''
        WRITE_OUTPUT_TO_FILE = False
        JSON_FILES_FOLDER_PATH = "../../doc/json-examples/"

        def _get_path_info(nodeid, fileName):
            node_data_dir = os.path.join(self.options.tmpdir,
                                         "node" + str(nodeid))
            node_conf_dir = os.path.join(node_data_dir, "zen.conf")
            file_with_path = os.path.join(JSON_FILES_FOLDER_PATH + fileName)
            return node_conf_dir, file_with_path

        def dump_json_tx(fileName, tx, nodeid=0):

            if WRITE_OUTPUT_TO_FILE == False:
                return

            node_conf_dir, file_with_path = _get_path_info(nodeid, fileName)

            hex_tx = self.nodes[nodeid].getrawtransaction(tx)
            cmd_ret = subprocess.check_output([
                os.getenv("BITCOINCLI", "zen-cli"), "-conf=" + node_conf_dir,
                "-rpcwait", "decoderawtransaction",
                str(hex_tx).rstrip()
            ])
            with open(file_with_path, 'w') as f:
                f.write(cmd_ret)

        def dump_json_block(fileName, blockhash, verbose=2, nodeid=0):
            if WRITE_OUTPUT_TO_FILE == False:
                return

            node_conf_dir, file_with_path = _get_path_info(nodeid, fileName)

            cmd_ret = subprocess.check_output([
                os.getenv("BITCOINCLI", "zen-cli"), "-conf=" + node_conf_dir,
                "-rpcwait", "getblock", blockhash,
                str(verbose)
            ])
            with open(file_with_path, 'w') as f:
                f.write(cmd_ret)

        def dump_json_getscinfo(fileName, nodeid=0):
            if WRITE_OUTPUT_TO_FILE == False:
                return

            node_conf_dir, file_with_path = _get_path_info(nodeid, fileName)

            cmd_ret = subprocess.check_output([
                os.getenv("BITCOINCLI", "zen-cli"), "-conf=" + node_conf_dir,
                "-rpcwait", "getscinfo", "*"
            ])
            with open(file_with_path, 'w') as f:
                f.write(cmd_ret)

        def dump_json_getblocktemplate(fileName, nodeid=0):
            if WRITE_OUTPUT_TO_FILE == False:
                return

            node_conf_dir, file_with_path = _get_path_info(nodeid, fileName)

            cmd_ret = subprocess.check_output([
                os.getenv("BITCOINCLI", "zen-cli"), "-conf=" + node_conf_dir,
                "-rpcwait", "getblocktemplate"
            ])
            with open(file_with_path, 'w') as f:
                f.write(cmd_ret)

        # network topology: (0)--(1)

        mark_logs("Node 1 generates 2 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        #generate wCertVk and constant
        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = certMcTest.generate_params('sc1')
        cswVk = cswMcTest.generate_params("sc1")
        constant1 = generate_random_field_element_hex()

        amount = Decimal('10.0')
        fee = Decimal('0.000025')
        feCfg = []
        cmtCfg = []

        # all certs must have custom FieldElements with exactly those values as size in bits
        feCfg.append([31, 48, 16])

        # one custom bv element with:
        # - as many bits in the uncompressed form (must be divisible by 254 and 8)
        # - a compressed size that allows the usage of BIT_VECTOR_BUF
        cmtCfg.append([[254 * 4, len(BIT_VECTOR_BUF) / 2]])

        # ascii chars, just for storing a text string
        customData = "746869732069732061207465737420737472696e67"

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'amount': amount,
            'fee': fee,
            'constant': constant1,
            'wCertVk': vk,
            'toaddress': "cdcd",
            'wCeasedVk': cswVk,
            'customData': customData,
            'vFieldElementCertificateFieldConfig': feCfg[0],
            'vBitVectorCertificateFieldConfig': cmtCfg[0],
            'forwardTransferScFee': Decimal('0.001'),
            'mainchainBackwardTransferScFee': Decimal('0.002'),
            'mainchainBackwardTransferRequestDataLength': 2
        }

        mark_logs(
            "\nNode 1 create SC1 with valid vFieldElementCertificateFieldConfig / vBitVectorCertificateFieldConfig pair",
            self.nodes, DEBUG_MODE)
        try:
            res = self.nodes[1].sc_create(cmdInput)
            tx = res['txid']
            scid1 = res['scid']
            scid1_swapped = str(swap_bytes(scid1))
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)

        self.sync_all()
        print("tx = {}".format(tx))

        dump_json_tx('sidechain-creation-output.json', tx)

        # two more SC creations
        #-------------------------------------------------------
        vk = certMcTest.generate_params("sc2")
        constant2 = generate_random_field_element_hex()
        customData = "c0ffee"
        cswVk = ""
        feCfg.append([16])
        cmtCfg.append([])

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'toaddress': "dada",
            'amount': amount,
            'wCertVk': vk,
            'customData': customData,
            'constant': constant2,
            'wCeasedVk': cswVk,
            'vFieldElementCertificateFieldConfig': feCfg[1],
            'vBitVectorCertificateFieldConfig': cmtCfg[1],
            'forwardTransferScFee': 0,
            'mainchainBackwardTransferScFee': 0,
            'mainchainBackwardTransferRequestDataLength': 1
        }

        mark_logs(
            "\nNode 1 create SC2 with valid vFieldElementCertificateFieldConfig / vBitVectorCertificateFieldConfig pair",
            self.nodes, DEBUG_MODE)
        try:
            ret = self.nodes[1].sc_create(cmdInput)
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)
        self.sync_all()

        creating_tx = ret['txid']
        scid2 = ret['scid']
        scid2_swapped = str(swap_bytes(scid2))

        print("tx = {}".format(creating_tx))

        decoded_tx = self.nodes[1].getrawtransaction(creating_tx, 1)
        dec_sc_id = decoded_tx['vsc_ccout'][0]['scid']

        #-------------------------------------------------------
        vk = certMcTest.generate_params("sc3")
        constant3 = generate_random_field_element_hex()
        customData = "badc0ffee"
        feCfg.append([])
        cmtCfg.append([[254 * 8 * 4, 1967]])

        sc_cr = [{
            "version": 0,
            "epoch_length": EPOCH_LENGTH,
            "amount": amount,
            "address": "ddaa",
            "wCertVk": vk,
            "constant": constant3,
            "vFieldElementCertificateFieldConfig": feCfg[2],
            "vBitVectorCertificateFieldConfig": cmtCfg[2]
        }]

        mark_logs(
            "\nNode 0 create SC3 with valid vFieldElementCertificateFieldConfig / vBitVectorCertificateFieldConfig pair",
            self.nodes, DEBUG_MODE)
        try:
            rawtx = self.nodes[0].createrawtransaction([], {}, [], sc_cr)
            funded_tx = self.nodes[0].fundrawtransaction(rawtx)
            sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'])
            creating_tx = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)
        self.sync_all()

        decoded_tx = self.nodes[0].getrawtransaction(creating_tx, 1)
        scid3 = decoded_tx['vsc_ccout'][0]['scid']
        print("tx = {}".format(creating_tx))

        #-------------------------------------------------------
        mark_logs("\nNode 0 generates 1 block confirming SC creations",
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()

        # send funds to SC1
        amounts = []
        fwt_amount_1 = Decimal("2.0")
        fwt_amount_2 = Decimal("10.0")
        fwt_amount_3 = Decimal("3.0")
        fwt_amount_many = fwt_amount_1 + fwt_amount_2 + fwt_amount_3

        mark_logs(
            "\nNode 0 sends 3 amounts to SC 1 (tot: " + str(fwt_amount_many) +
            ")", self.nodes, DEBUG_MODE)
        mc_return_address1 = self.nodes[0].getnewaddress()
        mc_return_address2 = self.nodes[0].getnewaddress()
        mc_return_address3 = self.nodes[0].getnewaddress()
        amounts.append({
            "toaddress": "add1",
            "amount": fwt_amount_1,
            "scid": scid1,
            "mcReturnAddress": mc_return_address1
        })
        amounts.append({
            "toaddress": "add2",
            "amount": fwt_amount_2,
            "scid": scid2,
            "mcReturnAddress": mc_return_address2
        })
        amounts.append({
            "toaddress": "add3",
            "amount": fwt_amount_3,
            "scid": scid3,
            "mcReturnAddress": mc_return_address3
        })
        tx = self.nodes[0].sc_send(amounts)
        self.sync_all()

        print("tx = {}".format(tx))
        dump_json_tx('forward-transfer-output.json', tx)

        # request some mainchain backward transfer
        mark_logs("\nNode0 creates a tx with a bwt request", self.nodes,
                  DEBUG_MODE)
        fe1 = generate_random_field_element_hex()
        fe2 = generate_random_field_element_hex()
        fe3 = generate_random_field_element_hex()
        mc_dest_addr0 = self.nodes[0].getnewaddress()
        mc_dest_addr1 = self.nodes[1].getnewaddress()
        outputs = [{
            'vScRequestData': [fe1, fe2],
            'scFee': Decimal("0.0025"),
            'scid': scid1,
            'mcDestinationAddress': mc_dest_addr0
        }, {
            'vScRequestData': [fe3],
            'scFee': Decimal("0.0026"),
            'scid': scid2,
            'mcDestinationAddress': mc_dest_addr1
        }]

        cmdParms = {"minconf": 0, "changeaddress": mc_dest_addr0}
        try:
            tx = self.nodes[0].sc_request_transfer(outputs, cmdParms)
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)
        print("tx = {}".format(tx))
        dump_json_tx('mainchain-backward-transfer-request.json', tx)

        #-------------------------------------------------------
        # advance epoch
        mark_logs("\nNode 0 generates {} block".format(EPOCH_LENGTH - 1),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(EPOCH_LENGTH - 1)
        self.sync_all()

        epoch_number_1, epoch_cum_tree_hash_1 = get_epoch_data(
            scid1, self.nodes[0], EPOCH_LENGTH)
        mark_logs(
            "epoch_number = {}, epoch_cum_tree_hash = {}".format(
                epoch_number_1, epoch_cum_tree_hash_1), self.nodes, DEBUG_MODE)

        addr_node1a = self.nodes[1].getnewaddress()
        addr_node1b = self.nodes[1].getnewaddress()
        addr_node0 = self.nodes[1].getnewaddress()
        bwt_amount_1 = Decimal("0.2")
        bwt_amount_2 = Decimal("0.15")

        # get a UTXO
        utx, change = get_spendable(self.nodes[0], CERT_FEE)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {addr_node0: change}
        bwt_outs = [{
            "address": addr_node1a,
            "amount": bwt_amount_1
        }, {
            "address": addr_node1b,
            "amount": bwt_amount_2
        }]
        addresses = []
        amounts = []

        # preserve order for proof validity
        for entry in bwt_outs:
            addresses.append(entry["address"])
            amounts.append(entry["amount"])

        #-------------------------------------------------------
        mark_logs(
            "\nCreate raw cert with good custom field elements for SC2...",
            self.nodes, DEBUG_MODE)
        # cfgs for SC2: [16], []
        # we must be careful with ending bits for having valid fe.
        vCfe = ["0100"]
        vCmt = []

        # serialized fe for the proof has 32 byte size
        fe1 = get_field_element_with_padding("0100", 0)

        quality = 72
        scProof3 = certMcTest.create_test_proof('sc2', scid2_swapped,
                                                epoch_number_1, quality,
                                                MBTR_SC_FEE, FT_SC_FEE,
                                                epoch_cum_tree_hash_1,
                                                constant2, addresses, amounts,
                                                [fe1])

        params = {
            'scid': scid2,
            'quality': quality,
            'endEpochCumScTxCommTreeRoot': epoch_cum_tree_hash_1,
            'scProof': scProof3,
            'withdrawalEpochNumber': epoch_number_1,
            'vFieldElementCertificateField': vCfe,
            'vBitVectorCertificateField': vCmt,
            'ftScFee': FT_SC_FEE,
            'mbtrScFee': MBTR_SC_FEE
        }

        try:
            rawcert = self.nodes[0].createrawcertificate(
                inputs, outputs, bwt_outs, params)
            signed_cert = self.nodes[0].signrawtransaction(rawcert)
            cert = self.nodes[0].sendrawtransaction(signed_cert['hex'])
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(
                "Send certificate failed with reason {}".format(errorString),
                self.nodes, DEBUG_MODE)
            assert (False)

        self.sync_all()
        print("cert = {}".format(cert))

        #-------------------------------------------------------
        # get another UTXO
        utx, change = get_spendable(self.nodes[0], CERT_FEE)
        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): change}

        mark_logs(
            "\nCreate raw cert with good custom field elements for SC1...",
            self.nodes, DEBUG_MODE)

        # Any number ending with 0x00 is not over module for being a valid field element, therefore it is OK
        vCfe = ["ab000100", "ccccdddd0000", "0100"]
        # this is a compressed buffer which will yield a valid field element for the proof (see below)
        vCmt = [BIT_VECTOR_BUF]

        fe1 = get_field_element_with_padding("ab000100", 0)
        fe2 = get_field_element_with_padding("ccccdddd0000", 0)
        fe3 = get_field_element_with_padding("0100", 0)
        fe4 = BIT_VECTOR_FE

        quality = 18
        scProof3 = certMcTest.create_test_proof('sc1', scid1_swapped,
                                                epoch_number_1, quality,
                                                MBTR_SC_FEE, FT_SC_FEE,
                                                epoch_cum_tree_hash_1,
                                                constant1, addresses, amounts,
                                                [fe1, fe2, fe3, fe4])

        params = {
            'scid': scid1,
            'quality': quality,
            'endEpochCumScTxCommTreeRoot': epoch_cum_tree_hash_1,
            'scProof': scProof3,
            'withdrawalEpochNumber': epoch_number_1,
            'vFieldElementCertificateField': vCfe,
            'vBitVectorCertificateField': vCmt,
            'ftScFee': FT_SC_FEE,
            'mbtrScFee': MBTR_SC_FEE
        }

        try:
            rawcert = self.nodes[0].createrawcertificate(
                inputs, outputs, bwt_outs, params)
            signed_cert = self.nodes[0].signrawtransaction(rawcert)
            cert = self.nodes[0].sendrawtransaction(signed_cert['hex'])
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(
                "Send certificate failed with reason {}".format(errorString),
                self.nodes, DEBUG_MODE)
            assert (False)
        self.sync_all()

        print("cert = {}".format(cert))
        dump_json_tx('certificate-with-backward-transfer.json', cert)

        # add a pair of standard txes
        self.nodes[0].sendtoaddress(addr_node1a, Decimal('0.1'))
        self.nodes[1].sendtoaddress(addr_node0, Decimal('0.2'))

        dump_json_getblocktemplate('getblocktemplate.json', nodeid=0)

        bl = self.nodes[0].generate(1)[-1]
        self.sync_all()

        dump_json_block('block-with-certificates.json', bl, 1)
        dump_json_block('block-with-certificates-expanded.json', bl, 2)

        # advance one epochs for SC1 and let the others cease
        mark_logs(
            "\nLet 1 epoch pass by and send a cert for SC1 only...".format(
                EPOCH_LENGTH), self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid1, "sc1",
                                           constant1, EPOCH_LENGTH, 10,
                                           CERT_FEE, FT_SC_FEE, MBTR_SC_FEE,
                                           vCfe, vCmt, [fe1, fe2, fe3, fe4])

        mark_logs(
            "\n==> certificate from SC1 for epoch {} {}".format(
                epoch_number, cert), self.nodes, DEBUG_MODE)

        dump_json_getscinfo('getscinfo-output.json', nodeid=0)

        mark_logs("Let also SC1 cease... ".format(scid2), self.nodes,
                  DEBUG_MODE)

        nbl = int(EPOCH_LENGTH * 1.5)
        mark_logs("Node0 generates {} blocks".format(nbl), self.nodes,
                  DEBUG_MODE)
        # let all sidechains cease
        self.nodes[0].generate(3 * EPOCH_LENGTH)
        self.sync_all()

        mark_logs(
            "\nCreate a CSW for SC1 withdrawing coins for two different addresses... ",
            self.nodes, DEBUG_MODE)

        # CSW sender MC address
        csw_mc_address = self.nodes[0].getnewaddress()

        sc_csw_amount_0 = Decimal('2.0')
        sc_csw_amount_1 = Decimal('1.0')
        null0 = generate_random_field_element_hex()
        null1 = generate_random_field_element_hex()
        actCertData = self.nodes[0].getactivecertdatahash(
            scid1)['certDataHash']

        ceasingCumScTxCommTree = self.nodes[0].getceasingcumsccommtreehash(
            scid1)['ceasingCumScTxCommTree']

        sc_proof0 = cswMcTest.create_test_proof("sc1", sc_csw_amount_0,
                                                scid1_swapped, null0,
                                                csw_mc_address,
                                                ceasingCumScTxCommTree,
                                                actCertData, constant1)

        sc_proof1 = cswMcTest.create_test_proof("sc1", sc_csw_amount_1,
                                                scid1_swapped, null1,
                                                csw_mc_address,
                                                ceasingCumScTxCommTree,
                                                actCertData, constant1)

        sc_csws = [{
            "amount": sc_csw_amount_0,
            "senderAddress": csw_mc_address,
            "scId": scid1,
            "epoch": 0,
            "nullifier": null0,
            "activeCertData": actCertData,
            "ceasingCumScTxCommTree": ceasingCumScTxCommTree,
            "scProof": sc_proof0
        }, {
            "amount": sc_csw_amount_1,
            "senderAddress": csw_mc_address,
            "scId": scid1,
            "epoch": 0,
            "nullifier": null1,
            "activeCertData": actCertData,
            "ceasingCumScTxCommTree": ceasingCumScTxCommTree,
            "scProof": sc_proof1
        }]

        # recipient MC address
        taddr_0 = self.nodes[0].getnewaddress()
        taddr_1 = self.nodes[1].getnewaddress()
        sc_csw_tx_outs = {taddr_0: sc_csw_amount_0, taddr_1: sc_csw_amount_1}

        rawtx = self.nodes[0].createrawtransaction([], sc_csw_tx_outs, sc_csws)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'], None,
                                                    None, "NONE")
        tx = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
        mark_logs("sent csw retrieving coins on Node0 and Node1 behalf",
                  self.nodes, DEBUG_MODE)
        self.sync_all()

        print("tx = {}".format(tx))
        dump_json_tx('ceased-sidechain-withdrawal.json', tx)
Пример #15
0
class sc_cert_bwt_amount_rounding(BitcoinTestFramework):
    alert_filename = None

    def setup_chain(self, split=False):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)
        self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
        with open(self.alert_filename, 'w'):
            pass  # Just open then close to create zero-length file

    def setup_network(self, split=False):

        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[[
                '-logtimemicros=1', '-debug=py', '-debug=sc', '-debug=mempool',
                '-debug=cert', '-debug=bench', '-scproofqueuesize=0'
            ]] * NUMB_OF_NODES)

        connect_nodes_bi(self.nodes, 0, 1)
        self.is_network_split = split
        self.sync_all()

    def run_test(self):
        def create_sc(cmdInput, node):
            try:
                res = node.sc_create(cmdInput)
                tx = res['txid']
                scid = res['scid']
            except JSONRPCException, e:
                errorString = e.error['message']
                mark_logs(errorString, self.nodes, DEBUG_MODE)
                assert_true(False)

            return tx, scid

        '''
        Purpose of this test is to verify that a decimal amount with many decimal digits is correctly handled, expecially
        with reference to the compatibility between creation and verification of the proof, which are performed by the test
        framework and the zend_oo core implementations.
        '''
        # network topology: (0)--(1)

        mark_logs("Node 1 generates {} block".format(2), self.nodes,
                  DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 2)
        self.sync_all()

        #generate Vks and constant
        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)

        certVk = certMcTest.generate_params('scs')
        constant = generate_random_field_element_hex()
        cr_amount = 1000.0

        #-------------------------------------------------------
        fee = 0.000025

        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'amount': cr_amount,
            'fee': fee,
            'constant': constant,
            'wCertVk': certVk,
            'toaddress': "cdcd"
        }

        tx, scid = create_sc(cmdInput, self.nodes[0])
        mark_logs("Created SC with scid={} via tx={}".format(scid, tx),
                  self.nodes, DEBUG_MODE)
        self.sync_all()
        hexTx = self.nodes[0].getrawtransaction(tx)
        print "sz=", len(hexTx) // 2

        # advance epoch
        self.nodes[0].generate(EPOCH_LENGTH)
        self.sync_all()
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)

        NUM_OF_BWT = 1
        print "==============================================================================================================================================================================="
        print "Adding {} backward transfers to certificate".format(NUM_OF_BWT)
        print "==============================================================================================================================================================================="

        bwt_amount = Decimal('1.952929687000111')

        print "bwt amount {}".format(bwt_amount)
        bwt_cert = []
        addr_array = []
        bwt_amount_array = []
        proof = None
        addr_node1 = self.nodes[1].getnewaddress()

        for _ in range(0, NUM_OF_BWT):

            addr_array.append(addr_node1)
            bwt_amount_array.append(bwt_amount)

            entry = {"address": addr_node1, "amount": bwt_amount}
            bwt_cert.append(entry)
            pprint.pprint(entry)

        print "Generating cert proof..."
        t0 = time.time()
        q = 10
        scid_swapped = str(swap_bytes(scid))
        print "---------------------"
        proof = certMcTest.create_test_proof("scs", scid_swapped, epoch_number,
                                             q, MBTR_SC_FEE, FT_SC_FEE,
                                             epoch_cum_tree_hash, constant,
                                             addr_array, bwt_amount_array)
        assert_true(proof != None)
        t1 = time.time()
        print "...proof with sz={} generated: {} secs".format(
            len(proof) // 2, t1 - t0)

        try:
            cert = self.nodes[0].sc_send_certificate(scid, epoch_number, q,
                                                     epoch_cum_tree_hash,
                                                     proof, bwt_cert,
                                                     FT_SC_FEE, MBTR_SC_FEE,
                                                     CERT_FEE)
        except JSONRPCException, e:
            errorString = e.error['message']
            print "Send certificate failed with reason {}".format(errorString)
            assert (False)
Пример #16
0
    def run_test(self):
        '''
        The test checks that the "GetBlockTemplate" command correctly detects a new certificate in the mempool,
        in the same way as it happens for normal transactions.
        '''

        # amounts
        creation_amount = Decimal("10")
        bwt_amount = Decimal("1.0")

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()
        cmdInput = {
            "version": 0,
            "withdrawalEpochLength": EPOCH_LENGTH,
            "toaddress": "dada",
            "amount": creation_amount,
            "wCertVk": vk,
            "constant": constant,
        }

        ret = self.nodes[0].sc_create(cmdInput)
        scid = ret['scid']
        scid_swapped = str(swap_bytes(scid))
        mark_logs("Node 0 created a SC", self.nodes, DEBUG_MODE)

        nblocks = EPOCH_LENGTH
        mark_logs(
            "Node 0 generating {} more blocks to confirm the sidechain and reach the end of withdrawal epoch"
            .format(nblocks), self.nodes, DEBUG_MODE)
        self.nodes[0].generate(nblocks)
        self.sync_all()

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        addr_node1 = self.nodes[1].getnewaddress()

        #Create proof for WCert
        quality = 10
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [addr_node1], [bwt_amount])

        amount_cert_1 = [{"address": addr_node1, "amount": bwt_amount}]

        cur_h = self.nodes[0].getblockcount()
        ret = self.nodes[0].getscinfo(scid, True, False)['items'][0]
        ceas_h = ret['ceasingHeight']
        ceas_limit_delta = ceas_h - cur_h - 1

        mark_logs(
            "Node0 generating {} blocks reaching the third to last block before the SC ceasing"
            .format(ceas_limit_delta), self.nodes, DEBUG_MODE)
        self.nodes[0].generate(ceas_limit_delta - 2)
        self.sync_all()

        mark_logs(
            "\nCall GetBlockTemplate on each node to create a cached (empty) version",
            self.nodes, DEBUG_MODE)
        for i in range(0, NUMB_OF_NODES):
            self.nodes[i].getblocktemplate()

        mark_logs(
            "Node 0 sends a normal mainchain transaction to mempool and checks that it's not immediately included into the block template",
            self.nodes, DEBUG_MODE)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 0.1)
        self.sync_all()

        for i in range(0, NUMB_OF_NODES):
            assert (len(self.nodes[i].getblocktemplate()['certificates']) == 0)
            assert (len(self.nodes[i].getblocktemplate()['transactions']) == 0)

        GET_BLOCK_TEMPLATE_DELAY = 5  # Seconds
        mark_logs(
            "Wait {} seconds and check that the transaction is now included into the block template"
            .format(GET_BLOCK_TEMPLATE_DELAY), self.nodes, DEBUG_MODE)
        time.sleep(GET_BLOCK_TEMPLATE_DELAY)
        for i in range(0, NUMB_OF_NODES):
            assert (len(self.nodes[i].getblocktemplate()['certificates']) == 0)
            assert (len(self.nodes[i].getblocktemplate()['transactions']) == 1)

        mark_logs("Node 0 mines one block to clean the mempool", self.nodes,
                  DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()

        mark_logs(
            "\nCall GetBlockTemplate on each node to create a new cached version",
            self.nodes, DEBUG_MODE)
        for i in range(0, NUMB_OF_NODES):
            self.nodes[i].getblocktemplate()

        mark_logs("Node 0 sends a certificate", self.nodes, DEBUG_MODE)
        try:
            cert_epoch_0 = self.nodes[0].sc_send_certificate(
                scid, epoch_number, quality, epoch_cum_tree_hash, proof,
                amount_cert_1, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE)
            assert (len(cert_epoch_0) > 0)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(
                "Send certificate failed with reason {}".format(errorString),
                self.nodes, DEBUG_MODE)
            assert (False)
        actCertData1 = self.nodes[0].getactivecertdatahash(
            scid1)['certDataHash']
        actCertData2 = self.nodes[0].getactivecertdatahash(
            scid2)['certDataHash']

        ceasingCumScTxCommTree1 = self.nodes[0].getceasingcumsccommtreehash(
            scid1)['ceasingCumScTxCommTree']
        ceasingCumScTxCommTree2 = self.nodes[0].getceasingcumsccommtreehash(
            scid2)['ceasingCumScTxCommTree']

        scid1_swapped = swap_bytes(scid1)
        scid2_swapped = swap_bytes(scid2)

        for i in range(MAX_NUM_OF_CSW_INPUTS_PER_SC + 1):

            nullifiers1.append(generate_random_field_element_hex())
            nullifiers2.append(generate_random_field_element_hex())

            csw_proofs1.append(
                cswMcTest.create_test_proof("sc1", sc_csw_amount,
                                            str(scid1_swapped), nullifiers1[i],
                                            csw_mc_address,
                                            ceasingCumScTxCommTree1,
                                            actCertData1, constant1))

            csw_proofs2.append(
                cswMcTest.create_test_proof("sc2", sc_csw_amount,
                                            str(scid2_swapped), nullifiers2[i],
                                            csw_mc_address,
                                            ceasingCumScTxCommTree2,
                                            actCertData2, constant2))
    def run_test(self):
        '''
        Create a SC, advance two epochs and then let it cease.
        Create two transactions, each one containing a CSW with
        an input value covering the whole sidechain balance.
        Even though the first CSW transaction is still in mempool,
        the second one should be rejected.
        '''

        # prepare some coins
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_epoch_len = EPOCH_LENGTH
        sc_cr_amount = Decimal('12.00000000')

        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        vk = certMcTest.generate_params("sc1")
        cswVk = cswMcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        sc_cr = []
        sc_cr.append({
            "version": 0,
            "epoch_length": sc_epoch_len,
            "amount": sc_cr_amount,
            "address": sc_address,
            "wCertVk": vk,
            "wCeasedVk": cswVk,
            "constant": constant
        })

        rawtx = self.nodes[0].createrawtransaction([], {}, [], sc_cr)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'])
        finalRawtx = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
        self.sync_all()

        decoded_tx = self.nodes[2].getrawtransaction(finalRawtx, 1)
        scid = decoded_tx['vsc_ccout'][0]['scid']
        mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE)
        print

        # advance two epochs
        mark_logs("\nLet 2 epochs pass by...", self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid, "sc1",
                                           constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for epoch {} {}".format(epoch_number, cert),
            self.nodes, DEBUG_MODE)

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[0],
                                           self.sync_all, scid, "sc1",
                                           constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for epoch {} {}l".format(epoch_number, cert),
            self.nodes, DEBUG_MODE)

        # mine one block for having last cert in chain
        mark_logs("\nNode0 generates 1 block confirming last cert", self.nodes,
                  DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()

        mark_logs("Let SC cease... ", self.nodes, DEBUG_MODE)

        nbl = int(sc_epoch_len * 1.5)
        mark_logs("Node0 generates {} blocks".format(nbl), self.nodes,
                  DEBUG_MODE)
        self.nodes[0].generate(nbl)
        self.sync_all()

        # check it is really ceased
        ret = self.nodes[0].getscinfo(scid, False, False)['items'][0]
        assert_equal(ret['state'], "CEASED")

        # and has the expected balance
        sc_bal = self.nodes[0].getscinfo(scid, False,
                                         False)['items'][0]['balance']
        assert_equal(sc_bal, sc_cr_amount)

        mark_logs("\nCreate a CSW withdrawing 90% of the sc balance... ",
                  self.nodes, DEBUG_MODE)

        # CSW sender MC address
        csw_mc_address = self.nodes[0].getnewaddress()

        sc_csw_amount = sc_bal * Decimal("0.9")
        null1 = generate_random_field_element_hex()
        actCertData = self.nodes[0].getactivecertdatahash(scid)['certDataHash']
        print "Active Cert Data Hash: -------> ", actCertData

        ceasingCumScTxCommTree = self.nodes[0].getceasingcumsccommtreehash(
            scid)['ceasingCumScTxCommTree']

        scid_swapped = swap_bytes(scid)
        sc_proof1 = cswMcTest.create_test_proof("sc1", sc_csw_amount,
                                                str(scid_swapped), null1,
                                                csw_mc_address,
                                                ceasingCumScTxCommTree,
                                                actCertData, constant)

        sc_csws = [{
            "amount": sc_csw_amount,
            "senderAddress": csw_mc_address,
            "scId": scid,
            "epoch": 0,
            "nullifier": null1,
            "activeCertData": actCertData,
            "ceasingCumScTxCommTree": ceasingCumScTxCommTree,
            "scProof": sc_proof1
        }]

        # recipient MC address
        taddr_2 = self.nodes[2].getnewaddress()
        sc_csw_tx_outs = {taddr_2: sc_csw_amount}

        rawtx = self.nodes[0].createrawtransaction([], sc_csw_tx_outs, sc_csws)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'], None,
                                                    None, "NONE")
        finalRawtx = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
        mark_logs(
            "sent csw 1 {} retrieving {} coins on Node2 behalf".format(
                finalRawtx, sc_csws[0]['amount']), self.nodes, DEBUG_MODE)
        self.sync_all()

        mark_logs("Check csw is in mempool...", self.nodes, DEBUG_MODE)
        assert_true(finalRawtx in self.nodes[2].getrawmempool())

        mark_logs(
            "\nCreate a second CSW withdrawing 90% of the sc balance (should be rejected)... ",
            self.nodes, DEBUG_MODE)

        # CSW sender MC address
        csw_mc_address = self.nodes[0].getnewaddress()

        sc_csw_amount = sc_bal * Decimal("0.9")
        null1 = generate_random_field_element_hex()

        sc_proof1 = cswMcTest.create_test_proof("sc1", sc_csw_amount,
                                                str(scid_swapped), null1,
                                                csw_mc_address,
                                                ceasingCumScTxCommTree,
                                                actCertData, constant)

        sc_csws = [{
            "amount": sc_csw_amount,
            "senderAddress": csw_mc_address,
            "scId": scid,
            "epoch": 0,
            "nullifier": null1,
            "activeCertData": actCertData,
            "ceasingCumScTxCommTree": ceasingCumScTxCommTree,
            "scProof": sc_proof1
        }]

        # recipient MC address
        taddr_2 = self.nodes[2].getnewaddress()
        sc_csw_tx_outs = {taddr_2: sc_csw_amount}

        rawtx = self.nodes[0].createrawtransaction([], sc_csw_tx_outs, sc_csws)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'], None,
                                                    None, "NONE")

        try:
            finalRawtx = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
            assert (False)
        except JSONRPCException, e:
            error_string = e.error['message']
            mark_logs(
                "Failed sending csw 2 {} retrieving {} coins on Node2 behalf, error message: {}"
                .format(finalRawtx, sc_csws[0]['amount'],
                        error_string), self.nodes, DEBUG_MODE)
            assert_true("bad-sc-tx-not-applicable" in error_string)
Пример #19
0
        # Check the sidechain has the expected balance
        sc_bal = self.nodes[0].getscinfo(scid, False,
                                         False)['items'][0]['balance']
        assert_equal(sc_bal, sc_cr_amount)

        # create a tx with 3 CSW for sc
        mark_logs(
            "\nCreate 3 CSWs in a tx withdrawing half the sc balance... ",
            self.nodes, DEBUG_MODE)

        # CSW sender MC address, in taddress and pub key hash formats
        csw_mc_address = self.nodes[0].getnewaddress()

        sc_csw_amount = (sc_bal / 2) / 3
        null_1 = generate_random_field_element_hex()
        null_2 = generate_random_field_element_hex()
        null_3 = generate_random_field_element_hex()

        act_cert_data = self.nodes[0].getactivecertdatahash(
            scid)['certDataHash']
        ceasing_cum_cc_tx_comm_tree = self.nodes[
            0].getceasingcumsccommtreehash(scid)['ceasingCumScTxCommTree']
        pprint.pprint(act_cert_data)

        sc_proof_1 = csw_mc_test.create_test_proof(
            "sc", sc_csw_amount, str(scid_swapped), null_1, csw_mc_address,
            ceasing_cum_cc_tx_comm_tree, act_cert_data, constant)
        sc_proof_2 = csw_mc_test.create_test_proof(
            "sc", sc_csw_amount, str(scid_swapped), null_2, csw_mc_address,
            ceasing_cum_cc_tx_comm_tree, act_cert_data, constant)