def test_getTransactionReceipt_not_exist(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): for endpoint in ("getTransactionReceipt", "eth_getTransactionReceipt"): resp = send_request(endpoint, ["0x" + bytes(36).hex()]) self.assertIsNone(resp)
def test_estimateGas(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext(1, acc1) as clusters, jrpc_server_context( clusters[0].master): response = send_request("estimateGas", [{ "to": "0x" + acc1.serialize().hex() }]) self.assertEqual(response, "0x5208") # 21000
def test_getTransactionReceipt_on_x_shard_transfer(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) acc2 = Address.create_from_identity(id1, full_shard_id=1) with ClusterContext(1, acc1) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list is_root, block = call_async( master.get_next_block_to_mine(address=acc2)) self.assertTrue(is_root) call_async(master.add_root_block(block)) s1, s2 = clusters[0].get_shard_state( 0), clusters[0].get_shard_state(1) tx_gen = lambda s, f, t: create_transfer_transaction( shard_state=s, key=id1.get_key(), from_address=f, to_address=t, gas=21000 if f == t else 30000, value=12345, ) self.assertTrue(slaves[0].add_tx(tx_gen(s1, acc1, acc2))) _, b1 = call_async(master.get_next_block_to_mine(address=acc1)) self.assertTrue(call_async(clusters[0].get_shard(0).add_block(b1))) _, b2 = call_async(master.get_next_block_to_mine(address=acc2)) self.assertTrue(call_async(clusters[0].get_shard(1).add_block(b2))) _, root_block = call_async( master.get_next_block_to_mine(address=acc1, prefer_root=True)) call_async(master.add_root_block(root_block)) tx = tx_gen(s2, acc2, acc2) self.assertTrue(slaves[1].add_tx(tx)) _, b3 = call_async(master.get_next_block_to_mine(address=acc2)) self.assertTrue(call_async(clusters[0].get_shard(1).add_block(b3))) # in-shard tx 21000 + receiving x-shard tx 9000 self.assertEqual(s2.evm_state.gas_used, 30000) self.assertEqual(s2.evm_state.xshard_receive_gas_used, 9000) resp = send_request( "getTransactionReceipt", "0x" + tx.get_hash().hex() + acc2.full_shard_id.to_bytes(4, "big").hex(), ) self.assertEqual(resp["transactionHash"], "0x" + tx.get_hash().hex()) self.assertEqual(resp["status"], "0x1") self.assertEqual(resp["cumulativeGasUsed"], hex(30000)) self.assertEqual(resp["gasUsed"], hex(21000)) self.assertIsNone(resp["contractAddress"])
def test_getWork_and_submitWork(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext( 1, acc1, remote_mining=True, shard_size=1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list branch = Branch.create(1, 0) tx = create_transfer_transaction( shard_state=slaves[0].shards[branch].state, key=id1.get_key(), from_address=acc1, to_address=acc1, value=0, gas_price=12, ) self.assertTrue(slaves[0].add_tx(tx)) for shard_id in ["0x0", None]: # shard, then root resp = send_request("getWork", shard_id) self.assertEqual(resp[1:], ["0x1", "0xa"]) # height and diff header_hash_hex = resp[0] if shard_id is not None: # shard 0 miner_address = Address.create_from( master.env.quark_chain_config.SHARD_LIST[0]. COINBASE_ADDRESS) else: # root miner_address = Address.create_from( master.env.quark_chain_config.ROOT.COINBASE_ADDRESS) _, block = call_async( master.get_next_block_to_mine( address=miner_address, prefer_root=shard_id is None)) self.assertEqual(header_hash_hex[2:], block.header.get_hash_for_mining().hex()) # solve it and submit work = MiningWork(bytes.fromhex(resp[0][2:]), 1, 10) solver = DoubleSHA256(work) nonce = solver.mine(0, 10000).nonce mixhash = "0x" + sha3_256(b"").hex() resp = send_request("submitWork", shard_id, header_hash_hex, hex(nonce), mixhash) self.assertTrue(resp) # show progress on shard 0 _, new_block = call_async( master.get_next_block_to_mine(address=acc1)) self.assertIsInstance(new_block, MinorBlock) self.assertEqual(new_block.header.height, 2)
def test_sendTransaction(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_random_account(full_shard_key=1) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): slaves = clusters[0].slave_list master = clusters[0].master block = call_async( master.get_next_block_to_mine(address=acc2, branch_value=None)) call_async(master.add_root_block(block)) evm_tx = EvmTransaction( nonce=0, gasprice=6, startgas=30000, to=acc2.recipient, value=15, data=b"", from_full_shard_key=acc1.full_shard_key, to_full_shard_key=acc2.full_shard_key, network_id=slaves[0].env.quark_chain_config.NETWORK_ID, gas_token_id=master.env.quark_chain_config.genesis_token, transfer_token_id=master.env.quark_chain_config.genesis_token, ) evm_tx.sign(id1.get_key()) request = dict( to="0x" + acc2.recipient.hex(), gasPrice="0x6", gas=hex(30000), value="0xf", # 15 v=quantity_encoder(evm_tx.v), r=quantity_encoder(evm_tx.r), s=quantity_encoder(evm_tx.s), nonce="0x0", fromFullShardKey="0x00000000", toFullShardKey="0x00000001", network_id=hex(slaves[0].env.quark_chain_config.NETWORK_ID), ) tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx)) response = send_request("sendTransaction", [request]) self.assertEqual(response, "0x" + tx.get_hash().hex() + "00000000") state = clusters[0].get_shard_state(2 | 0) self.assertEqual(len(state.tx_queue), 1) self.assertEqual( state.tx_queue.pop_transaction(state.get_transaction_count), evm_tx)
def test_getTransactionCount(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_random_account(full_shard_key=1) with ClusterContext( 1, acc1, small_coinbase=True ) as clusters, jrpc_server_context(clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list self.assertEqual( call_async(master.get_primary_account_data(acc1)).transaction_count, 0 ) for i in range(3): tx = create_transfer_transaction( shard_state=clusters[0].get_shard_state(2 | 0), key=id1.get_key(), from_address=acc1, to_address=acc1, value=12345, ) self.assertTrue(slaves[0].add_tx(tx)) block = call_async( master.get_next_block_to_mine(address=acc1, branch_value=0b10) ) self.assertEqual(i + 1, block.header.height) self.assertTrue( call_async(clusters[0].get_shard(2 | 0).add_block(block)) ) response = send_request( "getTransactionCount", "0x" + acc2.serialize().hex() ) self.assertEqual(response, "0x0") response = send_request( "getTransactionCount", "0x" + acc1.serialize().hex() ) self.assertEqual(response, "0x3") response = send_request( "getTransactionCount", "0x" + acc1.serialize().hex(), "latest" ) self.assertEqual(response, "0x3") for i in range(3): response = send_request( "getTransactionCount", "0x" + acc1.serialize().hex(), hex(i + 1) ) self.assertEqual(response, hex(i + 1))
def test_add_minor_block_request_list(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext(2, acc1) as clusters: shard_state = clusters[0].slave_list[0].shards[Branch(0b10)].state coinbase_amount = ( shard_state.env.quark_chain_config.SHARD_LIST[ shard_state.shard_id ].COINBASE_AMOUNT // 2 ) b1 = shard_state.get_tip().create_block_to_append() evm_state = shard_state.run_block(b1) b1.finalize( evm_state=evm_state, coinbase_amount=evm_state.block_fee + coinbase_amount, ) add_result = call_async( clusters[0].master.add_raw_minor_block(b1.header.branch, b1.serialize()) ) self.assertTrue(add_result) # Make sure the xshard list is not broadcasted to the other shard self.assertFalse( clusters[0] .slave_list[1] .shards[Branch(0b11)] .state.contain_remote_minor_block_hash(b1.header.get_hash()) ) self.assertTrue( clusters[0].master.root_state.is_minor_block_validated( b1.header.get_hash() ) ) # Make sure another cluster received the new block assert_true_with_timeout( lambda: clusters[1] .slave_list[0] .shards[Branch(0b10)] .state.contain_block_by_hash(b1.header.get_hash()) ) assert_true_with_timeout( lambda: clusters[1].master.root_state.is_minor_block_validated( b1.header.get_hash() ) )
def test_shard_genesis_fork_fork(self): """ Test shard forks at genesis blocks due to root chain fork at GENESIS.ROOT_HEIGHT""" acc1 = Address.create_random_account(0) acc2 = Address.create_random_account(1) with ClusterContext(2, acc1, genesis_root_heights=[0, 1]) as clusters: # shutdown cluster connection clusters[1].peer.close() master0 = clusters[0].master is_root, root0 = call_async(master0.get_next_block_to_mine(acc1)) self.assertTrue(is_root) call_async(master0.add_root_block(root0)) genesis0 = (clusters[0].get_shard_state( 2 | 1).db.get_minor_block_by_height(0)) self.assertEqual(genesis0.header.hash_prev_root_block, root0.header.get_hash()) master1 = clusters[1].master is_root, root1 = call_async(master1.get_next_block_to_mine(acc2)) self.assertTrue(is_root) self.assertNotEqual(root0.header.get_hash(), root1.header.get_hash()) call_async(master1.add_root_block(root1)) genesis1 = (clusters[1].get_shard_state( 2 | 1).db.get_minor_block_by_height(0)) self.assertEqual(genesis1.header.hash_prev_root_block, root1.header.get_hash()) # let's make cluster1's root chain longer than cluster0's is_root, root2 = call_async(master1.get_next_block_to_mine(acc2)) self.assertTrue(is_root) call_async(master1.add_root_block(root2)) self.assertEqual(master1.root_state.tip.height, 2) # reestablish cluster connection call_async(clusters[1].network.connect( "127.0.0.1", clusters[0].master.env.cluster_config.SIMPLE_NETWORK. BOOTSTRAP_PORT, )) # Expect cluster0's genesis change to genesis1 assert_true_with_timeout(lambda: clusters[0].get_shard_state( 2 | 1).db.get_minor_block_by_height(0).header.get_hash() == genesis1.header.get_hash()) self.assertTrue( clusters[0].get_shard_state(2 | 1).root_tip == root2.header)
def test_get_work_from_slave(self): genesis = Address.create_empty_account(full_shard_key=0) with ClusterContext(1, genesis, remote_mining=True) as clusters: slaves = clusters[0].slave_list # no posw state = clusters[0].get_shard_state(2 | 0) branch = state.create_block_to_mine().header.branch work = call_async(slaves[0].get_work(branch)) self.assertEqual(work.difficulty, 10) # enable posw, with total stakes equal genesis balance state.shard_config.POSW_CONFIG.ENABLED = True state.shard_config.POSW_CONFIG.TOTAL_STAKE_PER_BLOCK = 1000000 work = call_async(slaves[0].get_work(branch)) self.assertEqual(work.difficulty, 0)
def test_sendTransaction(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) acc2 = Address.create_random_account(full_shard_id=1) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): slaves = clusters[0].slave_list branch = Branch.create(2, 0) evm_tx = EvmTransaction( nonce=0, gasprice=6, startgas=30000, to=acc2.recipient, value=15, data=b"", from_full_shard_id=acc1.full_shard_id, to_full_shard_id=acc2.full_shard_id, network_id=slaves[0].env.quark_chain_config.NETWORK_ID, ) evm_tx.sign(id1.get_key()) request = dict( to="0x" + acc2.recipient.hex(), gasPrice="0x6", gas=hex(30000), value="0xf", # 15 v=quantity_encoder(evm_tx.v), r=quantity_encoder(evm_tx.r), s=quantity_encoder(evm_tx.s), nonce="0x0", fromFullShardId="0x00000000", toFullShardId="0x00000001", network_id=hex(slaves[0].env.quark_chain_config.NETWORK_ID), ) tx = Transaction(code=Code.create_evm_code(evm_tx)) response = send_request("sendTransaction", [request]) self.assertEqual(response, "0x" + tx.get_hash().hex() + "00000000") self.assertEqual(len(slaves[0].shards[branch].state.tx_queue), 1) self.assertEqual( slaves[0].shards[branch].state.tx_queue.pop_transaction(), evm_tx)
def test_get_primary_account_data(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_random_account(full_shard_key=1) with ClusterContext(1, acc1) as clusters: master = clusters[0].master slaves = clusters[0].slave_list branch = Branch(2) self.assertEqual( call_async( master.get_primary_account_data(acc1)).transaction_count, 0) tx = create_transfer_transaction( shard_state=slaves[0].shards[branch].state, key=id1.get_key(), from_address=acc1, to_address=acc1, value=12345, ) self.assertTrue(slaves[0].add_tx(tx)) is_root, root = call_async( master.get_next_block_to_mine(address=acc1, prefer_root=True)) self.assertTrue(is_root) call_async(master.add_root_block(root)) is_root, block1 = call_async( master.get_next_block_to_mine(address=acc1)) self.assertFalse(is_root) self.assertTrue( call_async( master.add_raw_minor_block(block1.header.branch, block1.serialize()))) self.assertEqual( call_async( master.get_primary_account_data(acc1)).transaction_count, 1) self.assertEqual( call_async( master.get_primary_account_data(acc2)).transaction_count, 0)
def test_add_transaction(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_from_identity(id1, full_shard_key=1) with ClusterContext(2, acc1) as clusters: master = clusters[0].master root = call_async( master.get_next_block_to_mine(acc1, branch_value=None)) call_async(master.add_root_block(root)) tx1 = create_transfer_transaction( shard_state=clusters[0].get_shard_state(0b10), key=id1.get_key(), from_address=acc1, to_address=acc1, value=12345, ) self.assertTrue(call_async(master.add_transaction(tx1))) self.assertEqual(len(clusters[0].get_shard_state(0b10).tx_queue), 1) branch1 = Branch(2 | 1) tx2 = create_transfer_transaction( shard_state=clusters[0].get_shard_state(0b11), key=id1.get_key(), from_address=acc2, to_address=acc1, value=12345, gas=30000, ) self.assertTrue(call_async(master.add_transaction(tx2))) self.assertEqual(len(clusters[0].get_shard_state(0b11).tx_queue), 1) # check the tx is received by the other cluster tx_queue = clusters[1].get_shard_state(0b10).tx_queue assert_true_with_timeout(lambda: len(tx_queue) == 1) self.assertEqual(tx_queue.pop_transaction(), tx1.tx.to_evm_tx()) tx_queue = clusters[1].get_shard_state(0b11).tx_queue assert_true_with_timeout(lambda: len(tx_queue) == 1) self.assertEqual(tx_queue.pop_transaction(), tx2.tx.to_evm_tx())
def test_call_success(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext( 1, acc1, small_coinbase=True ) as clusters, jrpc_server_context(clusters[0].master): slaves = clusters[0].slave_list response = send_request( "call", [{"to": "0x" + acc1.serialize().hex(), "gas": hex(21000)}] ) self.assertEqual(response, "0x") self.assertEqual( len(clusters[0].get_shard_state(2 | 0).tx_queue), 0, "should not affect tx queue", )
def test_getNextBlockToMine_with_shard_mask(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext(1, acc1) as clusters, jrpc_server_context( clusters[0].master): response = send_request("getNextBlockToMine", "0x" + acc1.serialize().hex(), "0x2") self.assertFalse(response["isRootBlock"]) block1 = MinorBlock.deserialize( bytes.fromhex(response["blockData"][2:])) self.assertEqual(block1.header.branch.value, 0b10) response = send_request("getNextBlockToMine", "0x" + acc1.serialize().hex(), "0x3") self.assertFalse(response["isRootBlock"]) block1 = MinorBlock.deserialize( bytes.fromhex(response["blockData"][2:])) self.assertEqual(block1.header.branch.value, 0b11)
def test_sendTransaction_missing_from_full_shard_id(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext(1, acc1) as clusters, jrpc_server_context( clusters[0].master): request = dict( to="0x" + acc1.recipient.hex(), gasPrice="0x6", gas=hex(30000), value="0xf", v="0x1", r="0x2", s="0x3", nonce="0x0", ) with self.assertRaises(Exception): send_request("sendTransaction", request)
def test_getTransactionReceipt_on_contract_creation_failure(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list # Add a root block to update block gas limit for xshard tx throttling # so that the following tx can be processed is_root, root_block = call_async( master.get_next_block_to_mine(acc1)) self.assertTrue(is_root) call_async(master.add_root_block(root_block)) branch = Branch.create(2, 0) to_full_shard_id = (acc1.full_shard_id + 1 ) # x-shard contract creation should fail tx = create_contract_creation_transaction( shard_state=slaves[0].shards[branch].state, key=id1.get_key(), from_address=acc1, to_full_shard_id=to_full_shard_id, ) self.assertTrue(slaves[0].add_tx(tx)) _, block1 = call_async(master.get_next_block_to_mine(address=acc1)) self.assertTrue( call_async(clusters[0].get_shard(0).add_block(block1))) for endpoint in ("getTransactionReceipt", "eth_getTransactionReceipt"): resp = send_request( endpoint, "0x" + tx.get_hash().hex() + branch.serialize().hex()) self.assertEqual(resp["transactionHash"], "0x" + tx.get_hash().hex()) self.assertEqual(resp["status"], "0x0") self.assertEqual(resp["cumulativeGasUsed"], "0x13d6c") self.assertIsNone(resp["contractAddress"])
def test_add_transaction(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_from_identity(id1, full_shard_key=1) with ClusterContext(2, acc1) as clusters: master = clusters[0].master slaves = clusters[0].slave_list branch0 = Branch(2) tx1 = create_transfer_transaction( shard_state=slaves[0].shards[branch0].state, key=id1.get_key(), from_address=acc1, to_address=acc1, value=12345, ) self.assertTrue(call_async(master.add_transaction(tx1))) self.assertEqual(len(slaves[0].shards[branch0].state.tx_queue), 1) branch1 = Branch(2 | 1) tx2 = create_transfer_transaction( shard_state=slaves[1].shards[branch1].state, key=id1.get_key(), from_address=acc2, to_address=acc1, value=12345, gas=30000, ) self.assertTrue(call_async(master.add_transaction(tx2))) self.assertEqual(len(slaves[1].shards[branch1].state.tx_queue), 1) # check the tx is received by the other cluster tx_queue = clusters[1].slave_list[0].shards[branch0].state.tx_queue assert_true_with_timeout(lambda: len(tx_queue) == 1) self.assertEqual(tx_queue.pop_transaction(), tx1.code.get_evm_transaction()) tx_queue = clusters[1].slave_list[1].shards[branch1].state.tx_queue assert_true_with_timeout(lambda: len(tx_queue) == 1) self.assertEqual(tx_queue.pop_transaction(), tx2.code.get_evm_transaction())
def test_broadcast_cross_shard_transactions_to_neighbor_only(self): """ Test the broadcast is only done to the neighbors """ id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) # create 64 shards so that the neighbor rule can kick in # explicitly set num_slaves to 4 so that it does not spin up 64 slaves with ClusterContext(1, acc1, 64, num_slaves=4) as clusters: master = clusters[0].master slaves = clusters[0].slave_list # Add a root block first so that later minor blocks referring to this root # can be broadcasted to other shards is_root, root_block = call_async( master.get_next_block_to_mine( Address.create_empty_account(), prefer_root=True ) ) self.assertTrue(is_root) call_async(master.add_root_block(root_block)) b1 = ( slaves[0] .shards[Branch(64 | 0)] .state.create_block_to_mine(address=acc1) ) self.assertTrue( call_async(master.add_raw_minor_block(b1.header.branch, b1.serialize())) ) neighbor_shards = [2 ** i for i in range(6)] for shard_id in range(64): xshard_tx_list = ( clusters[0] .get_shard_state(shard_id) .db.get_minor_block_xshard_tx_list(b1.header.get_hash()) ) # Only neighbor should have it if shard_id in neighbor_shards: self.assertIsNotNone(xshard_tx_list) else: self.assertIsNone(xshard_tx_list)
def test_call_success_default_gas(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext(1, acc1) as clusters, jrpc_server_context( clusters[0].master): slaves = clusters[0].slave_list branch = Branch.create(2, 0) # gas is not specified in the request response = send_request("call", {"to": "0x" + acc1.serialize().hex()}, "latest") self.assertEqual(response, "0x") self.assertEqual( len(slaves[0].shards[branch].state.tx_queue), 0, "should not affect tx queue", )
def test_call_failure(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext( 1, acc1, small_coinbase=True ) as clusters, jrpc_server_context(clusters[0].master): slaves = clusters[0].slave_list # insufficient gas response = send_request( "call", {"to": "0x" + acc1.serialize().hex(), "gas": "0x1"}, None ) self.assertIsNone(response, "failed tx should return None") self.assertEqual( len(clusters[0].get_shard_state(2 | 0).tx_queue), 0, "should not affect tx queue", )
def test_getTransactionReceipt_on_contract_creation(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list branch = Branch.create(2, 0) to_full_shard_id = acc1.full_shard_id + 2 tx = create_contract_creation_transaction( shard_state=slaves[0].shards[branch].state, key=id1.get_key(), from_address=acc1, to_full_shard_id=to_full_shard_id, ) self.assertTrue(slaves[0].add_tx(tx)) _, block1 = call_async(master.get_next_block_to_mine(address=acc1)) self.assertTrue( call_async(clusters[0].get_shard(0).add_block(block1))) for endpoint in ("getTransactionReceipt", "eth_getTransactionReceipt"): resp = send_request( endpoint, "0x" + tx.get_hash().hex() + branch.serialize().hex()) self.assertEqual(resp["transactionHash"], "0x" + tx.get_hash().hex()) self.assertEqual(resp["status"], "0x1") self.assertEqual(resp["cumulativeGasUsed"], "0x213eb") contract_address = mk_contract_address(acc1.recipient, to_full_shard_id, 0) self.assertEqual( resp["contractAddress"], "0x" + contract_address.hex() + to_full_shard_id.to_bytes(4, "big").hex(), )
def test_getWork_and_submitWork(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) with ClusterContext(1, acc1, remote_mining=True, shard_size=1) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list branch = Branch.create(1, 0) tx = create_transfer_transaction( shard_state=slaves[0].shards[branch].state, key=id1.get_key(), from_address=acc1, to_address=acc1, value=0, gas_price=12, ) self.assertTrue(slaves[0].add_tx(tx)) for shard_id in ["0x0", None]: # shard, then root resp = send_request("getWork", shard_id) self.assertEqual(resp[1:], ["0x1", "0xa"]) # height and diff header_hash_hex = resp[0] _, block = call_async( master.get_next_block_to_mine(address=acc1)) self.assertEqual(header_hash_hex[2:], block.header.get_hash_for_mining().hex()) # solve it and submit solver = DoubleSHA256(block) mined = solver.mine(0, 1000) self.assertTrue(mined) nonce_found = "0x" + solver.nonce_found.hex() mixhash = "0x" + sha3_256(b"").hex() resp = send_request("submitWork", shard_id, header_hash_hex, nonce_found, mixhash) # FIXME: also verify root chain block addition after fixing https://github.com/QuarkChain/pyquarkchain/issues/130 if shard_id is not None: self.assertTrue(resp)
def test_new_block_pool(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext(1, acc1) as clusters: shard_state = clusters[0].get_shard_state(0b10) b1 = _tip_gen(shard_state) add_result = call_async(clusters[0].master.add_raw_minor_block( b1.header.branch, b1.serialize())) self.assertTrue(add_result) # Update config to force checking diff clusters[ 0].master.env.quark_chain_config.SKIP_MINOR_DIFFICULTY_CHECK = False b2 = b1.create_block_to_append(difficulty=12345) shard = clusters[0].slave_list[0].shards[b2.header.branch] with self.assertRaises(ValueError): call_async(shard.handle_new_block(b2)) # Also the block should not exist in new block pool self.assertTrue( b2.header.get_hash() not in shard.state.new_block_pool)
def test_create_shard_at_different_height(self): acc1 = Address.create_random_account() id1 = 0 << 16 | 1 | 0 id2 = 1 << 16 | 1 | 0 genesis_root_heights = {id1: 1, id2: 2} with ClusterContext( 1, acc1, chain_size=2, shard_size=1, genesis_root_heights=genesis_root_heights, ) as clusters: master = clusters[0].master self.assertIsNone(clusters[0].get_shard(id1)) self.assertIsNone(clusters[0].get_shard(id2)) is_root, root = call_async(master.get_next_block_to_mine(acc1)) self.assertTrue(is_root) self.assertEqual(len(root.minor_block_header_list), 0) call_async(master.add_root_block(root)) # shard 0 created at root height 1 self.assertIsNotNone(clusters[0].get_shard(id1)) self.assertIsNone(clusters[0].get_shard(id2)) is_root, root = call_async(master.get_next_block_to_mine(acc1)) self.assertTrue(is_root) self.assertEqual(len(root.minor_block_header_list), 1) call_async(master.add_root_block(root)) self.assertIsNotNone(clusters[0].get_shard(id1)) # shard 1 created at root height 2 self.assertIsNotNone(clusters[0].get_shard(id2)) is_root, block = call_async(master.get_next_block_to_mine(acc1)) self.assertTrue(is_root) self.assertEqual(len(root.minor_block_header_list), 1) call_async(master.add_root_block(root))
def test_gasPrice(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list # run for multiple times for _ in range(3): tx = create_transfer_transaction( shard_state=clusters[0].get_shard_state(2 | 0), key=id1.get_key(), from_address=acc1, to_address=acc1, value=0, gas_price=12, ) self.assertTrue(slaves[0].add_tx(tx)) block = call_async( master.get_next_block_to_mine(address=acc1, branch_value=0b10)) self.assertTrue( call_async(clusters[0].get_shard(2 | 0).add_block(block))) for using_eth_endpoint in (True, False): if using_eth_endpoint: resp = send_request("eth_gasPrice", ["0x0"]) else: resp = send_request( "gasPrice", ["0x0", quantity_encoder(token_id_encode("QKC"))]) self.assertEqual(resp, "0xc")
def test_getTransactionReceipt_on_transfer(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list tx = create_transfer_transaction( shard_state=clusters[0].get_shard_state(2 | 0), key=id1.get_key(), from_address=acc1, to_address=acc1, value=12345, ) self.assertTrue(slaves[0].add_tx(tx)) block1 = call_async( master.get_next_block_to_mine(address=acc1, branch_value=0b10)) self.assertTrue( call_async(clusters[0].get_shard(2 | 0).add_block(block1))) for endpoint in ("getTransactionReceipt", "eth_getTransactionReceipt"): resp = send_request( endpoint, [ "0x" + tx.get_hash().hex() + acc1.full_shard_key.to_bytes(4, "big").hex() ], ) self.assertEqual(resp["transactionHash"], "0x" + tx.get_hash().hex()) self.assertEqual(resp["status"], "0x1") self.assertEqual(resp["cumulativeGasUsed"], "0x5208") self.assertIsNone(resp["contractAddress"])
def test_createTransactions(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_random_account(full_shard_key=1) loadtest_accounts = [ { "address": "b067ac9ebeeecb10bbcd1088317959d58d1e38f6b0ee10d5", "key": "ca0143c9aa51c3013f08e83f3b6368a4f3ba5b52c4841c6e0c22c300f7ee6827", }, { "address": "9f2b984937ff8e3f20d2a2592f342f47257870909fffa247", "key": "40efdb8528de149c35fb43a572fc821d8fbdf2469dcc7fe1a9e847ef29e3c941", }, ] with ClusterContext(1, acc1, small_coinbase=True, loadtest_accounts=loadtest_accounts ) as clusters, jrpc_server_context( clusters[0].master): slaves = clusters[0].slave_list master = clusters[0].master block = call_async( master.get_next_block_to_mine(address=acc2, branch_value=None)) call_async(master.add_root_block(block)) send_request("createTransactions", { "numTxPerShard": 1, "xShardPercent": 0 })
def test_getCode(self): key = bytes.fromhex( "c987d4506fb6824639f9a9e3b8834584f5165e94680501d1b0044071cd36c3b3") id1 = Identity.create_from_key(key) acc1 = Address.create_from_identity(id1, full_shard_key=0) created_addr = "0x8531eb33bba796115f56ffa1b7df1ea3acdd8cdd00000000" with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list tx = create_contract_with_storage_transaction( shard_state=clusters[0].get_shard_state(2 | 0), key=id1.get_key(), from_address=acc1, to_full_shard_key=acc1.full_shard_key, ) self.assertTrue(slaves[0].add_tx(tx)) block = call_async( master.get_next_block_to_mine(address=acc1, branch_value=0b10)) self.assertTrue( call_async(clusters[0].get_shard(2 | 0).add_block(block))) for using_eth_endpoint in (True, False): if using_eth_endpoint: resp = send_request("eth_getCode", [created_addr[:-8], "0x0"]) else: resp = send_request("getCode", [created_addr]) self.assertEqual( resp, "0x6080604052600080fd00a165627a7a72305820a6ef942c101f06333ac35072a8ff40332c71d0e11cd0e6d86de8cae7b42696550029", )
def test_getTransactionById(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext( 1, acc1, small_coinbase=True) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list self.assertEqual( call_async( master.get_primary_account_data(acc1)).transaction_count, 0) tx = create_transfer_transaction( shard_state=clusters[0].get_shard_state(2 | 0), key=id1.get_key(), from_address=acc1, to_address=acc1, value=12345, ) self.assertTrue(slaves[0].add_tx(tx)) block1 = call_async( master.get_next_block_to_mine(address=acc1, branch_value=0b10)) self.assertTrue( call_async(clusters[0].get_shard(2 | 0).add_block(block1))) resp = send_request( "getTransactionById", [ "0x" + tx.get_hash().hex() + acc1.full_shard_key.to_bytes(4, "big").hex() ], ) self.assertEqual(resp["hash"], "0x" + tx.get_hash().hex())
def test_add_minor_block_request_list(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) with ClusterContext(2, acc1) as clusters: shard_state = clusters[0].get_shard_state(0b10) b1 = _tip_gen(shard_state) add_result = call_async(clusters[0].master.add_raw_minor_block( b1.header.branch, b1.serialize())) self.assertTrue(add_result) # Make sure the xshard list is not broadcasted to the other shard self.assertFalse(clusters[0].get_shard_state( 0b11).contain_remote_minor_block_hash(b1.header.get_hash())) self.assertTrue( clusters[0].master.root_state.db.contain_minor_block_by_hash( b1.header.get_hash())) # Make sure another cluster received the new block assert_true_with_timeout(lambda: clusters[0].get_shard_state( 0b10).contain_block_by_hash(b1.header.get_hash())) assert_true_with_timeout( lambda: clusters[1].master.root_state.db. contain_minor_block_by_hash(b1.header.get_hash()))