def generate_sc_csw_and_csw_tx_out(self, sc_csw_amount, tag, scid, constant, csw_mc_test): csw_mc_address = self.nodes[0].getnewaddress() act_cert_data = self.nodes[0].getactivecertdatahash( scid)['certDataHash'] ceasing_cum_sc_tx_comm_tree = self.nodes[ 0].getceasingcumsccommtreehash(scid)['ceasingCumScTxCommTree'] scid_swapped = swap_bytes(scid) nullifier = generate_random_field_element_hex() sc_proof = csw_mc_test.create_test_proof(tag, sc_csw_amount, scid_swapped, nullifier, csw_mc_address, ceasing_cum_sc_tx_comm_tree, act_cert_data, constant) assert_true(sc_proof is not None) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "nullifier": nullifier, "activeCertData": act_cert_data, "ceasingCumScTxCommTree": ceasing_cum_sc_tx_comm_tree, "scProof": sc_proof }] sc_csw_tx_outs = { self.nodes[0].getnewaddress(): sc_csw_amount - Decimal('0.00001000') } return sc_csws, sc_csw_tx_outs
def template_to_bytes(tmpl, txlist, certlist, input_sc_commitment=None): blkver = pack('<L', tmpl['version']) objlist = txlist + certlist mrklroot = genmrklroot(list(dblsha(a) for a in objlist)) sc_commitment = b'\0' * 32 if input_sc_commitment != None: sc_commitment = input_sc_commitment mark_logs(("sc_commitment set in block template: %s" % swap_bytes(binascii.hexlify(sc_commitment))), NODE_LIST, DEBUG_MODE) timestamp = pack('<L', tmpl['curtime']) nonce = b'\0' * 32 soln = b'\0' blk = blkver + a2b_hex( tmpl['previousblockhash'] )[::-1] + mrklroot + sc_commitment + timestamp + a2b_hex( tmpl['bits'])[::-1] + nonce + soln blk += varlenEncode(len(txlist)) for tx in txlist: blk += tx if tmpl['version'] == SC_CERTIFICATE_BLOCK_VERSION: # fill vector of certificates from this version on blk += varlenEncode(len(certlist)) for cert in certlist: blk += cert return blk
def advance_sidechains_epoch(num_of_scs): for i in range(0, num_of_scs): if i == 0: self.nodes[0].generate(EPOCH_LENGTH) self.sync_all() # these parameters are valid for all scs since they share the same epoch length epoch_number, epoch_cum_tree_hash = get_epoch_data( scids[i], self.nodes[0], EPOCH_LENGTH) print "Generating cert proof..." t0 = time.time() scid_swapped = str(swap_bytes(scids[i])) proof = certMcTest.create_test_proof( "scs", scid_swapped, epoch_number, q, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [], [], proofCfeArray, CERT_NUM_CONSTRAINTS, SEGMENT_SIZE) assert_true(proof != None) t1 = time.time() print "...proof generated: {} secs".format(t1 - t0) try: cert = self.nodes[0].sc_send_certificate( scids[i], epoch_number, q, epoch_cum_tree_hash, proof, [], FT_SC_FEE, MBTR_SC_FEE, CERT_FEE, "", vCfe, vCmt) except JSONRPCException, e: errorString = e.error['message'] print "Send certificate failed with reason {}".format( errorString) assert (False) self.sync_all() mark_logs( "==> certificate for SC{} epoch {} {} (chain height={})". format(i, epoch_number, cert, self.nodes[0].getblockcount()), self.nodes, DEBUG_MODE)
def run_test(self): logging.info("Generating initial blockchain") self.nodes[0].generate(1) sync_blocks(self.nodes) self.nodes[1].generate(1) sync_blocks(self.nodes) self.nodes[2].generate(1) sync_blocks(self.nodes) self.nodes[3].generate(100) sync_blocks(self.nodes) assert_equal(self.nodes[0].getbalance(), 11.4375) assert_equal(self.nodes[1].getbalance(), 11.4375) assert_equal(self.nodes[2].getbalance(), 11.4375) assert_equal(self.nodes[3].getbalance(), 0) logging.info("Creating transactions") # Five rounds of sending each other transactions. for i in range(5): self.do_one_round() logging.info("Backing up") tmpdir = self.options.tmpdir self.nodes[0].backupwallet("walletbak") self.nodes[0].dumpwallet("walletdump") self.nodes[1].backupwallet("walletbak") self.nodes[1].dumpwallet("walletdump") self.nodes[2].backupwallet("walletbak") self.nodes[2].dumpwallet("walletdump") # Verify dumpwallet cannot overwrite an existing file try: self.nodes[2].dumpwallet("walletdump") assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Cannot overwrite existing file" in errorString) logging.info("More transactions") for i in range(5): self.do_one_round() # Generate 101 more blocks, so any fees paid mature self.nodes[3].generate(101) self.sync_all() balance0 = self.nodes[0].getbalance() balance1 = self.nodes[1].getbalance() balance2 = self.nodes[2].getbalance() balance3 = self.nodes[3].getbalance() total = balance0 + balance1 + balance2 + balance3 # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.) # 114 are mature, so the sum of all wallets should be 100*11.4375 + 4 * 11 + 10*8.75 = 1275.25 assert_equal(total, 1275.25) ## # Test restoring spender wallets from backups ## logging.info("Restoring using wallet.dat") self.stop_three() self.erase_three() # Start node2 with no chain shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks") shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") # Restore wallets from backup shutil.copyfile(tmpdir + "/node0/walletbak", tmpdir + "/node0/regtest/wallet.dat") shutil.copyfile(tmpdir + "/node1/walletbak", tmpdir + "/node1/regtest/wallet.dat") shutil.copyfile(tmpdir + "/node2/walletbak", tmpdir + "/node2/regtest/wallet.dat") logging.info("Re-starting nodes") self.start_three() sync_blocks(self.nodes) assert_equal(self.nodes[0].getbalance(), balance0) assert_equal(self.nodes[1].getbalance(), balance1) assert_equal(self.nodes[2].getbalance(), balance2) logging.info("Restoring using dumped wallet") self.stop_three() self.erase_three() #start node2 with no chain shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks") shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") self.start_three() assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0) self.nodes[0].importwallet(tmpdir + "/node0/walletdump") self.nodes[1].importwallet(tmpdir + "/node1/walletdump") self.nodes[2].importwallet(tmpdir + "/node2/walletdump") sync_blocks(self.nodes) assert_equal(self.nodes[0].getbalance(), balance0) assert_equal(self.nodes[1].getbalance(), balance1) assert_equal(self.nodes[2].getbalance(), balance2) # reach sidechain fork nb = int(self.nodes[0].getblockcount()) nb_to_gen = MINIMAL_SC_HEIGHT - nb if nb_to_gen > 0: mark_logs("Node 0 generates {} block".format(nb_to_gen), self.nodes, DEBUG_MODE) self.nodes[0].generate(nb_to_gen) self.sync_all() safe_guard_size = EPOCH_LENGTH // 5 if safe_guard_size < 2: safe_guard_size = 2 creation_amount = Decimal("1.0") bwt_amount1 = Decimal("0.10") bwt_amount2 = Decimal("0.20") bwt_amount3 = Decimal("0.40") prev_epoch_hash = self.nodes[0].getbestblockhash() #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() # do a shielded transaction for testing zaddresses in backup mark_logs("node0 shields it coinbase", self.nodes, DEBUG_MODE) zaddr0 = self.nodes[0].z_getnewaddress() res = self.nodes[0].z_shieldcoinbase("*", zaddr0) wait_and_assert_operationid_status(self.nodes[0], res['opid']) self.sync_all() self.nodes[0].generate(1) self.sync_all() mark_logs("node0 z_send to node1", self.nodes, DEBUG_MODE) zaddr1 = self.nodes[1].z_getnewaddress() opid = self.nodes[0].z_sendmany(zaddr0, [{ "address": zaddr1, "amount": Decimal("1.234") }]) wait_and_assert_operationid_status(self.nodes[0], opid) self.sync_all() # Create a SC 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("created SC id: {}".format(scid), self.nodes, DEBUG_MODE) self.sync_all() mark_logs("Node0 confirms Sc creation generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) sc_creating_height = self.nodes[0].getblockcount() self.sync_all() mark_logs( "Node0 generates {} more blocks to achieve end of withdrawal epochs" .format(EPOCH_LENGTH - 1), 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) n1_initial_balance = self.nodes[1].getbalance() # node0 create a cert_1 for funding node1 # skip default address, just to use a brand new one self.nodes[1].getnewaddress() addr_node1 = self.nodes[1].getnewaddress() amounts = [{ "address": addr_node1, "amount": bwt_amount1 }, { "address": addr_node1, "amount": bwt_amount2 }] mark_logs( "Node 0 sends a cert for scid {} with 2 bwd transfers of {} coins to Node1 address" .format(scid, bwt_amount1 + bwt_amount2, addr_node1), self.nodes, DEBUG_MODE) try: #Create proof for WCert quality = 1 proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node1, addr_node1], [bwt_amount1, bwt_amount2]) cert_1 = self.nodes[0].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("==> certificate is {}".format(cert_1), self.nodes, DEBUG_MODE) self.sync_all() except JSONRPCException, e: errorString = e.error['message'] mark_logs( "Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert (False)
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)
nullifiers1 = [] nullifiers2 = [] csw_proofs1 = [] csw_proofs2 = [] 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(
def run_test(self): ''' Test the accept and removal of certificates in the mempool, checking that the quality is correctly handled and reported as expected in the output of the rpc cmd getaddressmempool(). This test can be run only if the -addressindex', '-timestampindex', '-spentindex' options are supported by the zend_oo binary ''' logging.info("Generating initial blockchain") self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(1) self.sync_all() # reach sidechain fork nb = int(self.nodes[0].getblockcount()) node2_cb_height = 341 nb_to_gen1 = node2_cb_height - nb if nb_to_gen1 > 0: mark_logs("Node 0 generates {} block".format(nb_to_gen1), self.nodes, DEBUG_MODE) self.nodes[0].generate(nb_to_gen1) self.sync_all() mark_logs("Node 2 generates 1 block for coinbase to be used after 100 blocks", self.nodes, DEBUG_MODE) self.nodes[2].generate(1) self.sync_all() print("Chain height=", self.nodes[3].getblockcount()) # reach sidechain fork nb = int(self.nodes[0].getblockcount()) nb_to_gen = MINIMAL_SC_HEIGHT - nb -1 if nb_to_gen > 0: mark_logs("Node 0 generates {} block for reaching sc fork".format(nb_to_gen), self.nodes, DEBUG_MODE) self.nodes[0].generate(nb_to_gen) self.sync_all() print("Chain height=", self.nodes[3].getblockcount()) safe_guard_size = EPOCH_LENGTH//5 if safe_guard_size < 2: safe_guard_size = 2 creation_amount = Decimal("1.0") prev_epoch_hash = self.nodes[0].getbestblockhash() #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() # Create a SC 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'] tx_cr = ret['txid'] scid_swapped = str(swap_bytes(scid)) mark_logs("tx={} created SC id: {}".format(tx_cr, scid), self.nodes, DEBUG_MODE) self.sync_all() mark_logs("Node0 confirms Sc creation generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) sc_creating_height = self.nodes[0].getblockcount() self.sync_all() mark_logs("Node0 generates {} more blocks to achieve end of withdrawal epochs".format(EPOCH_LENGTH - 1), self.nodes, DEBUG_MODE) self.nodes[0].generate(EPOCH_LENGTH - 1) self.sync_all() mark_logs("Node0 generates 3 more blocks to give spendable funds to node2", self.nodes, DEBUG_MODE) bl = self.nodes[0].generate(3) #self.nodes[0].generate(1) self.sync_all() utxos_2 = self.nodes[2].listunspent() #pprint.pprint(utxos_2) assert_equal(len(utxos_2), 1) assert_equal(utxos_2[0]['confirmations'], 101) epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], EPOCH_LENGTH) taddr0 = self.nodes[0].getnewaddress() taddr1 = self.nodes[1].getnewaddress() taddr2 = self.nodes[2].getnewaddress() node0Addr = self.nodes[0].validateaddress(taddr0)['address'] node1Addr = self.nodes[1].validateaddress(taddr1)['address'] node2Addr = self.nodes[2].validateaddress(taddr2)['address'] bwt_amount0 = Decimal("0.10") bwt_amount1 = Decimal("0.20") bwt_amount2 = Decimal("0.30") try: #Create proof for WCert quality = 1 amounts = [{"address": node0Addr, "amount": bwt_amount0}] proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [node0Addr], [bwt_amount0]) mark_logs("Node 0 sends a cert with a bwd transfers of {} coins to Node0 taddr {}".format(bwt_amount0, taddr0), self.nodes, DEBUG_MODE) cert_0_top = self.nodes[0].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("==> certificate is {}".format(cert_0_top), self.nodes, DEBUG_MODE) self.sync_all() quality = 2 amounts = [{"address": node1Addr, "amount": bwt_amount1}] proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [node1Addr], [bwt_amount1]) mark_logs("Node 1 sends a cert with a bwd transfers of {} coins to Node1 taddr {}".format(bwt_amount1, taddr1), self.nodes, DEBUG_MODE) cert_1_top = self.nodes[1].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("==> certificate is {}".format(cert_1_top), self.nodes, DEBUG_MODE) self.sync_all() quality = 3 amounts = [{"address": node2Addr, "amount": bwt_amount2}] proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [node2Addr], [bwt_amount2]) mark_logs("Node 2 sends a cert with a bwd transfers of {} coins to Node2 taddr {}".format(bwt_amount2, taddr2), self.nodes, DEBUG_MODE) cert_2_top = self.nodes[2].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("==> certificate is {}".format(cert_2_top), self.nodes, DEBUG_MODE) self.sync_all() cert_hex = self.nodes[2].getrawtransaction(cert_2_top) except JSONRPCException as e: errorString = e.error['message'] mark_logs("Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert(False) print("Calling getcertmaturityinfo for cert {} , it should be in mempool, non top quality".format(cert_0_top)) ret = self.nodes[0].getcertmaturityinfo(cert_0_top) assert_equal(ret['blocksToMaturity'], -1) assert_equal(ret['certificateState'], "LOW_QUALITY_MEMPOOL") assert_equal(ret['maturityHeight'], -1) print("Calling getcertmaturityinfo for cert {} , it should be in mempool, top quality".format(cert_2_top)) ret = self.nodes[0].getcertmaturityinfo(cert_2_top) assert_equal(ret['blocksToMaturity'], -1) assert_equal(ret['certificateState'], "TOP_QUALITY_MEMPOOL") assert_equal(ret['maturityHeight'], -1) addr_list = [] addr_list.append(taddr0) addr_list.append(taddr1) addr_list.append(taddr2) args = {"addresses": addr_list} ret = self.nodes[3].getaddressmempool(args) #pprint.pprint(ret) for x in ret: addr = x['address'] sat = x['satoshis'] if sat < 0: # skip inputs continue cert_id = x['txid'] out_status = x['outstatus'] if addr == taddr0: assert_equal(sat, to_satoshis(bwt_amount0)) assert_equal(cert_id, cert_0_top) assert_equal(out_status, 2) if addr == taddr1: assert_equal(sat, to_satoshis(bwt_amount1)) assert_equal(cert_id, cert_1_top) assert_equal(out_status, 2) if addr == taddr2: assert_equal(sat, to_satoshis(bwt_amount2)) assert_equal(cert_id, cert_2_top) assert_equal(out_status, 1) # start first epoch + 2*epocs + safe guard bwtMaturityHeight = (sc_creating_height-1) + 2*EPOCH_LENGTH + safe_guard_size # revert last 3 blocks, thus causing the eviction of top quality cert from mempool # since its input, which is a coinbase, is not mature anymore mark_logs("Nodes revert last 3 blocks", self.nodes, DEBUG_MODE) for i in range(0, NUMB_OF_NODES): self.nodes[i].invalidateblock(bl[0]) self.sync_all() # cert_2_top is not in mempool, has been removed for i in range(0, NUMB_OF_NODES): assert_equal(False, cert_2_top in self.nodes[i].getrawmempool()) ret = self.nodes[3].getaddressmempool(args) for x in ret: addr = x['address'] # last top quality cert has been removed from mempool address data too assert_false(addr == taddr2) sat = x['satoshis'] if sat < 0: # skip inputs continue cert_id = x['txid'] out_status = x['outstatus'] if addr == taddr0: assert_equal(sat, to_satoshis(bwt_amount0)) assert_equal(cert_id, cert_0_top) assert_equal(out_status, 2) if addr == taddr1: assert_equal(sat, to_satoshis(bwt_amount1)) assert_equal(cert_id, cert_1_top) # last superseeded quality cert has been promoted to top assert_equal(out_status, 1) mark_logs("Node0 generates 3 more block", self.nodes, DEBUG_MODE) self.nodes[0].generate(3) self.sync_all() # coinbase utxo in node2 wallet is spendable again utxos_2 = self.nodes[2].listunspent() assert_equal(len(utxos_2), 1) assert_equal(utxos_2[0]['confirmations'], 101) mark_logs("Node2 resend a certificate", self.nodes, DEBUG_MODE) try: # slightly increase the fee, just for not having the same cert id hash. The reason is that an inventory already # known (and this would be since already broadcasted and then evicted) are not broadcasted by th p2p network new_cert_fee = CERT_FEE + Decimal(0.00001) cert_2_top_retried = self.nodes[2].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, new_cert_fee) mark_logs("==> certificate is {}".format(cert_2_top_retried), self.nodes, DEBUG_MODE) assert_true(cert_2_top_retried != cert_2_top) self.sync_all() except JSONRPCException as e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert(False) assert_true(cert_2_top_retried in self.nodes[0].getrawmempool()) # the certificate in blockchain is still the top quality print("Calling getcertmaturityinfo for cert {}".format(cert_1_top)) ret = self.nodes[3].getcertmaturityinfo(cert_1_top) #pprint.pprint(ret) nb = self.nodes[3].getblockcount() bl_to_mat = bwtMaturityHeight - nb print("nb = {}, bwtMaturityHeight = {}".format(nb, bwtMaturityHeight)) assert_equal(ret['blocksToMaturity'], bl_to_mat) assert_equal(ret['certificateState'], "IMMATURE") assert_equal(ret['maturityHeight'], bwtMaturityHeight) mark_logs("Calling getcertmaturityinfo for cert {} ...".format(cert_2_top_retried), self.nodes, DEBUG_MODE) try: ret = self.nodes[3].getcertmaturityinfo(cert_2_top_retried) assert_equal(ret['blocksToMaturity'], -1) assert_equal(ret['certificateState'], "TOP_QUALITY_MEMPOOL") assert_equal(ret['maturityHeight'], -1) except JSONRPCException as e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) mark_logs("Calling getaddressmempool for cert {}".format(cert_2_top_retried), self.nodes, DEBUG_MODE) ret = self.nodes[3].getaddressmempool(args) #pprint.pprint(ret) for x in ret: sat = x['satoshis'] if sat < 0: # skip inputs continue addr = x['address'] cert_id = x['txid'] out_status = x['outstatus'] assert_equal(addr, taddr2) assert_equal(sat, to_satoshis(bwt_amount2)) assert_equal(cert_id, cert_2_top_retried) assert_equal(out_status, 1) # create wCert proof mark_logs("Node 0 sends a cert with 2 outs and 2 bwts", self.nodes, DEBUG_MODE) quality = 10 am_bwt1 = Decimal(0.011) am_bwt2 = Decimal(0.022) am_out = Decimal(0.001) # python orders dictionaries by key, therefore we must use the same order when creating the proof pkh_arr = [] am_bwt_arr = [] raw_bwt_outs = [ {"address": node1Addr, "amount": am_bwt1}, {"address": node2Addr, "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, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, pkh_arr, am_bwt_arr) utx, change = get_spendable(self.nodes[0], CERT_FEE + am_out) raw_inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] # do not use the same address, this is not supported (and python would prevent it anyway since this is a dictionary) taddr3 = self.nodes[3].getnewaddress() raw_outs = { taddr0: change, taddr3: am_out } raw_params = { "scid": scid, "quality": quality, "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash, "scProof": proof, "withdrawalEpochNumber": epoch_number } raw_cert = [] cert_last = [] try: raw_cert = self.nodes[0].createrawcertificate(raw_inputs, raw_outs, raw_bwt_outs, raw_params) signed_cert = self.nodes[0].signrawtransaction(raw_cert) except JSONRPCException as e: errorString = e.error['message'] print("\n======> ", errorString) assert_true(False) #pprint.pprint(self.nodes[0].decoderawcertificate(signed_cert['hex'])) try: cert_last = self.nodes[0].sendrawtransaction(signed_cert['hex']) self.sync_all() except JSONRPCException as e: errorString = e.error['message'] print("======> ", errorString, "\n") assert_true(False) addr_list.append(taddr3) args = {"addresses": addr_list} mark_logs("Calling getaddressmempool for cert {}".format(cert_last), self.nodes, DEBUG_MODE) ret = self.nodes[3].getaddressmempool(args) #pprint.pprint(ret) for x in ret: sat = x['satoshis'] if sat < 0: # skip inputs continue addr = x['address'] cert_id = x['txid'] out_status = x['outstatus'] # ordinary outputs if addr == taddr0: assert_equal(sat, to_satoshis(change)) assert_equal(out_status, 0) if addr == taddr3: assert_equal(sat, to_satoshis(am_out)) assert_equal(out_status, 0) # certificates if addr == taddr2: # two certificates refer to this address, the latest is top quality, the former has been superseeded if cert_id == cert_last: assert_equal(sat, to_satoshis(am_bwt2)) assert_equal(out_status, 1) if cert_id == cert_2_top_retried: assert_equal(sat, to_satoshis(bwt_amount2)) assert_equal(out_status, 2) if addr == taddr1: assert_equal(cert_id, cert_last) assert_equal(sat, to_satoshis(am_bwt1)) assert_equal(out_status, 1) # the certificate in blockchain is still the top quality print("Calling getcertmaturityinfo for cert {}".format(cert_1_top)) ret = self.nodes[3].getcertmaturityinfo(cert_1_top) pprint.pprint(ret) bl = self.nodes[0].generate(1) self.sync_all() print("Calling getcertmaturityinfo for cert {}".format(cert_1_top)) ret = self.nodes[3].getcertmaturityinfo(cert_1_top) pprint.pprint(ret) print("Calling getcertmaturityinfo for cert {}".format(cert_last)) ret = self.nodes[3].getcertmaturityinfo(cert_last) pprint.pprint(ret) mark_logs("\nInvalidating the last block and checking RPC call results...", self.nodes, DEBUG_MODE) for i in range(0, NUMB_OF_NODES): self.nodes[i].invalidateblock(bl[0]) self.sync_all() print("Calling getcertmaturityinfo for cert {} , it should be in mempool".format(cert_last)) assert_true(cert_last in self.nodes[3].getrawmempool()) ret = self.nodes[3].getcertmaturityinfo(cert_last) pprint.pprint(ret) assert_equal(ret['blocksToMaturity'], -1) assert_equal(ret['certificateState'], "TOP_QUALITY_MEMPOOL") assert_equal(ret['maturityHeight'], -1) print("Clearing the mempool of all nodes...") for i in range(0, NUMB_OF_NODES): self.nodes[i].clearmempool() self.sync_all() for i in range(0, NUMB_OF_NODES): assert_equal(len(self.nodes[i].getrawmempool()), 0) print("Calling getcertmaturityinfo for cert {} , it shouldn't be in mempool anymore".format(cert_last)) assert_false(cert_last in self.nodes[3].getrawmempool()) ret = self.nodes[3].getcertmaturityinfo(cert_last) pprint.pprint(ret) assert_equal(ret['blocksToMaturity'], -1) assert_equal(ret['certificateState'], "INVALID") assert_equal(ret['maturityHeight'], -1) ret = self.nodes[1].verifychain(4, 0) assert_equal(ret, True)
self.sync_all() epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) mark_logs( "\nepoch_number = {}, epoch_cum_tree_hash = {}".format( epoch_number, epoch_cum_tree_hash), self.nodes, DEBUG_MODE) # node0 create a cert_1 for funding node1 bwt_address = self.nodes[1].getnewaddress() amounts = [{"address": bwt_address, "amount": bwt_amount1}] try: #Create proof for WCert quality = 1 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, [bwt_address], [bwt_amount1]) #---------------------------------------------------------------------------------------------- cert_1 = self.nodes[0].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs( "\n===> Node 0 sent a cert for scid {} with bwd transfer of {} coins to Node1 pkh (addr {})" .format(scid, bwt_amount1, bwt_address), self.nodes, DEBUG_MODE)
def run_test(self): NODE_LIST = self.nodes self.nodes[0].generate( 1) # Mine a block to leave initial block download self.sync_all() sc_fork_reached = False currentHeight = self.nodes[0].getblockcount() mark_logs(("active chain height = %d: testing before sidechain fork" % currentHeight), self.nodes, DEBUG_MODE) self.doTest(sc_fork_reached) # reach the height where the next block is the last before the fork point where certificates are supported delta = MINIMAL_SC_HEIGHT - currentHeight - 2 self.nodes[0].generate(delta) self.sync_all() mark_logs(( "active chain height = %d: testing last block before sidechain fork" % self.nodes[0].getblockcount()), self.nodes, DEBUG_MODE) self.doTestJustBeforeScFork() # reach the fork where certificates are supported self.nodes[0].generate(1) self.sync_all() mark_logs(( "active chain height = %d: testing block which will be at sidechain fork" % self.nodes[0].getblockcount()), self.nodes, DEBUG_MODE) sc_fork_reached = True # create a sidechain and a certificate for it in the mempool mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() cmdInput = { 'version': 0, 'withdrawalEpochLength': SC_EPOCH_LENGTH, 'toaddress': "dada", 'amount': SC_CREATION_AMOUNT, 'wCertVk': vk, 'customData': "bb" * 1024, 'constant': constant } ret = self.nodes[1].sc_create(cmdInput) creating_tx = ret['txid'] scid = ret['scid'] self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(creating_tx, 1) assert_equal(scid, decoded_tx['vsc_ccout'][0]['scid']) mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE) current_height = self.nodes[1].getblockcount() block_list = self.nodes[0].generate(SC_EPOCH_LENGTH) self.sync_all() addr_node0 = self.nodes[0].getnewaddress() amounts = [{"address": addr_node0, "amount": SC_CERT_AMOUNT}] #create wCert proof epoch_cum_tree_hash = self.nodes[0].getblock( block_list[-1])['scCumTreeHash'] ftScFee = 0.1 mbtrScFee = 0.1 fee = 0.000023 scid_swapped = str(swap_bytes(scid)) proof = mcTest.create_test_proof("sc1", scid_swapped, 0, 0, mbtrScFee, ftScFee, epoch_cum_tree_hash, constant, [addr_node0], [SC_CERT_AMOUNT]) cert = self.nodes[0].sc_send_certificate(scid, 0, 0, epoch_cum_tree_hash, proof, amounts, ftScFee, mbtrScFee, fee) self.sync_all() assert_true(cert in self.nodes[0].getrawmempool()) mark_logs("cert issued : {}".format(cert), self.nodes, DEBUG_MODE) # just one more tx, for having 3 generic txobjs and testing malleability of cert (Test 4) tx = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.01) self.sync_all() assert_true(tx in self.nodes[0].getrawmempool()) mark_logs("starting test: fork{}".format(sc_fork_reached), self.nodes, DEBUG_MODE) self.doTest(sc_fork_reached) self.nodes[0].generate(1) self.sync_all()
try: self.nodes[0].sendrawtransaction(sigRawtx['hex']) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs("Send csw failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) mark_logs( "\nCreate a CSW withdrawing un third of the original sc balance... ", self.nodes, DEBUG_MODE) sc_csw_amount = sc_bal / 3 sc_csw_tx_outs = {taddr_2: sc_csw_amount} null2 = generate_random_field_element_hex() scid_swapped = swap_bytes(scid) sc_proof2 = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null2, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null2, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof2
def run_test(self): ''' The test creates a sc, send funds to it and then sends a certificate to it, verifying also that specifying various combination of bad parameters causes a certificate to be refused. This test also checks that the receiver of cert backward transfer can spend it only when they become mature. ''' # forward transfer amounts creation_amount = Decimal("0.5") fwt_amount = Decimal("50") bwt_amount_bad = Decimal("100.0") bwt_amount = Decimal("50") bwt_amount_0_b = Decimal("0.10") self.nodes[0].getblockhash(0) # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(1) 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() # SC creation bal_before_sc_creation = self.nodes[1].getbalance("", 0) mark_logs( "Node1 balance before SC creation: {}".format( bal_before_sc_creation), 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[1].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[1].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) self.nodes[0].generate(1) sc_creating_height = self.nodes[0].getblockcount() self.sync_all() # Check node 1 balance following sc creation fee_sc_creation = self.nodes[1].gettransaction(creating_tx)['fee'] mark_logs("Fee paid for SC creation: {}".format(fee_sc_creation), self.nodes, DEBUG_MODE) bal_after_sc_creation = self.nodes[1].getbalance("", 0) mark_logs( "Node1 balance after SC creation: {}".format( bal_after_sc_creation), self.nodes, DEBUG_MODE) assert_equal(bal_before_sc_creation, bal_after_sc_creation + creation_amount - fee_sc_creation) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts'][0] ['amount'], creation_amount) # Fwd Transfer to Sc bal_before_fwd_tx = self.nodes[0].getbalance("", 0) mark_logs("Node0 balance before fwd tx: {}".format(bal_before_fwd_tx), self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount, "scid": scid, "mcReturnAddress": mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs( "Node0 transfers {} coins to SC with tx {}...".format( fwt_amount, fwd_tx), self.nodes, DEBUG_MODE) self.sync_all() mark_logs("Node0 confirms fwd transfer generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() # Check node 0 balance following fwd tx fee_fwt = self.nodes[0].gettransaction(fwd_tx)['fee'] mark_logs("Fee paid for fwd tx: {}".format(fee_fwt), self.nodes, DEBUG_MODE) bal_after_fwd_tx = self.nodes[0].getbalance("", 0) mark_logs("Node0 balance after fwd: {}".format(bal_after_fwd_tx), self.nodes, DEBUG_MODE) assert_equal( bal_before_fwd_tx, bal_after_fwd_tx + fwt_amount - fee_fwt - Decimal(MINER_REWARD_POST_H200)) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts'][0] ['amount'], creation_amount) assert_equal( self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts'][1] ['amount'], fwt_amount) nblocks = EPOCH_LENGTH - 2 mark_logs( "Node0 generating {} more blocks to achieve end of withdrawal epoch" .format(nblocks), self.nodes, DEBUG_MODE) self.nodes[0].generate(nblocks) self.sync_all() assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['balance'], creation_amount + fwt_amount) # Sc balance has matured assert_equal( len(self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts']), 0) epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) mark_logs( "epoch_number = {}, epoch_cum_tree_hash = {}".format( epoch_number, epoch_cum_tree_hash), self.nodes, DEBUG_MODE) 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}] #---------------------start negative tests------------------------- mark_logs( "Node 0 tries to send a cert with insufficient Sc balance...", self.nodes, DEBUG_MODE) amounts = [{"address": addr_node1, "amount": bwt_amount_bad}] try: self.nodes[0].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE)
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)
def run_test(self): self.init_nodes() ########################### # TRANSPARENT TX # ########################### print("TESTING TRANSPARENT TX") # Arrange unspent = self.nodes[0].listunspent()[0] inputs = [{'txid': unspent['txid'], 'vout': unspent['vout']}] outputs = { self.nodes[0].getnewaddress(): unspent['amount'] - Decimal('0.001') } raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) signed_tx = self.nodes[0].signrawtransaction(raw_tx) # Act r = requests.post(url=BASE_URL + "tx/send", json={"rawtx": signed_tx['hex']}) # Assert final_raw_tx = r.json()['txid'] assert_equal(final_raw_tx is not None, True) print('SUCCESS - txid: {}'.format(final_raw_tx)) self.nodes[0].generate(1) self.sync_all() ########################### # CREATE SC TX # ########################### print("TESTING CREATE SC TX") # Arrange # 1. Generate enough blocks to create a side chain self.nodes[1].generate(MINIMAL_SC_VERSION_HEIGHT - self.nodes[0].getblockcount()) self.sync_all() # 2. Define side chain values cert_mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir) csw_mc_test = CSWTestUtils(self.options.tmpdir, self.options.srcdir) sc_address = "0000000000000000000000000000000000000000000000000000000000000abc" sc_epoch_len = 123 sc_cr_amount = Decimal('10.00000000') vk = cert_mc_test.generate_params("sc1") csw_vk = csw_mc_test.generate_params("csw1") constant = generate_random_field_element_hex() sc_cr = [{ "epoch_length": sc_epoch_len, "amount": sc_cr_amount, "address": sc_address, "wCertVk": vk, "wCeasedVk": csw_vk, "constant": constant, "version": 1 }] # 3. Prepare a UTXO to fund the side chain txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), sc_cr_amount) self.sync_all() self.nodes[0].generate(1) self.sync_all() decoded_tx = self.nodes[0].decoderawtransaction( self.nodes[0].gettransaction(txid)['hex']) vout = {} for outpoint in decoded_tx['vout']: if outpoint['value'] == sc_cr_amount: vout = outpoint break # 4. Prepare raw transaction inputs = [{'txid': txid, 'vout': vout['n']}] raw_tx = self.nodes[0].createrawtransaction(inputs, {}, [], sc_cr, []) sign_raw_tx = self.nodes[0].signrawtransaction(raw_tx) # Act r = requests.post(url=BASE_URL + "tx/send", json={"rawtx": sign_raw_tx['hex']}) # Assert final_raw_tx = r.json()['txid'] decoded_tx = self.nodes[0].getrawtransaction(final_raw_tx, 1) scid = decoded_tx['vsc_ccout'][0]['scid'] assert_equal(final_raw_tx is not None, True) assert_equal(scid is not None, True) print('SUCCESS - scid: {}'.format(scid)) self.nodes[0].generate(1) self.sync_all() ########################### # SC FORWARD TRANSFER TX # ########################### print("TESTING SC FORWARD TRANSFER TX") # Arrange inputs = [] sc_ft_amount = Decimal('10.00000000') mc_return_address = self.nodes[0].getnewaddress() sc_ft = [{ "address": sc_address, "amount": sc_ft_amount, "scid": scid, "mcReturnAddress": mc_return_address }] raw_tx = self.nodes[0].createrawtransaction(inputs, {}, [], [], sc_ft) funded_tx = self.nodes[0].fundrawtransaction(raw_tx) sign_raw_tx = self.nodes[0].signrawtransaction(funded_tx['hex']) # Act r = requests.post(url=BASE_URL + "tx/send", json={"rawtx": sign_raw_tx['hex']}) # Assert final_raw_tx = r.json()['txid'] assert_equal(final_raw_tx is not None, True) print('SUCCESS - txid: {}'.format(final_raw_tx)) self.nodes[0].generate(1) self.sync_all() ########################### # SC CERTIFICATE TX # ########################### print("TESTING SC CERTIFICATE TX") # Arrange self.nodes[0].generate(sc_epoch_len) self.sync_all() epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], sc_epoch_len) proof = cert_mc_test.create_test_proof("sc1", swap_bytes(scid), epoch_number, 0, Decimal('0'), Decimal('0'), epoch_cum_tree_hash, constant) 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 = [] raw_params = { "scid": scid, "quality": 0, "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash, "scProof": proof, "withdrawalEpochNumber": epoch_number } raw_cert = self.nodes[0].createrawcertificate(raw_inputs, raw_outs, raw_bwt_outs, raw_params) signed_cert = self.nodes[0].signrawtransaction(raw_cert) # Act r = requests.post(url=BASE_URL + "tx/send", json={"rawtx": signed_cert['hex']}) # Assert final_raw_tx = r.json()['txid'] assert_equal(final_raw_tx is not None, True) print('SUCCESS - txid: {}'.format(final_raw_tx)) self.nodes[0].generate(1) self.sync_all()
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)
def run_test(self): ''' The test creates two sc, send funds to them and then sends a certificates to them, verifying also that mempool accepts certificate with different quality, certificate with higher fee but same quality substitutes certificate with lower fee, certificates from different sc are handled independently. ''' # forward transfer amounts creation_amount = Decimal("0.5") fwt_amount = Decimal("200") bwt_amount = Decimal("20") self.nodes[0].getblockhash(0) # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(1) self.sync_all() self.nodes[2].generate(1) 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() # SC creation bal_before_sc_creation = self.nodes[1].getbalance("", 0) mark_logs( "Node1 balance before SC creation: {}".format( bal_before_sc_creation), self.nodes, DEBUG_MODE) #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk_tag_1 = "sc1" vk_1 = mcTest.generate_params(vk_tag_1) constant_1 = generate_random_field_element_hex() vk_tag_2 = "sc2" vk_2 = mcTest.generate_params(vk_tag_2) constant_2 = generate_random_field_element_hex() cmdInput = { "version": 0, "withdrawalEpochLength": EPOCH_LENGTH, "toaddress": "dada", "amount": creation_amount, "wCertVk": vk_1, "constant": constant_1, } ret = self.nodes[1].sc_create(cmdInput) creating_tx_1 = ret['txid'] scid_1 = ret['scid'] scid1_swapped = str(swap_bytes(scid_1)) mark_logs( "Node 1 created the SC spending {} coins via tx {}.".format( creation_amount, creating_tx_1), self.nodes, DEBUG_MODE) self.sync_all() cmdInput = { "version": 0, "withdrawalEpochLength": EPOCH_LENGTH, "toaddress": "baba", "amount": creation_amount, "wCertVk": vk_2, "constant": constant_2, "minconf": 0 } ret = self.nodes[1].sc_create(cmdInput) creating_tx_2 = ret['txid'] scid_2 = ret['scid'] scid2_swapped = str(swap_bytes(scid_2)) mark_logs( "Node 1 created the SC spending {} coins via tx {}.".format( creation_amount, creating_tx_2), self.nodes, DEBUG_MODE) self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(creating_tx_1, 1) assert_equal(scid_1, decoded_tx['vsc_ccout'][0]['scid']) mark_logs("created SC id: {}".format(scid_1), self.nodes, DEBUG_MODE) mark_logs("Node0 confirms Sc creation generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) sc_creating_height = self.nodes[0].getblockcount() self.sync_all() # Check node 1 balance following sc creation fee_sc_creation_1 = Decimal( self.nodes[1].gettransaction(creating_tx_1)['fee']) fee_sc_creation_2 = Decimal( self.nodes[1].gettransaction(creating_tx_2)['fee']) mark_logs("Fee paid for SC1 creation: {}".format(fee_sc_creation_1), self.nodes, DEBUG_MODE) mark_logs("Fee paid for SC2 creation: {}".format(fee_sc_creation_2), self.nodes, DEBUG_MODE) bal_after_sc_creation = self.nodes[1].getbalance("", 0) mark_logs( "Node1 balance after SC creation: {}".format( bal_after_sc_creation), self.nodes, DEBUG_MODE) assert_equal( bal_before_sc_creation, bal_after_sc_creation + creation_amount + creation_amount - fee_sc_creation_1 - fee_sc_creation_2) assert_equal(self.nodes[0].getscinfo(scid_1)['items'][0]['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid_1)['items'][0]['immatureAmounts'][0] ['amount'], creation_amount) # Fwd Transfer to SC 1 bal_before_fwd_tx = self.nodes[0].getbalance("", 0) mc_return_address = self.nodes[0].getnewaddress() mark_logs("Node0 balance before fwd tx: {}".format(bal_before_fwd_tx), self.nodes, DEBUG_MODE) cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount, "scid": scid_1, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs( "Node0 transfers {} coins to SC 1 with tx {}...".format( fwt_amount, fwd_tx), self.nodes, DEBUG_MODE) self.sync_all() mark_logs("Node0 confirms fwd transfer generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() # Fwd Transfer to SC 2 bal_before_fwd_tx = self.nodes[0].getbalance("", 0) mc_return_address = self.nodes[0].getnewaddress() mark_logs("Node0 balance before fwd tx: {}".format(bal_before_fwd_tx), self.nodes, DEBUG_MODE) cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount, "scid": scid_2, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs( "Node0 transfers {} coins to SC 2 with tx {}...".format( fwt_amount, fwd_tx), self.nodes, DEBUG_MODE) self.sync_all() mark_logs("Node0 confirms fwd transfer generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() # Check node 0 balance following fwd tx fee_fwt = self.nodes[0].gettransaction(fwd_tx)['fee'] mark_logs("Fee paid for fwd tx: {}".format(fee_fwt), self.nodes, DEBUG_MODE) bal_after_fwd_tx = self.nodes[0].getbalance("", 0) mark_logs("Node0 balance after fwd: {}".format(bal_after_fwd_tx), self.nodes, DEBUG_MODE) assert_equal( bal_before_fwd_tx, bal_after_fwd_tx + fwt_amount - fee_fwt - Decimal(MINER_REWARD_POST_H200)) assert_equal(self.nodes[0].getscinfo(scid_1)['items'][0]['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid_1)['items'][0]['immatureAmounts'][0] ['amount'], creation_amount) assert_equal( self.nodes[0].getscinfo(scid_1)['items'][0]['immatureAmounts'][1] ['amount'], fwt_amount) mark_logs( "Node0 generating more blocks to achieve end of withdrawal epoch", self.nodes, DEBUG_MODE) self.nodes[0].generate(EPOCH_LENGTH - 3) self.sync_all() assert_equal(self.nodes[0].getscinfo(scid_1)['items'][0]['balance'], creation_amount + fwt_amount) # Sc balance has matured assert_equal( len(self.nodes[0].getscinfo(scid_1)['items'][0] ['immatureAmounts']), 0) epoch_number_1, epoch_cum_tree_hash_1 = get_epoch_data( scid_1, self.nodes[0], EPOCH_LENGTH) addr_node1 = self.nodes[1].getnewaddress() self.sync_all() epoch_number_2, epoch_cum_tree_hash_2 = get_epoch_data( scid_2, self.nodes[0], EPOCH_LENGTH) amount_cert = [{"address": addr_node1, "amount": bwt_amount}] # Create Cert1 with quality 100 and place it in mempool mark_logs("Create Cert1 with quality 100 and place it in mempool", self.nodes, DEBUG_MODE) quality = 100 proof = mcTest.create_test_proof(vk_tag_1, scid1_swapped, epoch_number_1, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash_1, constant_1, [addr_node1], [bwt_amount]) try: cert_1_epoch_0 = self.nodes[0].sc_send_certificate( scid_1, epoch_number_1, quality, epoch_cum_tree_hash_1, proof, amount_cert, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) assert (len(cert_1_epoch_0) > 0) mark_logs("Certificate is {}".format(cert_1_epoch_0), self.nodes, DEBUG_MODE) except JSONRPCException, e: errorString = e.error['message'] mark_logs( "Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert (False)
'fee': fee, 'constant': constant1, 'wCertVk': vk, 'toaddress': "cdcd", 'vFieldElementCertificateFieldConfig': feCfg[0], 'vBitVectorCertificateFieldConfig': cmtCfg[0] } 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, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true(False) self.sync_all() mark_logs( "Verify vFieldElementCertificateFieldConfig / vBitVectorCertificateFieldConfig are correctly set in creation tx", self.nodes, DEBUG_MODE) decoded_tx = self.nodes[1].getrawtransaction(tx, 1) dec_sc_id = decoded_tx['vsc_ccout'][0]['scid'] assert_equal(scid1, dec_sc_id) feCfgStr = decoded_tx['vsc_ccout'][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)
class CswNullifierTest(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=[[ "-sccoinsmaturity=0", '-scproofqueuesize=0', '-logtimemicros=1', '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net', '-debug=bench' ]] * NUMB_OF_NODES) if not split: # 1 and 2 are joint only if split==false connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes[1:3]) sync_mempools(self.nodes[1:3]) connect_nodes_bi(self.nodes, 0, 1) self.is_network_split = split self.sync_all() def split_network(self): # Split the network of three nodes into nodes 0-1 and 2. assert not self.is_network_split disconnect_nodes(self.nodes[1], 2) disconnect_nodes(self.nodes[2], 1) self.is_network_split = True def join_network(self): # Join the (previously split) network pieces together: 0-1-2 assert self.is_network_split connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 2, 1) time.sleep(2) self.is_network_split = False def run_test(self): ''' Create a SC, advance two epochs and then let it cease. Test CSW txes and related in/outputs verifying that nullifiers are properly handled also when blocks are disconnected. Split the network and test CSW conflicts handling on network rejoining. Restare the network and check DB integrity. Finally create a second SC, advance 1 epoch only and verify that no CSW can be accepted (max is 2 certs) ''' # prepare some coins self.nodes[0].generate(MINIMAL_SC_HEIGHT) self.sync_all() prev_epoch_hash = self.nodes[0].getbestblockhash() 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...".format(sc_epoch_len), 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() # check we have cert data hash for the last active certificate mark_logs("\nCheck we have expected cert data hashes", self.nodes, DEBUG_MODE) try: assert_true( self.nodes[0].getactivecertdatahash(scid)['certDataHash']) except JSONRPCException, e: errorString = e.error['message'] mark_logs("{}".format(errorString), self.nodes, DEBUG_MODE) assert (False) mark_logs("Let SC cease... ".format(scid), 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 half the sc balance... ", self.nodes, DEBUG_MODE) # CSW sender MC address csw_mc_address = self.nodes[0].getnewaddress() sc_csw_amount = sc_bal / 2 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 = str(swap_bytes(scid)) sc_proof1 = cswMcTest.create_test_proof("sc1", sc_csw_amount, 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() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) # vin - size(1): utxo for paying the fee # vout - size(2): recipient of the funds + sender change # vcsw_ccin - size(1): CSW funds assert_equal(1, len(decoded_tx['vin'])) assert_equal(2, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vcsw_ccin'])) csw_in = decoded_tx['vcsw_ccin'][0] mark_logs("Check csw is in mempool...", self.nodes, DEBUG_MODE) assert_true(finalRawtx in self.nodes[2].getrawmempool()) mark_logs("\nNode0 generates 1 block confirming CSW", self.nodes, DEBUG_MODE) bl = self.nodes[0].generate(1)[-1] self.sync_all() mark_logs("Check csw is in block just mined...", self.nodes, DEBUG_MODE) assert_true(finalRawtx in self.nodes[0].getblock(bl, True)['tx']) mark_logs("Check nullifier is in MC...", self.nodes, DEBUG_MODE) res = self.nodes[0].checkcswnullifier(scid, null1) assert_equal(res['data'], 'true') n2_bal = self.nodes[2].getbalance() mark_logs("Check Node2 has the expected balance...", self.nodes, DEBUG_MODE) assert_equal(n2_bal, sc_csw_amount) amount_2_1 = Decimal(n2_bal) / Decimal('4.0') mark_logs( "\nNode2 sends {} coins to Node1 using csw funds...".format( amount_2_1), self.nodes, DEBUG_MODE) tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), amount_2_1) mark_logs("tx = {}".format(tx), self.nodes, DEBUG_MODE) self.sync_all() mark_logs("Node0 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() mark_logs("\nNode2 invalidate its chain from csw block on...", self.nodes, DEBUG_MODE) self.nodes[2].invalidateblock(bl) sync_mempools(self.nodes[0:2]) mark_logs("Check csw has been put back in Node2 mempool...", self.nodes, DEBUG_MODE) assert_true(tx, finalRawtx in self.nodes[2].getrawmempool()) mark_logs("Check Node2 has null confirmed balance...", self.nodes, DEBUG_MODE) n2_bal = self.nodes[2].z_gettotalbalance()['total'] assert_equal(Decimal(n2_bal), Decimal('0.0')) mark_logs("Check nullifier is no more in MC from Node2 perspective...", self.nodes, DEBUG_MODE) res = self.nodes[2].checkcswnullifier(scid, null1) assert_equal(res['data'], 'false') mark_logs("\nNode2 reconsider last invalidated blocks", self.nodes, DEBUG_MODE) self.nodes[2].reconsiderblock(bl) self.sync_all() mark_logs("Check nullifier is back in MC from Node2 perspective...", self.nodes, DEBUG_MODE) res = self.nodes[2].checkcswnullifier(scid, null1) assert_equal(res['data'], 'true') # Try to create CSW with the nullifier which already exists in the chain mark_logs( "\nTrying to send a csw with the same nullifier (expecting failure...)", self.nodes, DEBUG_MODE) sc_csw_amount = sc_bal / 4 sc_csws[0]['amount'] = sc_csw_amount 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']) try: self.nodes[0].sendrawtransaction(sigRawtx['hex']) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs("Send csw failed with reason {}".format(errorString), self.nodes, DEBUG_MODE)
mark_logs("Default proof constant test", self.nodes, DEBUG_MODE) mark_logs("Node0 creates new sidechain", self.nodes, DEBUG_MODE) vk2 = mcTest.generate_params("sc2", "cert_no_const") cmdInput = { "version": 0, "withdrawalEpochLength": EPOCH_LENGTH, "toaddress": "dada", "amount": creation_amount, "wCertVk": vk2 } ret = self.nodes[0].sc_create(cmdInput) creating_tx = ret['txid'] scid2 = ret['scid'] scid2_swapped = str(swap_bytes(scid2)) 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(scid2, decoded_tx['vsc_ccout'][0]['scid']) mark_logs("created SC id: {}".format(scid2), self.nodes, DEBUG_MODE) mark_logs("Node0 confirms Sc creation generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() self.nodes[0].generate(EPOCH_LENGTH)
def run_test(self): def get_spendable(nodeIdx, min_amount): utx = False listunspent = self.nodes[nodeIdx].listunspent() for aUtx in listunspent: if aUtx['amount'] > min_amount: utx = aUtx change = aUtx['amount'] - min_amount break if utx == False: pprint.pprint(listunspent) assert_equal(utx != False, True) return utx, change ''' Create a SC, advance two epochs and then let it cease. Test CSW creation with the use of the cmd fundrawtransaction in different scenarios ''' # prepare some coins self.nodes[0].generate(MINIMAL_SC_HEIGHT) self.sync_all() prev_epoch_hash = self.nodes[0].getbestblockhash() sc_address = "0000000000000000000000000000000000000000000000000000000000000abc" sc_epoch_len = EPOCH_LENGTH sc_cr_amount = Decimal('21.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("Let 2 epochs pass by...", self.nodes, DEBUG_MODE) advance_epoch(certMcTest, self.nodes[0], self.sync_all, scid, "sc1", constant, sc_epoch_len) advance_epoch(certMcTest, self.nodes[0], self.sync_all, scid, "sc1", constant, sc_epoch_len) 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() print # check it is really ceased ret = self.nodes[0].getscinfo(scid, False, False)['items'][0] assert_equal(ret['state'], "CEASED") sc_bal = self.nodes[0].getscinfo(scid, False, False)['items'][0]['balance'] # CSW sender MC address csw_mc_address = self.nodes[0].getnewaddress() actCertData = self.nodes[0].getactivecertdatahash(scid)['certDataHash'] ceasingCumScTxCommTree = self.nodes[0].getceasingcumsccommtreehash( scid)['ceasingCumScTxCommTree'] scid_swapped = swap_bytes(scid) sc_csw_amount = sc_bal / 8 # recipient MC address taddr_2 = self.nodes[2].getnewaddress() sc_csw_tx_outs = {taddr_2: sc_csw_amount} vtxCsw = [] # -------------------------------------------------------------------- # 1) One csw input covering exacltly the output mark_logs("One csw input covering exacltly the output...", self.nodes, DEBUG_MODE) null1 = generate_random_field_element_hex() sc_proof = 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_proof }] 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("tx = {}".format(finalRawtx), self.nodes, DEBUG_MODE) vtxCsw.append(finalRawtx) print self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) #pprint.pprint(decoded_tx) # vin - size(1): utxo for paying the fee # vout - size(2): recipient of the funds + sender change # vcsw_ccin - size(1): CSW funds assert_equal(1, len(decoded_tx['vin'])) assert_equal(2, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vcsw_ccin'])) assert_true(finalRawtx in self.nodes[2].getrawmempool()) # -------------------------------------------------------------------- # 2) One csw input covering half the output mark_logs("One csw input covering half the output...", self.nodes, DEBUG_MODE) null2 = generate_random_field_element_hex() sc_proof = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null2, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null2, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof }] # recipient MC address sc_csw_tx_outs = {taddr_2: sc_csw_amount * 2} 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("tx = {}".format(finalRawtx), self.nodes, DEBUG_MODE) vtxCsw.append(finalRawtx) print self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) #pprint.pprint(decoded_tx) # vin - size(1): utxo for covering the reminder and paying the fee # vout - size(2): recipient of the funds + sender change # vcsw_ccin - size(1): CSW funds assert_equal(1, len(decoded_tx['vin'])) assert_equal(2, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vcsw_ccin'])) assert_true(finalRawtx in self.nodes[2].getrawmempool()) # --------------------------------------------------------------------------------------------------------- # 3) One csw input covering half the output, an utxo as input for a small amount and one output as preset change mark_logs( "One csw input covering half the output, an utxo as input for a small amount and one output as preset change...", self.nodes, DEBUG_MODE) null3 = generate_random_field_element_hex() sc_proof = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null3, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null3, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof }] # recipient MC address taddr_2 = self.nodes[2].getnewaddress() sc_csw_tx_outs = {taddr_2: sc_csw_amount * 2} utx, change = get_spendable(0, Decimal("0.0001")) #pprint.pprint(utx) #print "Change = ", change raw_inputs = [{'txid': utx['txid'], 'vout': utx['vout']}] raw_outs = { self.nodes[0].getnewaddress(): change, taddr_2: sc_csw_amount * Decimal('1.1') } rawtx = self.nodes[0].createrawtransaction(raw_inputs, raw_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("tx = {}".format(finalRawtx), self.nodes, DEBUG_MODE) vtxCsw.append(finalRawtx) print self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) #pprint.pprint(decoded_tx) # vin - size(2): utxo that was set and one for covering the reminder and paying the fee # vout - size(3): recipient of the funds + preset change + sender change # vcsw_ccin - size(1): CSW funds assert_equal(2, len(decoded_tx['vin'])) assert_equal(3, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vcsw_ccin'])) assert_true(finalRawtx in self.nodes[2].getrawmempool()) # --------------------------------------------------------------------------------------------------------- # 4) One csw input covering all of the output but a small amount to be used as fee. No call to fundrawtransaction mark_logs( "One csw input covering all of the output but a small amount to be used as fee. No call to fundrawtransaction...", self.nodes, DEBUG_MODE) null4 = generate_random_field_element_hex() sc_proof = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null4, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null4, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof }] # recipient MC address taddr_2 = self.nodes[2].getnewaddress() sc_csw_tx_outs = {taddr_2: (sc_csw_amount - Decimal("0.0001"))} rawtx = self.nodes[0].createrawtransaction([], sc_csw_tx_outs, sc_csws) sigRawtx = self.nodes[0].signrawtransaction(rawtx, None, None, "NONE") finalRawtx = self.nodes[0].sendrawtransaction(sigRawtx['hex']) mark_logs("tx = {}".format(finalRawtx), self.nodes, DEBUG_MODE) vtxCsw.append(finalRawtx) print self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) #pprint.pprint(decoded_tx) # vin - size(0): no utxo here # vout - size(1): recipient of the funds # vcsw_ccin - size(1): CSW funds assert_equal(0, len(decoded_tx['vin'])) assert_equal(1, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vcsw_ccin'])) assert_true(finalRawtx in self.nodes[2].getrawmempool()) # mine a block for clearing the mempool, we must not cross the limit for csw inputs to a SC mark_logs("\nNode0 generates 1 block", self.nodes, DEBUG_MODE) bl = self.nodes[0].generate(1)[-1] self.sync_all() mark_logs("Check all the txes have been included in the block...", self.nodes, DEBUG_MODE) blockTxList = self.nodes[0].getblock(bl, True)['tx'] for entry in vtxCsw: assert_true(entry in blockTxList) assert_true(len(self.nodes[2].getrawmempool()) == 0) vtxCsw = [] # --------------------------------------------------------------------------------------------------------- # 5) Two csw inputs and a sc creation, csws covering only part of the ccoutput mark_logs( "Two csw inputs and a sc creation, csws covering only part of the ccoutput...", self.nodes, DEBUG_MODE) cr_amount = Decimal("8.0") sc_address = "fade" vk2 = certMcTest.generate_params("sc2") constant2 = generate_random_field_element_hex() sc_cr = [{ "version": 0, "epoch_length": EPOCH_LENGTH, "amount": cr_amount, "address": sc_address, "wCertVk": vk2, "constant": constant2 }] sc_ft = [] null5 = generate_random_field_element_hex() null6 = generate_random_field_element_hex() sc_proof_a = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null5, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_proof_b = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null6, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null5, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof_a }, { "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null6, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof_b }] rawtx = self.nodes[1].createrawtransaction([], {}, sc_csws, sc_cr, sc_ft) 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("tx = {}".format(finalRawtx), self.nodes, DEBUG_MODE) vtxCsw.append(finalRawtx) print self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) #pprint.pprint(decoded_tx) # vin - size(1): utxo for paying the fee # vout - size(1): sender change # vccout - size(1): creation output # vcsw_ccin - size(2): CSW funds assert_equal(1, len(decoded_tx['vin'])) assert_equal(1, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vsc_ccout'])) assert_equal(2, len(decoded_tx['vcsw_ccin'])) assert_true(finalRawtx in self.nodes[2].getrawmempool()) scid2 = decoded_tx['vsc_ccout'][0]['scid'] # --------------------------------------------------------------------------------------------------------- # 6) Two csw inputs and a fw transfer to the latest created sc, csws spending more input than necessary mark_logs( "Two csw inputs and a fw transfer to the latest created sc, csws spending more input than necessary...", self.nodes, DEBUG_MODE) sc_address = "fade" sc_cr = [] sc_ft_amount = Decimal('1.0') mc_return_address = self.nodes[0].getnewaddress() sc_ft = [{ "address": sc_address, "amount": sc_ft_amount, "scid": scid2, "mcReturnAddress": mc_return_address }] null7 = generate_random_field_element_hex() null8 = generate_random_field_element_hex() sc_proof_a = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null7, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_proof_b = cswMcTest.create_test_proof("sc1", sc_csw_amount, str(scid_swapped), null8, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [{ "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null7, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof_a }, { "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": null8, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof_b }] rawtx = self.nodes[0].createrawtransaction([], {}, sc_csws, sc_cr, sc_ft) funded_tx = self.nodes[0].fundrawtransaction(rawtx) sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'], None, None, "NONE") #pprint.pprint(self.nodes[0].decoderawtransaction(sigRawtx['hex'])) #raw_input("______________") finalRawtx = self.nodes[0].sendrawtransaction(sigRawtx['hex']) mark_logs("tx = {}".format(finalRawtx), self.nodes, DEBUG_MODE) vtxCsw.append(finalRawtx) print self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(finalRawtx, 1) #pprint.pprint(decoded_tx) # vin - size(0): no utxo needed # vout - size(1): recipient of sender change # vccout - size(1): fwt output # vcsw_ccin - size(2): CSW funds assert_equal(0, len(decoded_tx['vin'])) assert_equal(1, len(decoded_tx['vout'])) assert_equal(1, len(decoded_tx['vft_ccout'])) assert_equal(2, len(decoded_tx['vcsw_ccin'])) assert_true(finalRawtx in self.nodes[2].getrawmempool()) mark_logs("\nNode0 generates 1 block confirming txes with csw", self.nodes, DEBUG_MODE) bl = self.nodes[0].generate(1)[-1] self.sync_all() mark_logs("Check all the txes have been included in the block...", self.nodes, DEBUG_MODE) blockTxList = self.nodes[0].getblock(bl, True)['tx'] for entry in vtxCsw: assert_true(entry in blockTxList) assert_true(len(self.nodes[2].getrawmempool()) == 0)
def run_test(self): def removekey(d, key='unconf'): r = dict(d) for k in d: if key in k: del r[k] return r ''' Node0 creates a SC and sends funds to it, and then sends a cert to it with a bwt to Node1 Node0 then sends a few tx with fwt to the same SC and then a second cert with a bwt to Node2 Node0 than invalidates all the latest blocks one by one checking sc state and checking also that a cert remains in mempool until its end epoch is reverted Node0 finally generates a sufficient number of blocks for reverting other nodes' chains and the test checks their sc state ''' sc_txes = [] certs = [] # forward transfer amount creation_amount = Decimal("0.5") fwt_amount_1 = Decimal("1000.0") fwt_amount_2 = Decimal("1.0") fwt_amount_3 = Decimal("2.0") fwt_amount_4 = Decimal("3.0") bwt_amount_1 = Decimal("8.0") bwt_amount_2 = Decimal("8.5") sc_info = [] # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 0 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) 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() mark_logs( "Node0 creates the SC spending {} coins ...".format( creation_amount), 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)) sc_info.append(removekey(self.nodes[0].getscinfo(scid)['items'][0])) 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("creating_tx = {}".format(creating_tx), self.nodes, DEBUG_MODE) sc_txes.append(creating_tx) self.sync_all() prev_epoch_block_hash = self.nodes[0].getblockhash( self.nodes[0].getblockcount()) self.refresh_sidechain(sc_info, scid) sc_creating_height = self.nodes[0].getblockcount() mark_logs( "Node 0 performs a fwd transfer of {} coins to SC...".format( fwt_amount_1), self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount_1, "scid": scid, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) print "fwd_tx=" + fwd_tx sc_txes.append(fwd_tx) self.sync_all() self.refresh_sidechain(sc_info, scid) addr_node1 = self.nodes[1].getnewaddress() addr_node2 = self.nodes[2].getnewaddress() mark_logs("...3 more blocks needed for achieving sc coins maturity", self.nodes, DEBUG_MODE) self.refresh_sidechain(sc_info, scid) self.refresh_sidechain(sc_info, scid) self.refresh_sidechain(sc_info, scid) mark_logs( "##### End epoch block = {}".format( self.nodes[0].getbestblockhash()), self.nodes, DEBUG_MODE) epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) mark_logs( "epoch_number = {}, epoch_cum_tree_hash = {}".format( epoch_number, epoch_cum_tree_hash), self.nodes, DEBUG_MODE) mark_logs( "Node 0 performs a bwd transfer of {} coins to Node1...".format( bwt_amount_1), self.nodes, DEBUG_MODE) amounts = [] amounts.append({"address": addr_node1, "amount": bwt_amount_1}) #Create proof for WCert quality = 0 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_1]) cert = self.nodes[0].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("cert = {}".format(cert), self.nodes, DEBUG_MODE) certs.append(cert) self.sync_all() self.refresh_sidechain(sc_info, scid) mark_logs( "Node 0 performs a fwd transfer of {} coins to SC...".format( fwt_amount_2), self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount_2, "scid": scid, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs("fwd_tx = {}".format(fwd_tx), self.nodes, DEBUG_MODE) sc_txes.append(fwd_tx) self.sync_all() self.refresh_sidechain(sc_info, scid) mark_logs( "Node 0 performs a fwd transfer of {} coins to SC...".format( fwt_amount_3), self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount_3, "scid": scid, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs("fwd_tx = {}".format(fwd_tx), self.nodes, DEBUG_MODE) sc_txes.append(fwd_tx) self.sync_all() self.refresh_sidechain(sc_info, scid) mark_logs( "Node 0 performs a fwd transfer of {} coins to SC...".format( fwt_amount_4), self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount_4, "scid": scid, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs("fwd_tx = {}".format(fwd_tx), self.nodes, DEBUG_MODE) sc_txes.append(fwd_tx) self.sync_all() self.refresh_sidechain(sc_info, scid) self.refresh_sidechain(sc_info, scid) mark_logs( "##### End epoch block = {}".format( self.nodes[0].getbestblockhash()), self.nodes, DEBUG_MODE) self.refresh_sidechain(sc_info, scid) epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) sc_creating_height = self.nodes[0].getscinfo( scid)['items'][0]['createdAtBlockHeight'] epoch_block_hash = self.nodes[0].getblockhash(sc_creating_height - 1 + ((epoch_number + 1) * EPOCH_LENGTH)) mark_logs( "epoch_number = {}, epoch_cum_tree_hash = {}".format( epoch_number, epoch_cum_tree_hash), self.nodes, DEBUG_MODE) mark_logs( "Node 0 performs a bwd transfer of {} coins to Node2...".format( bwt_amount_2), self.nodes, DEBUG_MODE) amounts = [] amounts.append({"address": addr_node2, "amount": bwt_amount_2}) #Create proof for WCert quality = 1 proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node2], [bwt_amount_2]) cert = self.nodes[0].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("cert = {}".format(cert), self.nodes, DEBUG_MODE) certs.append(cert) self.sync_all() self.refresh_sidechain(sc_info, scid) old_bal = self.nodes[0].getbalance() cross_epoch_1 = False cross_epoch_0 = False end_epoch_height = self.nodes[0].getblock(epoch_block_hash)['height'] # invalidate all blocks one by one for j in range(0, len(sc_info)): inv_hash = self.nodes[0].getbestblockhash() inv_heigth = self.nodes[0].getblockcount() mark_logs( "Node 0 invalidates last block of height = {}".format( inv_heigth), self.nodes, DEBUG_MODE) self.nodes[0].invalidateblock(inv_hash) sync_mempools(self.nodes[1:3]) sc_info.pop() # check that last cert is always in mempool until end epoch is reverted if (end_epoch_height < inv_heigth): assert_true(certs[1] in self.nodes[0].getrawmempool()) mark_logs("cert[{}] is in mempool".format(certs[1]), self.nodes, DEBUG_MODE) else: assert_false(certs[1] in self.nodes[0].getrawmempool()) # list are empty, exit loop if (len(sc_info) == 0): break try: ret = removekey(self.nodes[0].getscinfo(scid)['items'][0]) assert_equal(ret, sc_info[-1]) except JSONRPCException, e: errorString = e.error['message'] print errorString if (inv_heigth > sc_creating_height): assert (False) assert_true(creating_tx in self.nodes[0].getrawmempool()) mark_logs("creating tx[{}] is in mempool".format(creating_tx), self.nodes, DEBUG_MODE)
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 fwt, mbtr and a certificate, all of them are stored in mempool. The other network part sends a certificate and mines one block reaching a longer chain height. When the network is joined, verify that the SC is alive, fwt is still in the mempool of the the loosing network part, but cert and mbtr have been removed from those 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) # generate wCertVk and constant vk = certMcTest.generate_params("sc1") constant = generate_random_field_element_hex() cmdInput = { 'version': 0, 'withdrawalEpochLength': sc_epoch_len, 'amount': sc_cr_amount, 'toaddress': sc_address, 'wCertVk': vk, 'constant': constant, 'mainchainBackwardTransferRequestDataLength': 1 } res = self.nodes[0].sc_create(cmdInput) tx = res['txid'] scid = res['scid'] scid_swapped = str(swap_bytes(scid)) self.sync_all() mark_logs("tx {} created SC {}".format(tx, scid), self.nodes, DEBUG_MODE) dest_addr = self.nodes[1].getnewaddress() fe1 = [generate_random_field_element_hex()] # 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() bal_initial = self.nodes[0].getscinfo(scid, False, False)['items'][0]['balance'] #============================================================================================ 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 "------------------" # use different nodes for sending txes and cert in order to be sure there are no dependancies from each other fwt_amount = Decimal("2.0") mc_return_address = self.nodes[0].getnewaddress() mark_logs( "\nNTW part 1) Node0 sends {} coins to SC".format(fwt_amount), self.nodes, DEBUG_MODE) cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount, "scid": scid, 'mcReturnAddress': mc_return_address }] tx_fwd = self.nodes[0].sc_send(cmdInput) sync_mempools(self.nodes[0:3]) mark_logs(" Check fwd tx {} is in mempool".format(tx_fwd), self.nodes, DEBUG_MODE) assert_true(tx_fwd in self.nodes[0].getrawmempool()) outputs = [{ 'vScRequestData': fe1, 'scFee': Decimal("0.001"), 'scid': scid, 'mcDestinationAddress': dest_addr }] cmdParms = {"minconf": 0, "fee": 0.0} mark_logs("\nNTW part 1) Node1 creates a tx with a bwt request", self.nodes, DEBUG_MODE) try: tx_bwt = self.nodes[1].sc_request_transfer(outputs, cmdParms) 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 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)
def run_test(self): #Give time to explorer to start self.nodes[0].generate(MINIMAL_SC_HEIGHT) self.sync_all() time.sleep(35) self.nodes[0].getnewaddress() tAddr = self.nodes[0].getnewaddress() tAddr2 = self.nodes[0].getnewaddress() zAddr = self.nodes[0].z_getnewaddress() zAddr2 = self.nodes[1].z_getnewaddress() ############################################################################################################################# #### /tx/:txid #### print("######## /tx/:txid ########") #Test coinbase-transaction coinbaseTxId = self.nodes[0].getblock("100")['tx'][0] coinbaseTx = self.nodes[0].gettransaction(coinbaseTxId) decodedCoinbaseTx = self.nodes[0].decoderawtransaction(coinbaseTx['hex']) r = requests.get(url = self.BASE_URL+"block/"+self.nodes[0].getblock("400")['hash'], params = {}) data = r.json() r = requests.get(url = self.BASE_URL+"tx/"+coinbaseTxId, params = {}) data = r.json() self.validate_full_tx(data,decodedCoinbaseTx,coinbaseTx) #Test t-transaction tTxId = self.nodes[0].sendtoaddress(tAddr,10.0001) self.sync_all() self.nodes[0].generate(2) self.sync_all() time.sleep(5) transparentTx = self.nodes[0].gettransaction(tTxId) decodedTransparentTx = self.nodes[0].decoderawtransaction(transparentTx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+tTxId, params = {}) data = r.json() self.validate_full_tx(data,decodedTransparentTx, transparentTx) ''' #This parameter doesn't work on this version of the explorer #Test noAsm parameter r = requests.get(url = self.BASE_URL+"tx/"+tTxId+"?noAsm=true", params = {}) data = r.json() print(data) for output in data['vout']: assert_false('asm' in output['scriptPubKey']) ''' #Test z-transaction t->z myopid = self.nodes[0].z_sendmany(tAddr,[{"address":zAddr,"amount":4.0},{"address":zAddr2,"amount":6.0}]) zTxid = wait_and_assert_operationid_status(self.nodes[0],myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(zAddr),4) assert_equal(self.nodes[1].z_getbalance(zAddr2),6) shieldTx = self.nodes[0].gettransaction(zTxid) decodedShieldTx = self.nodes[0].decoderawtransaction(shieldTx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+zTxid, params = {}) data = r.json() self.validate_full_tx(data,decodedShieldTx,shieldTx) #Test z-transaction z->z myopid = self.nodes[0].z_sendmany(zAddr,[{"address":zAddr2,"amount":3.0}]) zTxid2 = wait_and_assert_operationid_status(self.nodes[0],myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() shieldTx = self.nodes[0].gettransaction(zTxid2) decodedShieldTx = self.nodes[0].decoderawtransaction(shieldTx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+zTxid2, params = {}) data = r.json() self.validate_full_tx(data,decodedShieldTx,shieldTx,True) #Test multiple sidechain creation txId = self.nodes[0].sendtoaddress(tAddr2,20.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() tx = self.nodes[0].gettransaction(txId) rawtx = self.nodes[0].decoderawtransaction(tx['hex']) vout = {} for outpoint in rawtx['vout']: if (outpoint['value'] == Decimal('20.0')): vout = outpoint break sc_address = "0000000000000000000000000000000000000000000000000000000000000abc" sc_address2 = "0000000000000000000000000000000000000000000000000000000000000acb" sc_epoch = 100 sc_cr_amount = Decimal('5.00000000') #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() vk2 = mcTest.generate_params("sc2") cswVk = cswMcTest.generate_params("sc1") cswVk2 = cswMcTest.generate_params("sc2") sc = [{"epoch_length": sc_epoch, "address": sc_address, "amount": sc_cr_amount,"wCertVk": vk, "constant": constant, "mainchainBackwardTransferScFee": MBTR_SC_FEE, "mainchainBackwardTransferRequestDataLength": 1, "wCeasedVk": cswVk, "version":1}, {"epoch_length": sc_epoch, "address": sc_address2, "amount": sc_cr_amount, "wCertVk": vk2, "constant": constant, "mainchainBackwardTransferScFee": MBTR_SC_FEE, "mainchainBackwardTransferRequestDataLength": 1, "wCeasedVk": cswVk2, "version":1}] inputs = [{'txid': txId, 'vout': vout['n']}] rawtx = self.nodes[0].createrawtransaction(inputs, {tAddr2: 10.0}, [], sc, []) sigRawtx = self.nodes[0].signrawtransaction(rawtx) scTxid = self.nodes[0].sendrawtransaction(sigRawtx['hex']) self.sync_all() time.sleep(2) self.nodes[0].generate(1) self.sync_all() time.sleep(2) scTx = self.nodes[0].gettransaction(scTxid) scid = scTx['vsc_ccout'][0]['scid'] scid2 = scTx['vsc_ccout'][1]['scid'] assert_equal(len(self.nodes[0].getscinfo("*")['items']),2) decodedScTx = self.nodes[0].decoderawtransaction(scTx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+scTxid, params = {}) data = r.json() self.validate_full_tx(data,decodedScTx,scTx) #Test with multiple forward transfers rawtx = self.nodes[0].decoderawtransaction(scTx['hex']) vout = {} for outpoint in rawtx['vout']: if (outpoint['value'] == Decimal('10.0')): vout = outpoint break mcReturnAddress = self.nodes[0].getnewaddress() ft = [{"address": sc_address, "amount": sc_cr_amount, "scid": scid, "mcReturnAddress": mcReturnAddress}, {"address": sc_address2, "amount": sc_cr_amount, "scid": scid2, "mcReturnAddress": mcReturnAddress}] inputs = [{'txid': scTxid, 'vout': vout['n']}] rawtx = self.nodes[0].createrawtransaction(inputs, {}, [], [], ft) sigRawtx = self.nodes[0].signrawtransaction(rawtx) ftTxid = self.nodes[0].sendrawtransaction(sigRawtx['hex']) self.sync_all() self.nodes[0].generate(1) self.sync_all() ftTx = self.nodes[0].gettransaction(ftTxid) decodedFtTx = self.nodes[0].decoderawtransaction(ftTx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+ftTxid, params = {}) data = r.json() self.validate_full_tx(data,decodedFtTx,ftTx) #Test with BackwardTransferRequest bwtr_address = self.nodes[0].getnewaddress() btwr_txid=self.nodes[0].sc_request_transfer([ {'mcDestinationAddress': bwtr_address, 'vScRequestData': [generate_random_field_element_hex()], 'scid': scid, 'scFee': Decimal('1.0')}, {'mcDestinationAddress': bwtr_address, 'vScRequestData': [generate_random_field_element_hex()], 'scid': scid2, 'scFee': Decimal('1.0')} ]) self.sync_all() time.sleep(1) self.nodes[0].generate(1) self.sync_all() time.sleep(2) bwtrTx = self.nodes[0].gettransaction(btwr_txid) decodedBwtrTx = self.nodes[0].decoderawtransaction(bwtrTx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+btwr_txid, params = {}) data = r.json() self.validate_full_tx(data,decodedBwtrTx,bwtrTx) #Test with a immature certificate self.nodes[0].generate(sc_epoch) self.sync_all() time.sleep(5) #Mine Certificate 1 with quality = 5 epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], sc_epoch) quality = 5 pkh_node1 = self.nodes[1].getnewaddress() bwt_amount = Decimal('3.0') proof = mcTest.create_test_proof( "sc1", swap_bytes(scid), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [pkh_node1], [bwt_amount]) amount_cert_1 = [{"address": pkh_node1, "amount": bwt_amount}] 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() cert1_block = self.nodes[0].generate(1)[0] self.sync_all() time.sleep(2) r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=1", params = {}) data = r.json() certTx = self.nodes[0].gettransaction(cert1) decodedCertTx = self.nodes[0].decoderawtransaction(certTx['hex']) certInfo = self.nodes[0].getcertmaturityinfo(cert1) self.validate_full_tx(data, decodedCertTx, certTx) self.validate_certificate(data, certInfo, True) r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=0", params = {}) data = r.json() self.validate_certificate(data, certInfo, False) r = requests.get(url = self.BASE_URL+"tx/"+cert1, params = {}) data = r.json() self.validate_certificate(data, certInfo, False) #Test also the /txs endpoint with blockhash r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=1", params = {}) data = r.json() assert_equal(len(data['txs']), 2) self.validate_certificate(data['txs'][1], certInfo, True) r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=0", params = {}) data = r.json() assert_equal(len(data['txs']), 2) self.validate_certificate(data['txs'][1], certInfo, False) r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block, params = {}) data = r.json() assert_equal(len(data['txs']), 2) self.validate_certificate(data['txs'][1], certInfo, False) #Test also the /txs endpoint with address r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=1", params = {}) data = r.json() found = False for tx in data['txs']: if (tx['version'] == -5): assert_false(found) found = True self.validate_certificate(tx, certInfo, True) assert_true(found) found = False r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=0", params = {}) data = r.json() for tx in data['txs']: if (tx['version'] == -5): assert_false(found) found = True self.validate_certificate(tx, certInfo, True) assert_true(found) found = False r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1, params = {}) data = r.json() for tx in data['txs']: if (tx['version'] == -5): assert_false(found) found = True self.validate_certificate(tx, certInfo, True) assert_true(found) #Advance of 1 epoch self.nodes[0].generate(110) self.sync_all() #Create a block with 2 certificates (one will be superseded) that let mature the certificate of the previous epoch quality = 7 epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], sc_epoch) proof = mcTest.create_test_proof( "sc1", str(swap_bytes(scid)), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [pkh_node1], [bwt_amount]) amount_cert_2 = [{"address": pkh_node1, "amount": bwt_amount}] 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() quality = 9 proof = mcTest.create_test_proof( "sc1", str(swap_bytes(scid)), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [pkh_node1], [bwt_amount]) cert3 = 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) cert2_3_block = self.nodes[0].generate(30)[0] self.sync_all() time.sleep(2) #Test that the first certificate became mature certInfo = self.nodes[0].getcertmaturityinfo(cert1) r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=1", params = {}) data = r.json() self.validate_certificate(data, certInfo, True) r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=0", params = {}) data = r.json() self.validate_certificate(data, certInfo, True) r = requests.get(url = self.BASE_URL+"tx/"+cert1, params = {}) data = r.json() self.validate_certificate(data, certInfo, True) #Test also the /txs endpoint with blockhash r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=1", params = {}) data = r.json() assert_equal(len(data['txs']), 2) self.validate_certificate(data['txs'][1], certInfo, True) r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=0", params = {}) data = r.json() assert_equal(len(data['txs']), 2) self.validate_certificate(data['txs'][1], certInfo, True) r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block, params = {}) data = r.json() assert_equal(len(data['txs']), 2) self.validate_certificate(data['txs'][1], certInfo, True) #Test also the /txs endpoint with address r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=1", params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert1): self.validate_certificate(tx, certInfo, True) r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=0", params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert1): self.validate_certificate(tx, certInfo, True) r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1, params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert1): self.validate_certificate(tx, certInfo, True) #Test that the certificate 2 is superseded certTx2 = self.nodes[0].gettransaction(cert2) certInfo2 = self.nodes[0].getcertmaturityinfo(cert2) r = requests.get(url = self.BASE_URL+"tx/"+cert2+"?showImmatureBTs=1", params = {}) data = r.json() self.validate_certificate(data, certInfo2, False) r = requests.get(url = self.BASE_URL+"tx/"+cert2+"?showImmatureBTs=0", params = {}) data = r.json() self.validate_certificate(data, certInfo2, False) r = requests.get(url = self.BASE_URL+"tx/"+cert2, params = {}) data = r.json() self.validate_certificate(data, certInfo2, False) #Test also the /txs endpoint with blockhash r = requests.get(url = self.BASE_URL+"txs?block="+cert2_3_block+"&showImmatureBTs=1", params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert2): self.validate_certificate(tx, certInfo2, False) r = requests.get(url = self.BASE_URL+"txs?block="+cert2_3_block+"&showImmatureBTs=0", params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert2): self.validate_certificate(tx, certInfo2, False) r = requests.get(url = self.BASE_URL+"txs?block="+cert2_3_block, params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert2): self.validate_certificate(tx, certInfo2, False) #Test also the /txs endpoint with address r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=1", params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert2): self.validate_certificate(tx, certInfo2, False) r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=0", params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert2): self.validate_certificate(tx, certInfo2, False) r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1, params = {}) data = r.json() for tx in data['txs']: if (tx['txid'] == cert2): self.validate_certificate(tx, certInfo2, False) #Let the sidechains to cease self.nodes[0].generate(120) self.sync_all() assert_equal(self.nodes[0].getscinfo("*",True)['totalItems'], 0) time.sleep(20) #Test with a CSW # CSW sender MC address, in taddress and pub key hash formats csw_mc_address = self.nodes[0].getnewaddress() sc_csw_amount = Decimal('1.0') nullifier = generate_random_field_element_hex() # Get the active cert data hash actCertData = self.nodes[0].getactivecertdatahash(scid)['certDataHash'] ceasingCumScTxCommTree = self.nodes[0].getceasingcumsccommtreehash(scid)['ceasingCumScTxCommTree'] scid1_swapped = swap_bytes(scid) sc_proof = cswMcTest.create_test_proof( "sc1", sc_csw_amount, str(scid1_swapped), nullifier, csw_mc_address, ceasingCumScTxCommTree, actCertData, constant) sc_csws = [ { "amount": sc_csw_amount, "senderAddress": csw_mc_address, "scId": scid, "epoch": 0, "nullifier": nullifier, "activeCertData": actCertData, "ceasingCumScTxCommTree": ceasingCumScTxCommTree, "scProof": sc_proof } ] # recipient MC address taddr_2 = self.nodes[0].getnewaddress() sc_csw_tx_outs = {taddr_2: Decimal(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") cswTxid = self.nodes[0].sendrawtransaction(sigRawtx['hex']) self.sync_all() time.sleep(2) self.nodes[0].generate(1) self.sync_all() time.sleep(2) r = requests.get(url = self.BASE_URL+"tx/"+cswTxid, params = {}) data = r.json() cswTx = self.nodes[0].gettransaction(cswTxid) decodedCswTx = self.nodes[0].decoderawtransaction(cswTx['hex']) self.validate_full_tx(data,decodedCswTx,cswTx) #Test with an invalid txid invalidTxId = "fe86fa1c6d61585e5e24424997d1542d8857758033937fa0812c407d83adfd14" r = requests.get(url = self.BASE_URL+"tx/"+invalidTxId, params = {}) assert_equal(r.text,"Not found") ############################################################################################################################# #### /rawtx/:rawId #### print("######## /rawtx/:rawId ########") #Test coinbase-transaction r = requests.get(url = self.BASE_URL+"rawtx/"+coinbaseTxId, params = {}) data = r.json() assert_equal(data['rawtx'],self.nodes[0].gettransaction(coinbaseTxId)['hex']) #Test t-transaction r = requests.get(url = self.BASE_URL+"rawtx/"+tTxId, params = {}) data = r.json() assert_equal(data['rawtx'],self.nodes[0].gettransaction(tTxId)['hex']) #Test z-transaction t->z r = requests.get(url = self.BASE_URL+"rawtx/"+zTxid, params = {}) data = r.json() assert_equal(data['rawtx'],self.nodes[0].gettransaction(zTxid)['hex']) #Test z-transaction z->z r = requests.get(url = self.BASE_URL+"rawtx/"+zTxid2, params = {}) data = r.json() assert_equal(data['rawtx'],self.nodes[0].gettransaction(zTxid2)['hex']) #Test multiple sidechain creation and ft r = requests.get(url = self.BASE_URL+"rawtx/"+scTxid, params = {}) data = r.json() assert_equal(data['rawtx'],self.nodes[0].gettransaction(scTxid)['hex']) #Test with an invalid txid invalidTxId = "fe86fa1c6d61585e5e24424997d1542d8857758033937fa0812c407d83adfd14" r = requests.get(url = self.BASE_URL+"rawtx/"+invalidTxId, params = {}) assert_equal(r.text,"Not found") ############################################################################################################################# #### /tx/send #### print("######## /tx/send ########") txId = self.nodes[0].sendtoaddress(tAddr,10.0001) self.sync_all() self.nodes[0].generate(1) self.sync_all() tx = self.nodes[0].gettransaction(txId) rawtx = self.nodes[0].decoderawtransaction(tx['hex']) vout = {} for outpoint in rawtx['vout']: if (outpoint['value'] == Decimal('10.0001')): vout = outpoint break inputs = [{'txid': txId, 'vout': vout['n']}] rawtx = self.nodes[0].createrawtransaction(inputs, {tAddr2:8.0,tAddr:2.0}) sigRawtx = self.nodes[0].signrawtransaction(rawtx) #Test with not signed tx r = requests.post(url = self.BASE_URL+"tx/send", json={"rawtx":rawtx}) assert_equal(r.status_code,400) #Test with signed tx r = requests.post(url = self.BASE_URL+"tx/send", json={"rawtx":sigRawtx['hex']}) assert_equal(r.status_code,200) self.sync_all() self.nodes[0].generate(1) self.sync_all() txid = r.json()['txid'] tx = self.nodes[0].gettransaction(txid) decodedTx = self.nodes[0].decoderawtransaction(tx['hex']) assert_equal(tx['hex'],sigRawtx['hex']) r = requests.get(url = self.BASE_URL+"tx/"+txid, params = {}) data = r.json() self.validate_full_tx(data,decodedTx, tx) ############################################################################################################################# #### /txs #### #Test with blockhash txs = [] for i in range (1,36): txs += [self.nodes[0].sendtoaddress(tAddr,Decimal(str(i)))] self.sync_all() block = self.nodes[0].generate(1) self.sync_all() #Add the coinbase to the list of transactions txs +=[self.nodes[0].getblock(block[0])['tx'][0]] time.sleep(5) #Test withouth pageNum (1st page) r = requests.get(url = self.BASE_URL+"txs?block="+block[0], params = {}) data = r.json() assert_equal(len(data['txs']),10) assert_equal(data['pagesTotal'],4) for tx in data['txs']: assert_true(tx['txid'] in txs) transaction = self.nodes[0].gettransaction(tx['txid']) decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex']) self.validate_full_tx(tx,decodedTransaction,transaction) #Test with pageNum r = requests.get(url = self.BASE_URL+"txs?pageNum=1&block="+block[0], params = {}) data = r.json() assert_equal(len(data['txs']),10) assert_equal(data['pagesTotal'],4) for tx in data['txs']: assert_true(tx['txid'] in txs) transaction = self.nodes[0].gettransaction(tx['txid']) decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex']) self.validate_full_tx(tx,decodedTransaction,transaction) #Test with last pageNum r = requests.get(url = self.BASE_URL+"txs?pageNum=3&block="+block[0], params = {}) data = r.json() assert_equal(len(data['txs']),6) assert_equal(data['pagesTotal'],4) for tx in data['txs']: assert_true(tx['txid'] in txs) transaction = self.nodes[0].gettransaction(tx['txid']) decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex']) self.validate_full_tx(tx,decodedTransaction,transaction) #Test with invalid blockhash invalidBlockHash = "010857e2c8d072c0142aad2faeca8a856e438fe2d1fe963d78dba8d9e5f664b8" r = requests.get(url = self.BASE_URL+"txs?block="+invalidBlockHash, params = {}) assert_equal(r.status_code,404) #Test with address and no pageNum (1st page) r = requests.get(url = self.BASE_URL+"txs?address="+tAddr, params = {}) data = r.json() assert_equal(len(data['txs']),10) assert_equal(data['pagesTotal'],4) txs += [txid,txId,tTxId,zTxid] for tx in data['txs']: assert_true(tx['txid'] in txs) transaction = self.nodes[0].gettransaction(tx['txid']) decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex']) self.validate_full_tx(tx,decodedTransaction,transaction) #Test with address and no pageNum (1st page) r = requests.get(url = self.BASE_URL+"txs?pageNum=1&address="+tAddr, params = {}) data = r.json() assert_equal(len(data['txs']),10) assert_equal(data['pagesTotal'],4) for tx in data['txs']: assert_true(tx['txid'] in txs) transaction = self.nodes[0].gettransaction(tx['txid']) decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex']) self.validate_full_tx(tx,decodedTransaction,transaction) #Test with address and last pageNum r = requests.get(url = self.BASE_URL+"txs?pageNum=3&address="+tAddr, params = {}) data = r.json() assert_equal(len(data['txs']),9) assert_equal(data['pagesTotal'],4) for tx in data['txs']: assert_true(tx['txid'] in txs) transaction = self.nodes[0].gettransaction(tx['txid']) decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex']) self.validate_full_tx(tx,decodedTransaction,transaction) #Test with invalid address invalidAddress = "ztVfuvhoNcrunLThJvNeRmg7on4NWidvsVk" r = requests.get(url = self.BASE_URL+"txs?address="+invalidAddress, params = {}) data = r.json() assert_equal(len(data['txs']),0) assert_equal(data['pagesTotal'],0) #Test with no parameters r = requests.get(url = self.BASE_URL+"txs", params = {}) assert_equal(r.status_code,503)
def run_test(self): ''' ( 1) Create a SC ( 2) Advance to next epoch ( 3) Send a cert to SC with 2 bwt to Node1 at the same address ( 4) checks behavior of some rpc cmd with bwt maturity info ''' creation_amount = Decimal("10.0") bwt_amount1 = Decimal("1.5") bwt_amount2 = Decimal("2.0") bwt_amount3 = Decimal("4.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 } # Create a SC with a budget of 10 coins ret = self.nodes[0].sc_create(cmdInput) creating_tx = ret['txid'] scid = ret['scid'] scid_swapped = str(swap_bytes(scid)) mark_logs( "Node 0 created the SC spending {} coins via tx {}.".format( creation_amount, creating_tx), self.nodes, DEBUG_MODE) self.sync_all() decoded_tx = self.nodes[1].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) self.nodes[0].generate(1) sc_creating_height = self.nodes[0].getblockcount() self.sync_all() mark_logs( "Node0 generates 4 more blocks to achieve end of withdrawal epochs", self.nodes, DEBUG_MODE) self.nodes[0].generate(4) self.sync_all() epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) bal_without_bwt = self.nodes[1].getbalance() # node0 create a cert_1 for funding node1 addr_node1 = self.nodes[1].getnewaddress() amounts = [{ "address": addr_node1, "amount": bwt_amount1 }, { "address": addr_node1, "amount": bwt_amount2 }] mark_logs( "Node 0 sends a cert for scid {} with 2 bwd transfers of {} coins to Node1 address" .format(scid, bwt_amount1 + bwt_amount2, addr_node1), self.nodes, DEBUG_MODE) try: # Create proof for WCert quality = 1 proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node1, addr_node1], [bwt_amount1, bwt_amount2]) cert_1 = self.nodes[0].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) mark_logs("==> certificate is {}".format(cert_1), self.nodes, DEBUG_MODE) self.sync_all() except JSONRPCException, e: errorString = e.error['message'] mark_logs( "Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert (False)
def run_test(self): ''' The test creates a sc, send funds to it and then: ( 1) Switch ON the CZendooLowPrioThreadGuard that should prevent any mempool Cert to be included, because of ProofVerifier threads are on pause. ( 2) Switch OFF the CZendooLowPrioThreadGuard -> certificate must be applied to mempool. ( 3) Switch ON the CZendooLowPrioThreadGuard and try to generate the block with Certificate - must be successful ''' # forward transfer amounts creation_amount = Decimal("0.5") fwt_amount = Decimal("50") bwt_amount_bad = Decimal("100.0") bwt_amount = Decimal("50") self.nodes[0].getblockhash(0) mark_logs("Node generates {} block".format(MINIMAL_SC_HEIGHT), self.nodes, DEBUG_MODE) self.nodes[0].generate(MINIMAL_SC_HEIGHT) # SC creation # 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 created the SC spending {} coins via tx {}.".format(creation_amount, creating_tx), self.nodes, DEBUG_MODE) 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("Node confirms Sc creation generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['balance'], Decimal(0)) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts'][0]['amount'], creation_amount) # Fwd Transfer to Sc bal_before_fwd_tx = self.nodes[0].getbalance("", 0) mark_logs("Node balance before fwd tx: {}".format(bal_before_fwd_tx), self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{'toaddress': "abcd", 'amount': fwt_amount, "scid": scid, "mcReturnAddress": mc_return_address}] fwd_tx = self.nodes[0].sc_send(cmdInput) mark_logs("Node transfers {} coins to SC with tx {}...".format(fwt_amount, fwd_tx), self.nodes, DEBUG_MODE) mark_logs("Node confirms fwd transfer generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['balance'], Decimal(0)) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts'][0]['amount'], creation_amount) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts'][1]['amount'], fwt_amount) nblocks = EPOCH_LENGTH - 2 mark_logs("Node0 generating {} more blocks to achieve end of withdrawal epoch".format(nblocks), self.nodes, DEBUG_MODE) self.nodes[0].generate(nblocks) assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['balance'], creation_amount + fwt_amount) # Sc balance has matured assert_equal(len(self.nodes[0].getscinfo(scid)['items'][0]['immatureAmounts']), 0) epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], EPOCH_LENGTH) mark_logs("epoch_number = {}, epoch_cum_tree_hash = {}".format(epoch_number, epoch_cum_tree_hash), self.nodes, DEBUG_MODE) addr_node0 = self.nodes[0].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_node0], [bwt_amount]) amount_cert_1 = [{"address": addr_node0, "amount": bwt_amount}] # Enable CZendooLowPrioThreadGuard mark_logs("Enable CZendooLowPrioThreadGuard...", self.nodes, DEBUG_MODE) res = self.nodes[0].setproofverifierlowpriorityguard(True) assert_equal(res["enabled"], True) # Try to send WCert - should fail because of the timeout: mempool proof verifier has low priority mark_logs("Node sends a certificate while CZendooLowPrioThreadGuard is enabled...", self.nodes, DEBUG_MODE) try: 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(False) except Exception as e: errorString = e.message assert("timed out" == errorString) # Establish new AuthServiceProxy, because previous one is dead after the timeout error self.nodes[0] = AuthServiceProxy(self.nodes[0].get_service_url(), timeout=10) mark_logs("Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) # Disable CZendooLowPrioThreadGuard mark_logs("Disable CZendooLowPrioThreadGuard...", self.nodes, DEBUG_MODE) res = self.nodes[0].setproofverifierlowpriorityguard(False) assert_equal(res["enabled"], False) # Try to send WCert mark_logs("Node sends a certificate while CZendooLowPrioThreadGuard is enabled...", 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) mark_logs("Certificate is {}".format(cert_epoch_0), self.nodes, DEBUG_MODE) except JSONRPCException, e: errorString = e.error['message'] mark_logs("Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert (False)
def run_test(self): def get_spendable(nodeIdx, min_amount): # get a UTXO for setting fee utx = False listunspent = self.nodes[nodeIdx].listunspent() for aUtx in listunspent: if aUtx['amount'] > min_amount: utx = aUtx change = aUtx['amount'] - min_amount break if utx == False: pprint.pprint(listunspent) assert_equal(utx != False, True) return utx, change ''' Testing the capabilities of the api for creating raw certificates and handling their decoding. Negative tests are also performed by specifying wrong params and incorrect pkey for the signing ''' # forward transfer amount cr_amount = Decimal("5.0") bt_amount = Decimal("4.0") sc_amount = cr_amount # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(1) self.sync_all() mark_logs("Node 0 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() mark_logs("Node 3 generates {} block".format(MINIMAL_SC_HEIGHT - 1), self.nodes, DEBUG_MODE) self.nodes[3].generate(MINIMAL_SC_HEIGHT - 1) self.sync_all() # node 1 has just the coinbase which is now mature bal_before = self.nodes[1].getbalance("", 0) # create a sc via createraw cmd mark_logs( "Node 1 creates the SC spending " + str(sc_amount) + " coins ...", self.nodes, DEBUG_MODE) sc_address = "fade" #generate vk and constant for this sidechain mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() sc_cr = [{ "version": 0, "epoch_length": EPOCH_LENGTH, "amount": cr_amount, "address": sc_address, "wCertVk": vk, "constant": constant }] sc_ft = [] raw_tx = self.nodes[1].createrawtransaction([], {}, [], sc_cr, sc_ft) funded_tx = self.nodes[1].fundrawtransaction(raw_tx) signed_tx = self.nodes[1].signrawtransaction(funded_tx['hex']) creating_tx = self.nodes[1].sendrawtransaction(signed_tx['hex']) self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(creating_tx, 1) scid = decoded_tx['vsc_ccout'][0]['scid'] scid_swapped = str(swap_bytes(scid)) mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE) #retrieve previous_end_epoch_mc_b_hash current_height = self.nodes[3].getblockcount() mark_logs("Node3 generating {} blocks".format(EPOCH_LENGTH), self.nodes, DEBUG_MODE) self.nodes[3].generate(EPOCH_LENGTH) self.sync_all() epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) # save them for the last test epn_0 = epoch_number epoch_cum_tree_hash_0 = epoch_cum_tree_hash # -------------------------- end epoch sc_funds_pre = self.nodes[3].getscinfo(scid)['items'][0]['balance'] addr_node2 = self.nodes[2].getnewaddress() mark_logs("Node3 generating 2 block, overcoming safeguard", self.nodes, DEBUG_MODE) self.nodes[3].generate(2) self.sync_all() # create wCert proof quality = 0 proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node2], [bt_amount]) utx, change = get_spendable(0, CERT_FEE) raw_inputs = [{'txid': utx['txid'], 'vout': utx['vout']}] raw_outs = {self.nodes[0].getnewaddress(): change} raw_bwt_outs = [{"address": addr_node2, "amount": bt_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) except JSONRPCException, e: errorString = e.error['message'] print "\n======> ", errorString assert_true(False)
def run_test(self): self.nodes[0].generate(110) self.sync_all() time.sleep(30) #### /block/:hash #### #Test with a simple block with only 1-transparent address tAddr1 = self.nodes[1].getnewaddress() tTxId = self.nodes[0].sendtoaddress(tAddr1,5.0) self.sync_all() block = self.nodes[0].generate(2) self.sync_all() blockRPC = self.nodes[0].getblock(block[0]) r = requests.get(url = self.BASE_URL+"block/"+block[0], params = {}) data = r.json() self.validate_full_block(data,blockRPC) assert_true(data['isMainChain']) assert_true('cert' not in data) self.nodes[0].generate(1) self.sync_all() tAddr = self.nodes[0].getnewaddress() self.nodes[0].sendtoaddress(tAddr,20.0) self.sync_all() #Test with a bt self.nodes[0].generate(MINIMAL_SC_HEIGHT) self.sync_all() sc_epoch = 100 sc_cr_amount = Decimal('5.00000000') #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() scAddress = "8aaddc9671dc5c8d33a3494df262883411935f4f54002fe283745fb394be508a" sc = self.nodes[0].sc_create({"withdrawalEpochLength":sc_epoch, "customData":"dada", "amount":sc_cr_amount, "wCertVk":vk, "constant": constant, "toaddress":scAddress}) scTxid = sc["txid"] scid = sc["scid"] self.sync_all() self.nodes[0].generate(1) self.sync_all() scid = self.nodes[0].gettransaction(scTxid)['vsc_ccout'][0]['scid'] assert_equal(len(self.nodes[0].getscinfo("*")['items']),1) assert_equal(self.nodes[0].getscinfo("*")['items'][0]['scid'],scid) self.nodes[0].generate(100) self.sync_all() endBlockHash = self.nodes[0].getblockhash(320) quality = 5 bwt_amount = 2.0 epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], sc_epoch) #Generate proof proof = mcTest.create_test_proof("sc1", str(swap_bytes(scid)), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [tAddr1], [bwt_amount]) amounts_cert = [{"address": tAddr1, "amount": bwt_amount}] self.nodes[1].sc_send_certificate(scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts_cert, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) self.sync_all() certblock = self.nodes[0].generate(1) self.sync_all() blockRPC = self.nodes[0].getblock(certblock[0]) r = requests.get(url = self.BASE_URL+"block/"+certblock[0], params = {}) data = r.json() self.validate_full_block(data,blockRPC) assert_true(data['isMainChain']) #Test with an invalid hash invalidHash = "010857e2c8d072c0142aad2faeca8a856e438fe2d1fe963d78dba8d9e5f664b8" r = requests.get(url = self.BASE_URL+"block/"+invalidHash, params = {}) assert_equal(r.text,"Not found") ############################################################################################################################# #### /block-index/:height #### r = requests.get(url = self.BASE_URL+"block-index/320", params = {}) data = r.json() assert_equal(data['blockHash'],endBlockHash) #Test with an invalid height r = requests.get(url = self.BASE_URL+"block-index/800", params = {}) assert_equal(r.text,"Block height out of range. Code:-8") ############################################################################################################################# #### /rawblock/:blockHash #### r = requests.get(url = self.BASE_URL+"rawblock/"+endBlockHash, params = {}) data = r.json() rawblockRPC = self.nodes[0].getblock(endBlockHash,False) assert_equal(data['rawblock'],rawblockRPC) #Test with an invalid hash r = requests.get(url = self.BASE_URL+"rawblock/800", params = {}) assert_equal(r.text,"Not found") #Test with an invalid hash r = requests.get(url = self.BASE_URL+"rawblock/"+invalidHash, params = {}) assert_equal(r.status_code, 404) ############################################################################################################################# #### /blocks #### self.nodes[0].generate(100) self.sync_all() #Test the max number of block returned r = requests.get(url = self.BASE_URL+"blocks", params = {}) data = r.json() assert_equal(data['length'],200) assert_equal(len(data['blocks']),200) assert_true(data['pagination']['more']) #Test all blocks returned for block in data['blocks']: blockRPC = self.nodes[0].getblock(block['hash']) self.validate_block(block,blockRPC)
def run_test(self): ''' The test creates a sc, send funds to it and then sends a certificate to it, Then test that getrawtransaction decodes correctly tx and cert when possible. ''' # forward transfer amounts creation_amount = Decimal("0.5") fwt_amount = Decimal("50") bwt_amount = Decimal("50") # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(1) 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() # SC creation #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk_tag = "sc1" vk = mcTest.generate_params(vk_tag) constant = generate_random_field_element_hex() cmdInput = { "version": 0, "withdrawalEpochLength": EPOCH_LENGTH, "toaddress": "dada", "amount": creation_amount, "wCertVk": vk, "constant": constant, } ret = self.nodes[1].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_mempool = self.nodes[1].getrawtransaction(creating_tx, 1) assert_equal(scid, decoded_tx_mempool['vsc_ccout'][0]['scid']) decoded_tx_mempool_hex = self.nodes[1].getrawtransaction(creating_tx) dec = self.nodes[1].decoderawtransaction(decoded_tx_mempool_hex) assert_equal(creating_tx, dec['txid']) assert_equal(scid, dec['vsc_ccout'][0]['scid']) mark_logs("Node0 confirms Sc creation generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) sc_creating_height = self.nodes[0].getblockcount() self.sync_all() decoded_tx_notxindex = self.nodes[1].getrawtransaction(creating_tx, 1) assert_equal(decoded_tx_mempool['hex'], decoded_tx_notxindex['hex']) decoded_tx_txindex = self.nodes[2].getrawtransaction(creating_tx, 1) assert_equal(decoded_tx_mempool['hex'], decoded_tx_txindex['hex']) # Fwd Transfer to Sc mark_logs("Node0 sends fwd transfer", self.nodes, DEBUG_MODE) mc_return_address = self.nodes[0].getnewaddress() cmdInput = [{ 'toaddress': "abcd", 'amount': fwt_amount, "scid": scid, 'mcReturnAddress': mc_return_address }] fwd_tx = self.nodes[0].sc_send(cmdInput) self.sync_all() decoded_tx_mempool = self.nodes[1].getrawtransaction(fwd_tx, 1) assert_equal(scid, decoded_tx_mempool['vft_ccout'][0]['scid']) mark_logs("Node0 confirms fwd transfer generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() decoded_tx_notxindex = self.nodes[1].getrawtransaction(fwd_tx, 1) assert_equal(decoded_tx_mempool['hex'], decoded_tx_notxindex['hex']) decoded_tx_txindex = self.nodes[2].getrawtransaction(fwd_tx, 1) assert_equal(decoded_tx_mempool['hex'], decoded_tx_txindex['hex']) mark_logs( "Node0 generating 3 more blocks to achieve end of withdrawal epoch", self.nodes, DEBUG_MODE) self.nodes[0].generate(3) self.sync_all() epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) addr_node1 = self.nodes[1].getnewaddress() amount_cert_1 = [{"address": addr_node1, "amount": bwt_amount}] #Create proof for WCert quality = 0 proof = mcTest.create_test_proof(vk_tag, scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node1], [bwt_amount]) mark_logs( "Node 0 performs a bwd transfer of {} coins to Node1 address {}". format(amount_cert_1[0]["address"], amount_cert_1[0]["amount"]), 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) mark_logs("Certificate is {}".format(cert_epoch_0), self.nodes, DEBUG_MODE) except JSONRPCException, e: errorString = e.error['message'] mark_logs( "Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert (False)
def run_test(self): ''' Node1 creates a sc and sends to it a certificate with a bwt to Node2 and a fee. Node0 mines a block and checks that the cert fee is contained in the coinbase Node0 sends a lot of small coins to Node3, who will use them as input for including a fee in a new certificate ''' # cross chain transfer amounts creation_amount = Decimal("0.5") bwt_amount = Decimal("0.4") # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(1) 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, "darlin") 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[1].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[1].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) prev_epoch_block_hash = self.nodes[0].getblockhash( self.nodes[0].getblockcount()) self.nodes[0].generate(1) self.sync_all() # fee can be seen on sender wallet (it is a negative value) fee = self.nodes[1].gettransaction(creating_tx)['fee'] mark_logs("Fee paid for SC creation: {}".format(fee), self.nodes, DEBUG_MODE) mark_logs( "Node0 generating 4 more blocks to achieve end of withdrawal epoch", self.nodes, DEBUG_MODE) self.nodes[0].generate(4) self.sync_all() mark_logs( "Sc {} state: {}".format( scid, self.nodes[0].getscinfo(scid)['items'][0]), self.nodes, DEBUG_MODE) epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[0], EPOCH_LENGTH) mark_logs( "epoch_number = {}, epoch_cum_tree_hash = {}".format( epoch_number, epoch_cum_tree_hash), self.nodes, DEBUG_MODE) addr_node2 = self.nodes[2].getnewaddress() amounts = [{"address": addr_node2, "amount": bwt_amount}] #Create proof for WCert quality = 1 proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node2], [bwt_amount]) mark_logs( "Node 1 performs a bwd transfer of {} coins to Node2 address {}". format(bwt_amount, addr_node2), self.nodes, DEBUG_MODE) try: cert_good = self.nodes[1].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, amounts, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE) assert (len(cert_good) > 0) mark_logs("Certificate is {}".format(cert_good), self.nodes, DEBUG_MODE) except JSONRPCException, e: errorString = e.error['message'] mark_logs( "Send certificate failed with reason {}".format(errorString), self.nodes, DEBUG_MODE) assert (False)