def run_test(self): mark_logs("Node 2 generates 150 block", self.nodes, DEBUG_MODE) self.nodes[2].generate(150) self.sync_all() # check block versions ( skip genesis that is 4) mark_logs(("Check that block version is %d" % BLOCK_VERSION), self.nodes, DEBUG_MODE) for i in range(1, 151): v = self.nodes[0].getblock(str(i))['version'] assert_equal(v, BLOCK_VERSION) # Mine 51 up-version blocks, they are supported up to sidechain fork mark_logs("Node 1 generates 51 block with an up-version", self.nodes, DEBUG_MODE) self.nodes[1].generate(51) self.sync_all() # check block versions mark_logs(("Check that block version is %d" % UP_VERSION), self.nodes, DEBUG_MODE) for i in range(151, 201): v = self.nodes[0].getblock(str(i))['version'] assert_equal(v, UP_VERSION) try: self.nodes[0].generate(1) raise AssertionError("Can not generate blocks with version = 2") except JSONRPCException, e: errorString = e.error['message'] mark_logs( errorString + " ===> Ok, Can not generate blocks with version = 2", self.nodes, DEBUG_MODE)
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 refresh_sidechain(self, sc_info, scid, nIdx=0): mark_logs("Node{} generating 1 block".format(nIdx), self.nodes, DEBUG_MODE) self.nodes[nIdx].generate(1) self.sync_all() sc_info.append(self.nodes[nIdx].getscinfo(scid)['items'][0]) mark_logs(" ==> height {}".format(self.nodes[nIdx].getblockcount()), self.nodes, DEBUG_MODE)
def send_unconf_to_node1(self, taddr, quota, numbtx): tot_amount = 0 for i in range(1, numbtx+1): amount = i*quota tot_amount += amount tx = self.nodes[1].sendtoaddress(taddr, amount) mark_logs("Node 1 sent {} coins to Node0 address {} via tx {}.".format(amount, taddr, tx), self.nodes, DEBUG_MODE) return tot_amount
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)
def getEpochData(self, sc_creating_height): current_height = self.nodes[0].getblockcount() epoch_number = (current_height - sc_creating_height + 1) // EPOCH_LENGTH - 1 mark_logs( "Current height {}, Sc creation height {}, epoch length {} --> current epoch number {}" .format(current_height, sc_creating_height, EPOCH_LENGTH, epoch_number), self.nodes, DEBUG_MODE) epoch_block_hash = self.nodes[0].getblockhash(sc_creating_height - 1 + ((epoch_number + 1) * EPOCH_LENGTH)) return epoch_block_hash, epoch_number
def run_test(self): ''' This test validates the rpc cmds for SBH wallet ''' amount_1 = Decimal("40.0") sc_creation_amount = Decimal("20.0") sc_fwd_amount = Decimal("15.0") bwt_amount1 = Decimal("10.0") amount_2 = Decimal("3.0") txs_node1 = [] # network topology: (0)--(1)--(2) mark_logs("\nNode 0 generates 220 blocks", self.nodes, DEBUG_MODE) self.nodes[0].generate(220) self.sync_all() taddr_1 = self.nodes[1].getnewaddress() #---------------------------------------------------------------------------------------------- tx = self.nodes[0].sendtoaddress(taddr_1, amount_1) self.sync_all() txs_node1.append(tx) mark_logs( "\n===> Node0 sent {} coins to Node1 at addr {}".format( amount_1, taddr_1), self.nodes, DEBUG_MODE) mark_logs("\nNode0 generates 1 more block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() #generate wCertVk and constant mcTest = MCTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() sc_creating_height = self.nodes[0].getblockcount() + 1 sc_toaddress = "5c1dadd" minconf = 1 fee = Decimal("0.000025") cmdInput = { "withdrawalEpochLength": EPOCH_LENGTH, "fromaddress": taddr_1, "toaddress": sc_toaddress, "amount": sc_creation_amount, "changeaddress": taddr_1, "fee": fee, "wCertVk": vk, "constant": constant } try: #---------------------------------------------------------------------------------------------- res = self.nodes[1].create_sidechain(cmdInput) tx = res['txid'] scid = res['scid'] txs_node1.append(tx) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true(False)
def run_test(self): ''' Create a few SCs specifying related configurations for the custom fields that a cert must set; during this phase, different versions of cmd for SC creation are tested. Send some certificate with custom fields configured accordingly to the SC they refer. Along the test execution, some negative test is also performed. JSON representation of scinfo as well as tx/cert are checked for expected contents too. ''' # network topology: (0)--(1) # Read the huge bit vector from file with open( os.path.dirname(os.path.abspath(__file__)) + "/../zen/test_data/16_GB_bitvector.bz2", "rb") as f: BIT_VECTOR_BUF_HUGE = binascii.hexlify(f.read()) mark_logs("Node 1 generates 2 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(2) self.sync_all() mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT), self.nodes, DEBUG_MODE) self.nodes[0].generate(MINIMAL_SC_HEIGHT) self.sync_all() #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params('sc1') constant1 = generate_random_field_element_hex() amount = Decimal("1.0") fee = 0.000025 #------------------------------------------------------- bad_obj = {"a": 1, "b": 2} cmdInput = { 'version': 0, 'withdrawalEpochLength': EPOCH_LENGTH, 'vFieldElementCertificateFieldConfig': bad_obj, 'toaddress': "abcd", 'amount': amount, 'fee': fee, 'wCertVk': vk } mark_logs( "\nNode 1 create SC with wrong vFieldElementCertificateFieldConfig obj in input (expecting failure...)", self.nodes, DEBUG_MODE) try: self.nodes[1].sc_create(cmdInput) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true("not an array" in errorString)
def run_test(self): ''' This test try creating a SC with sc_create using invalid parameters and valid parameters. It also checks the coin mature time of the FT ''' # network topology: (0)--(1)--(2) mark_logs("Node 1 generates 220 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(220) self.sync_all() creation_amount = Decimal("1.0") fwt_amount_1 = Decimal("2.0") fwt_amount_2 = Decimal("2.0") fwt_amount_3 = Decimal("3.0") fwt_amount_many = fwt_amount_1 + fwt_amount_2 + fwt_amount_3 #generate wCertVk and constant mcTest = MCTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() # --------------------------------------------------------------------------------------- # Node 2 try creating a SC with insufficient funds mark_logs("\nNode 2 try creating a SC with insufficient funds", self.nodes, DEBUG_MODE) amounts = [{"address": "dada", "amount": creation_amount}] errorString = "" try: self.nodes[2].sc_create(123, "dada", creation_amount, vk, "", constant) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, 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() mark_logs(("active chain height = %d: testing before sidechain fork" % self.nodes[0].getblockcount()), self.nodes, DEBUG_MODE) self.doTest() # reach the fork where certificates are supported self.nodes[0].generate(20) self.sync_all() mark_logs(("active chain height = %d: testing after sidechain fork" % self.nodes[0].getblockcount()), self.nodes, DEBUG_MODE) # create a sidechain and a certificate for it in the mempool mcTest = MCTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() creating_tx = self.nodes[1].sc_create(SC_EPOCH_LENGTH, "dada", SC_CREATION_AMOUNT, vk, "bb" * 1024, constant) self.sync_all() decoded_tx = self.nodes[1].getrawtransaction(creating_tx, 1) scid = decoded_tx['vsc_ccout'][0]['scid'] mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE) current_height = self.nodes[1].getblockcount() pebh = self.nodes[1].getblockhash(current_height) block_list = self.nodes[0].generate(SC_EPOCH_LENGTH) self.sync_all() pkh = self.nodes[0].getnewaddress("", True) amounts = [{"pubkeyhash": pkh, "amount": SC_CERT_AMOUNT}] #create wCert proof eph = block_list[-1] proof = mcTest.create_test_proof("sc1", 0, eph, pebh, 0, constant, [pkh], [SC_CERT_AMOUNT]) fee = 0.000023 cert = self.nodes[0].send_certificate(scid, 0, 0, block_list[-1], proof, amounts, fee) self.sync_all() assert_true(cert in self.nodes[0].getrawmempool()) # 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()) self.doTest() self.nodes[0].generate(1) self.sync_all()
def flood_mempool(): mark_logs("Creating many txes...", self.nodes, DEBUG_MODE) tot_num_tx = 0 tot_tx_sz = 0 taddr_node1 = self.nodes[0].getnewaddress() fee = Decimal('0.001') # there are a few coinbase utxo now matured listunspent = self.nodes[0].listunspent() print "num of utxo: ", len(listunspent) while True: if len(listunspent) <= tot_num_tx: # all utxo have been spent self.sync_all() break utxo = listunspent[tot_num_tx] change = utxo['amount'] - Decimal(fee) raw_inputs = [ {'txid' : utxo['txid'], 'vout' : utxo['vout']}] raw_outs = { taddr_node1: change } try: raw_tx = self.nodes[0].createrawtransaction(raw_inputs, raw_outs) signed_tx = self.nodes[0].signrawtransaction(raw_tx) tx = self.nodes[0].sendrawtransaction(signed_tx['hex']) except JSONRPCException, e: errorString = e.error['message'] print "Send raw tx failed with reason {}".format(errorString) assert(False) tot_num_tx += 1 hexTx = self.nodes[0].getrawtransaction(tx) sz = len(hexTx)//2 tot_tx_sz += sz if tot_tx_sz > 5*EPOCH_LENGTH*BLK_MAX_SZ: self.sync_all() break
def run_test(self): ''' This test try to create a SC using the command sc_create using invalid parameters and valid parameters. ''' #{"withdrawalEpochLength", "fromaddress", "toaddress", "amount", "minconf", "fee", "customData"}; # 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() tx = [] errorString = "" toaddress = "abcdef" #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params('sc1') constant = generate_random_field_element_hex() # create with wrong key in input #------------------------------------ amount = 12.0 fee = 0.000025 cmdInput = { 'version': 0, 'wrong_key': 123, 'toaddress': toaddress, 'amount': amount, 'fee': fee, 'wCertVk': vk } mark_logs("\nNode 1 create SC with wrong key in input", self.nodes, DEBUG_MODE) try: self.nodes[1].sc_create(cmdInput) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true("wrong_key" in errorString)
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): ''' 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)
errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true("amount" in errorString) # create with a missing mandatory key in input #------------------------------------------------ cmdInput = { 'version': 0, 'withdrawalEpochLength': 10, 'toaddress': toaddress, 'fee': fee, 'wCertVk': vk, 'customData': "bb" * 1024 } mark_logs("\nNode 1 create SC with duplicate key in input", self.nodes, DEBUG_MODE) try: self.nodes[1].sc_create(cmdInput) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true("amount" in errorString) # create with a bad value for amount #------------------------------------------------ cmdInput = { 'version': 0, 'withdrawalEpochLength': 10, 'toaddress': toaddress, 'amount': -0.1,
try: cert_epoch_1 = self.nodes[0].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, [], FT_SC_FEE, MBTR_SC_FEE, nullFee) mark_logs("Certificate is {}".format(cert_epoch_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) mark_logs( "Check the certificate for this scid has no vin and no vouts", self.nodes, DEBUG_MODE) decoded_cert_mempool = self.nodes[0].getrawtransaction(cert_epoch_1, 1) assert_equal(decoded_cert_mempool['cert']['scid'], scid) mark_logs("Node0 confims bwd transfer generating 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() # no more in mempool, only node with txindex=1 can decode it try: decoded_cert_notxindex = self.nodes[1].getrawtransaction( cert_epoch_1, 1) except JSONRPCException, e: errorString = e.error['message']
class sc_cert_getraw(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 = [] self.nodes = start_nodes( NUMB_OF_NODES, self.options.tmpdir, extra_args=[[ '-debug=py', '-debug=sc', '-debug=mempool', '-debug=net', '-debug=cert', '-debug=zendoo_mc_cryptolib', '-scproofqueuesize=0', '-logtimemicros=1' ], [ '-debug=py', '-debug=sc', '-debug=mempool', '-debug=net', '-debug=cert', '-debug=zendoo_mc_cryptolib', '-scproofqueuesize=0', '-logtimemicros=1' ], [ '-txindex=1', '-debug=py', '-debug=sc', '-debug=mempool', '-debug=net', '-debug=cert', '-debug=zendoo_mc_cryptolib', '-scproofqueuesize=0', '-logtimemicros=1' ]]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes[1:NUMB_OF_NODES]) sync_mempools(self.nodes[1:NUMB_OF_NODES]) self.is_network_split = split self.sync_all() 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) self.sync_all() decoded_cert_mempool = self.nodes[1].getrawtransaction(cert_epoch_0, 1) decoded_cert_mempool2 = self.nodes[1].getrawtransaction( cert_epoch_0, 1) assert_equal(decoded_cert_mempool, decoded_cert_mempool2) assert_equal(scid, decoded_cert_mempool['cert']['scid']) decoded_cert_mempool_hex = self.nodes[1].getrawtransaction( cert_epoch_0) decoded_cert_mempool_hex2 = self.nodes[1].getrawtransaction( cert_epoch_0) assert_equal(decoded_cert_mempool_hex, decoded_cert_mempool_hex2) dec = self.nodes[2].decoderawtransaction(decoded_cert_mempool_hex) assert_equal(cert_epoch_0, dec['txid']) assert_equal(scid, dec['cert']['scid']) dec2 = self.nodes[2].decoderawtransaction(decoded_cert_mempool_hex) assert_equal(dec2, dec) mark_logs("Node0 confims bwd transfer generating 1 block", self.nodes, DEBUG_MODE) mined = self.nodes[0].generate(1)[0] self.sync_all() decoded_cert_notxindex = self.nodes[1].getrawtransaction( cert_epoch_0, 1) assert_equal(decoded_cert_mempool['hex'], decoded_cert_notxindex['hex']) decoded_cert_txindex = self.nodes[2].getrawtransaction(cert_epoch_0, 1) assert_equal(decoded_cert_mempool['hex'], decoded_cert_txindex['hex']) mark_logs( "Node0 generating enough blocks to move to new withdrawal 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( "Generate new certificate for epoch {}. No bwt and no fee are included" .format(epoch_number), self.nodes, DEBUG_MODE) # Create new proof for WCert quality = 1 proof = mcTest.create_test_proof(vk_tag, scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [], []) nullFee = Decimal("0.0") try: cert_epoch_1 = self.nodes[0].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, [], FT_SC_FEE, MBTR_SC_FEE, nullFee) mark_logs("Certificate is {}".format(cert_epoch_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)
class sc_cert_base(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 = [] self.nodes = start_nodes( NUMB_OF_NODES, self.options.tmpdir, extra_args=[[ '-debug=py', '-debug=sc', '-debug=mempool', '-debug=net', '-debug=cert', '-debug=zendoo_mc_cryptolib', '-logtimemicros=1' ]] * NUMB_OF_NODES) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes[1:NUMB_OF_NODES]) sync_mempools(self.nodes[1:NUMB_OF_NODES]) self.is_network_split = split self.sync_all() def run_test(self): # 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) # 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 220 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(220) 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 = MCTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() creating_tx = self.nodes[1].sc_create(EPOCH_LENGTH, "dada", creation_amount, vk, "", constant) 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) 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)['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid)['immature amounts'][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) fwd_tx = self.nodes[0].sc_send("abcd", fwt_amount, scid) 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(8.75)) # 8.75 is matured coinbase assert_equal(self.nodes[0].getscinfo(scid)['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid)['immature amounts'][0]['amount'], creation_amount) assert_equal( self.nodes[0].getscinfo(scid)['immature amounts'][1]['amount'], fwt_amount) 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() assert_equal(self.nodes[0].getscinfo(scid)['balance'], creation_amount + fwt_amount) # Sc balance has matured assert_equal(len(self.nodes[0].getscinfo(scid)['immature amounts']), 0) current_height = self.nodes[0].getblockcount() epoch_number = (current_height - sc_creating_height + 1) // EPOCH_LENGTH - 1 mark_logs( "Current height {}, Sc creation height {}, epoch length {} --> current epoch number {}" .format(current_height, sc_creating_height, EPOCH_LENGTH, epoch_number), self.nodes, DEBUG_MODE) epoch_block_hash = self.nodes[0].getblockhash(sc_creating_height - 1 + ((epoch_number + 1) * EPOCH_LENGTH)) prev_epoch_block_hash = self.nodes[0].getblockhash(sc_creating_height - 1 + ((epoch_number) * EPOCH_LENGTH)) eph_wrong = self.nodes[0].getblockhash(sc_creating_height) print "epoch_number = ", epoch_number, ", epoch_block_hash = ", epoch_block_hash pkh_node1 = self.nodes[1].getnewaddress("", True) #Create proof for WCert quality = 0 proof = mcTest.create_test_proof("sc1", epoch_number, epoch_block_hash, prev_epoch_block_hash, quality, constant, [pkh_node1], [bwt_amount]) mark_logs( "Node 0 tries to perform a bwd transfer with insufficient Sc balance...", self.nodes, DEBUG_MODE) amounts = [{"pubkeyhash": pkh_node1, "amount": bwt_amount_bad}] try: self.nodes[0].send_certificate(scid, epoch_number, quality, epoch_block_hash, proof, amounts, CERT_FEE) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_equal("sidechain has insufficient funds" in errorString, True) assert_equal(self.nodes[0].getscinfo(scid)['balance'], creation_amount + fwt_amount) assert_equal(len(self.nodes[0].getscinfo(scid)['immature amounts']), 0) mark_logs( "Node 0 tries to perform a bwd transfer with an invalid epoch number ...", self.nodes, DEBUG_MODE) amount_cert_1 = [{"pubkeyhash": pkh_node1, "amount": bwt_amount}] try: self.nodes[0].send_certificate(scid, epoch_number + 1, quality, epoch_block_hash, proof, amount_cert_1, CERT_FEE) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE)
def run_test(self): # 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) # 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 220 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(220) 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 = MCTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() creating_tx = self.nodes[1].sc_create(EPOCH_LENGTH, "dada", creation_amount, vk, "", constant) 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) 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)['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid)['immature amounts'][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) fwd_tx = self.nodes[0].sc_send("abcd", fwt_amount, scid) 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(8.75)) # 8.75 is matured coinbase assert_equal(self.nodes[0].getscinfo(scid)['balance'], Decimal(0)) assert_equal( self.nodes[0].getscinfo(scid)['immature amounts'][0]['amount'], creation_amount) assert_equal( self.nodes[0].getscinfo(scid)['immature amounts'][1]['amount'], fwt_amount) 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() assert_equal(self.nodes[0].getscinfo(scid)['balance'], creation_amount + fwt_amount) # Sc balance has matured assert_equal(len(self.nodes[0].getscinfo(scid)['immature amounts']), 0) current_height = self.nodes[0].getblockcount() epoch_number = (current_height - sc_creating_height + 1) // EPOCH_LENGTH - 1 mark_logs( "Current height {}, Sc creation height {}, epoch length {} --> current epoch number {}" .format(current_height, sc_creating_height, EPOCH_LENGTH, epoch_number), self.nodes, DEBUG_MODE) epoch_block_hash = self.nodes[0].getblockhash(sc_creating_height - 1 + ((epoch_number + 1) * EPOCH_LENGTH)) prev_epoch_block_hash = self.nodes[0].getblockhash(sc_creating_height - 1 + ((epoch_number) * EPOCH_LENGTH)) eph_wrong = self.nodes[0].getblockhash(sc_creating_height) print "epoch_number = ", epoch_number, ", epoch_block_hash = ", epoch_block_hash pkh_node1 = self.nodes[1].getnewaddress("", True) #Create proof for WCert quality = 0 proof = mcTest.create_test_proof("sc1", epoch_number, epoch_block_hash, prev_epoch_block_hash, quality, constant, [pkh_node1], [bwt_amount]) mark_logs( "Node 0 tries to perform a bwd transfer with insufficient Sc balance...", self.nodes, DEBUG_MODE) amounts = [{"pubkeyhash": pkh_node1, "amount": bwt_amount_bad}] try: self.nodes[0].send_certificate(scid, epoch_number, quality, epoch_block_hash, proof, amounts, CERT_FEE) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE)
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): 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()
decoded_cert_pre = self.nodes[0].decoderawtransaction(raw_cert) decoded_cert_pre_list = sorted(decoded_cert_pre.items()) mark_logs( "Node0 sending raw certificate for epoch {}, expecting failure...". format(epoch_number), self.nodes, DEBUG_MODE) # we expect it to fail because beyond the safeguard try: cert = self.nodes[0].sendrawtransaction(signed_cert['hex']) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] print "======> ", errorString, "\n" mark_logs( "Node0 invalidates last block, thus shortening the chain by one and returning in the safe margin", self.nodes, DEBUG_MODE) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) sync_mempools(self.nodes[1:3]) mark_logs( "Node0 sending raw certificate for epoch {}, expecting success". format(epoch_number), self.nodes, DEBUG_MODE) try: cert = self.nodes[0].sendrawtransaction(signed_cert['hex']) except JSONRPCException, e: errorString = e.error['message'] print "\n======> ", errorString assert_true(False) decoded_cert_pre = self.nodes[0].decoderawtransaction(
class sc_rawcert(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 = [] self.nodes = start_nodes( NUMB_OF_NODES, self.options.tmpdir, extra_args=[[ '-debug=py', '-debug=sc', '-debug=mempool', '-debug=net', '-debug=cert', '-scproofqueuesize=0', '-logtimemicros=1', '-txindex=1', '-zapwallettxes=2' ]] * NUMB_OF_NODES) for idx, _ in enumerate(self.nodes): if idx < (NUMB_OF_NODES - 1): connect_nodes_bi(self.nodes, idx, idx + 1) sync_blocks(self.nodes[1:NUMB_OF_NODES]) sync_mempools(self.nodes[1:NUMB_OF_NODES]) self.is_network_split = split self.sync_all() 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) decoded_cert_pre = self.nodes[0].decoderawtransaction(raw_cert) decoded_cert_pre_list = sorted(decoded_cert_pre.items()) mark_logs( "Node0 sending raw certificate for epoch {}, expecting failure...". format(epoch_number), self.nodes, DEBUG_MODE) # we expect it to fail because beyond the safeguard try: cert = self.nodes[0].sendrawtransaction(signed_cert['hex']) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] print "======> ", errorString, "\n"
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)
class CertMempoolCleanupSplit(BitcoinTestFramework): def setup_chain(self): print("Initializing test directory " + self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES) def setup_network(self, split=False): self.nodes = start_nodes( NUMB_OF_NODES, self.options.tmpdir, extra_args=[[ '-logtimemicros=1', '-scproofqueuesize=0', '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net', '-debug=bench' ]] * NUMB_OF_NODES) if not split: # 2 and 3 are joint only if split==false connect_nodes_bi(self.nodes, 2, 3) sync_blocks(self.nodes[2:4]) sync_mempools(self.nodes[2:4]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) self.is_network_split = split self.sync_all() def split_network(self): # Split the network of three nodes into nodes 0-1-2 and 3. assert not self.is_network_split disconnect_nodes(self.nodes[2], 3) disconnect_nodes(self.nodes[3], 2) self.is_network_split = True def join_network(self): # Join the (previously split) network pieces together: 0-1-2-3 assert self.is_network_split connect_nodes_bi(self.nodes, 2, 3) connect_nodes_bi(self.nodes, 3, 2) time.sleep(2) self.is_network_split = False def run_test(self): ''' Create a SC, advance two epochs, move to the limit of the safe guard and then split the network. One network part sends 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) sync_mempools(self.nodes[0:3]) mark_logs(" Check bwd tx {} is in mempool".format(tx_bwt), self.nodes, DEBUG_MODE) assert_true(tx_bwt in self.nodes[0].getrawmempool()) mark_logs("\nNTW part 1) Node2 sends a certificate", self.nodes, DEBUG_MODE) epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[2], sc_epoch_len) bt_amount = Decimal("5.0") addr_node1 = self.nodes[1].getnewaddress() quality = 10 proof = certMcTest.create_test_proof("sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node1], [bt_amount]) amount_cert = [{"address": addr_node1, "amount": bt_amount}] try: cert_bad = self.nodes[2].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, amount_cert, 0, 0, 0.01) except JSONRPCException, e: errorString = e.error['message'] print "Send certificate failed with reason {}".format(errorString) assert (False)
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)
class SCCreateTest(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=[[ "-sccoinsmaturity=%d" % SC_COINS_MAT, '-logtimemicros=1', '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net', '-debug=bench' ]] * NUMB_OF_NODES) connect_nodes_bi(self.nodes, 0, 1) self.is_network_split = split self.sync_all() def run_test(self): ''' This test try to create a SC using the command sc_create using invalid parameters and valid parameters. ''' #{"withdrawalEpochLength", "fromaddress", "toaddress", "amount", "minconf", "fee", "customData"}; # 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() tx = [] errorString = "" toaddress = "abcdef" #generate wCertVk and constant mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params('sc1') constant = generate_random_field_element_hex() # create with wrong key in input #------------------------------------ amount = 12.0 fee = 0.000025 cmdInput = { 'version': 0, 'wrong_key': 123, 'toaddress': toaddress, 'amount': amount, 'fee': fee, 'wCertVk': vk } mark_logs("\nNode 1 create SC with wrong key in input", self.nodes, DEBUG_MODE) try: self.nodes[1].sc_create(cmdInput) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true("wrong_key" in errorString) # create with duplicate key in input #------------------------------------ cmdInput = FakeDict([('version', 0), ('fee', fee), ('amount', amount), ('amount', 6.0), ('toaddress', str(toaddress)), ('wCertVk', vk)]) mark_logs("\nNode 1 create SC with duplicate key in input", self.nodes, DEBUG_MODE) try: self.nodes[1].sc_create(cmdInput) assert_true(False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_true("amount" in errorString)
self.nodes[0].send_certificate(scid, epoch_number + 1, quality, epoch_block_hash, proof, amount_cert_1, CERT_FEE) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_equal("invalid epoch data" in errorString, True) assert_equal( self.nodes[0].getscinfo(scid)['balance'], creation_amount + fwt_amount) # Sc has not been affected by faulty certificate assert_equal(len(self.nodes[0].getscinfo(scid)['immature amounts']), 0) mark_logs( "Node 0 tries to perform a bwd transfer with an invalid quality ...", self.nodes, DEBUG_MODE) try: self.nodes[0].send_certificate(scid, epoch_number, quality - 1, epoch_block_hash, proof, amount_cert_1, CERT_FEE) assert (False) except JSONRPCException, e: errorString = e.error['message'] mark_logs(errorString, self.nodes, DEBUG_MODE) assert_equal("Invalid quality parameter" in errorString, True) assert_equal( self.nodes[0].getscinfo(scid)['balance'], creation_amount + fwt_amount) # Sc has not been affected by faulty certificate
quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [addr_node1], [bt_amount]) amount_cert = [{"address": addr_node1, "amount": bt_amount}] try: cert_bad = self.nodes[2].sc_send_certificate( scid, epoch_number, quality, epoch_cum_tree_hash, proof, amount_cert, 0, 0, 0.01) except JSONRPCException, e: errorString = e.error['message'] print "Send certificate failed with reason {}".format(errorString) assert (False) sync_mempools(self.nodes[0:3]) mark_logs(" Check cert {} is in mempool".format(cert_bad), self.nodes, DEBUG_MODE) assert_true(cert_bad in self.nodes[0].getrawmempool()) print "Node0 Chain h = ", self.nodes[0].getblockcount() # Network part 2 #------------------ mark_logs("\nNTW part 2) Node3 sends a certificate", self.nodes, DEBUG_MODE) epoch_number, epoch_cum_tree_hash = get_epoch_data( scid, self.nodes[3], sc_epoch_len) bt_amount_2 = Decimal("10.0") addr_node1 = self.nodes[1].getnewaddress() quality = 5 proof = certMcTest.create_test_proof("sc1", scid_swapped, epoch_number,
def doTest(self, sc_fork_reached): node = self.nodes[0] tmpl = node.getblocktemplate() if 'coinbasetxn' not in tmpl: rawcoinbase = encodeUNum(tmpl['height']) rawcoinbase += b'\x01-' hexcoinbase = b2x(rawcoinbase) hexoutval = b2x(pack('<Q', tmpl['coinbasevalue'])) tmpl['coinbasetxn'] = { 'data': '01000000' + '01' + '0000000000000000000000000000000000000000000000000000000000000000ffffffff' + ('%02x' % (len(rawcoinbase), )) + hexcoinbase + 'fffffffe' + '01' + hexoutval + '00' + '00000000' } txlist = list( bytearray(a2b_hex(a['data'])) for a in (tmpl['coinbasetxn'], ) + tuple(tmpl['transactions'])) certlist = [] # if the block supports certificates, add them (if any) if tmpl['version'] == SC_CERTIFICATE_BLOCK_VERSION: assert_true(sc_fork_reached) certlist = list( bytearray(a2b_hex(a['data'])) for a in tuple(tmpl['certificates'])) # Test 0: Capability advertised assert ('proposal' in tmpl['capabilities']) # NOTE: This test currently FAILS (regtest mode doesn't enforce block height in coinbase) ## Test 1: Bad height in coinbase #txlist[0][4+1+36+1+1] += 1 #assert_template(node, tmpl, txlist, 'FIXME') #txlist[0][4+1+36+1+1] -= 1 # Test 2: Bad input hash for gen tx txlist[0][4 + 1] += 1 assert_template(node, tmpl, txlist, certlist, 'bad-cb-missing') txlist[0][4 + 1] -= 1 # Test 3: Truncated final tx lastbyte = txlist[-1].pop() try: assert_template(node, tmpl, txlist, certlist, 'n/a') except JSONRPCException: pass # Expected txlist[-1].append(lastbyte) # Check for merkle tree malleability (CVE-2012-2459): repeating sequences # of transactions (or certificates) in a block without affecting the merkle root, # while still invalidating it. if len(certlist) == 0: # Test 4: Add an invalid tx to the end (duplicate of gen tx) txlist.append(txlist[0]) assert_template(node, tmpl, txlist, certlist, 'bad-txns-duplicate') txlist.pop() else: # Test 4: Add an invalid cert to the end (duplicate of cert) certlist.append(certlist[0]) assert_template(node, tmpl, txlist, certlist, 'bad-txns-duplicate') certlist.pop() # Test 5: Add an invalid tx to the end (non-duplicate) txlist.append(bytearray(txlist[0])) txlist[-1][4 + 1] = b'\xff' #! This transaction is failing sooner than intended in the #! test because of the lack of an op-checkblockheight #assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent') assert_template(node, tmpl, txlist, certlist, 'op-checkblockatheight-needed') txlist.pop() # Test 6: Future tx lock time txlist[0][ 49] -= 1 # in template nSequence is equal 0xffffffff, in such case it disables nLockTime. Decrease nSequence to enable lock time check. txlist[0][-4:] = b'\xff\xff\xff\xff' # set nLockTime far in future assert_template(node, tmpl, txlist, certlist, 'bad-txns-nonfinal') txlist[0][-4:] = b'\0\0\0\0' # Test 7: Bad tx count txlist.append(b'') try: assert_template(node, tmpl, txlist, certlist, 'n/a') except JSONRPCException: pass # Expected txlist.pop() # Test 8: Bad bits realbits = tmpl['bits'] tmpl['bits'] = '1c0000ff' # impossible in the real world assert_template(node, tmpl, txlist, certlist, 'bad-diffbits') tmpl['bits'] = realbits # Test 9: Bad merkle root rawtmpl = template_to_bytes(tmpl, txlist, certlist) rawtmpl[4 + 32] = (rawtmpl[4 + 32] + 1) % 0x100 rsp = node.getblocktemplate({'data': b2x(rawtmpl), 'mode': 'proposal'}) if rsp != 'bad-txnmrklroot': raise AssertionError('unexpected: %s' % (rsp, )) # Test 10: Bad timestamps realtime = tmpl['curtime'] tmpl['curtime'] = 0x7fffffff if sc_fork_reached == False: assert_template(node, tmpl, txlist, certlist, 'time-too-new') else: # if we reached sc fork we also have passed timeblock fork and the error changes assert_template(node, tmpl, txlist, certlist, 'time-too-far-ahead-of-mtp') tmpl['curtime'] = 0 assert_template(node, tmpl, txlist, certlist, 'time-too-old') tmpl['curtime'] = realtime if sc_fork_reached == False: # Test 11: Valid block assert_template(node, tmpl, txlist, certlist, None) else: assert_true(len(certlist) != 0) # compute commitment for the only contribution of certificate (we have no sctx/btr) ''' TODO - this test is commented out since in this branch the sc commitment tree is computed in a different way in mainchain and it would trigger an error ----- TxsHash = dblsha(SC_NULL_HASH + SC_NULL_HASH) WCertHash = dblsha(certlist[0]) scid = certlist[0][4:4+32] SCHash = dblsha(TxsHash + WCertHash + scid) assert_template(node, tmpl, txlist, certlist, None, SCHash) ''' # Test 12: Orphan block orig_val = tmpl['previousblockhash'] tmpl['previousblockhash'] = 'ff00' * 16 assert_template(node, tmpl, txlist, certlist, 'inconclusive-not-best-prevblk') tmpl['previousblockhash'] = orig_val if sc_fork_reached == True: assert_true(len(certlist) != 0) # cert only specific tests # Test 13: Bad cert count mark_logs("Bad cert count (expecting failure...)", NODE_LIST, DEBUG_MODE) certlist.append(b'') try: assert_template(node, tmpl, txlist, certlist, 'n/a') except JSONRPCException: pass # Expected certlist.pop() # Test 14: Truncated final cert mark_logs("Truncated final cert (expecting failure...)", NODE_LIST, DEBUG_MODE) lastbyte = certlist[-1].pop() try: assert_template(node, tmpl, txlist, certlist, 'n/a') except JSONRPCException: pass # Expected certlist[-1].append(lastbyte) # Test 15: invalid field element as a commitment tree fake_commitment = (b'\xff' * 32) fake_commitment_str = binascii.hexlify(fake_commitment) assert_template(node, tmpl, txlist, certlist, 'invalid-sc-txs-commitment', fake_commitment) # Test 16: wrong commitment, the block will be rejected because it is different from the one computed using tx/certs rnd_fe = generate_random_field_element_hex() fake_commitment = a2b_hex(rnd_fe) assert_template(node, tmpl, txlist, certlist, 'bad-sc-txs-commitment', fake_commitment)