def test_shard_state_recovery_from_root_block(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env, shard_id=0) blockHeaders = [] blockMetas = [] for i in range(12): b = state.get_tip().create_block_to_append(address=acc1) state.finalize_and_add_block(b) blockHeaders.append(b.header) blockMetas.append(b.meta) # add a fork b1 = state.db.get_minor_block_by_height(3) b1.header.create_time += 1 state.finalize_and_add_block(b1) self.assertEqual( state.db.get_minor_block_by_hash(b1.header.get_hash()), b1) root_block = state.root_tip.create_block_to_append() root_block.minor_block_header_list = blockHeaders[:5] root_block.finalize() state.add_root_block(root_block) recoveredState = ShardState(env=env, shard_id=0) recoveredState.init_from_root_block(root_block) # forks are pruned self.assertIsNone( recoveredState.db.get_minor_block_by_hash(b1.header.get_hash())) self.assertEqual( recoveredState.db.get_minor_block_by_hash(b1.header.get_hash(), consistency_check=False), b1, ) self.assertEqual(recoveredState.root_tip, root_block.header) self.assertEqual(recoveredState.header_tip, blockHeaders[4]) self.assertEqual(recoveredState.confirmed_header_tip, blockHeaders[4]) self.assertEqual(recoveredState.meta_tip, blockMetas[4]) self.assertEqual(recoveredState.evm_state.trie.root_hash, blockMetas[4].hash_evm_state_root)
def test_getTransactionCount(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) as clusters, jrpc_server_context( clusters[0].master): master = clusters[0].master slaves = clusters[0].slave_list branch = Branch.create(2, 0) self.assertEqual( call_async( master.get_primary_account_data(acc1)).transaction_count, 0) for i in range(3): 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)) _, block = call_async( master.get_next_block_to_mine(address=acc1)) self.assertEqual(i + 1, block.header.height) self.assertTrue( call_async(clusters[0].get_shard(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_tx_incorrect_from_shard_id(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=1) acc2 = Address.create_random_account(full_shard_id=1) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env) # state is shard 0 but tx from shard 1 tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=12345, ) self.assertFalse(state.add_tx(tx)) self.assertIsNone(state.execute_tx(tx, acc1))
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) coinbase_amount = ( shard_state.env.quark_chain_config.shards[ shard_state.full_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] .get_shard_state(0b11) .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[0] .get_shard_state(0b10) .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_native_token_transfer_0_value(self): """to prevent storage spamming, do not delta_token_balance does not take action if value is 0 """ MALICIOUS0 = token_id_encode("MALICIOUS0") id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc3 = Address.create_random_account(full_shard_key=0) env = get_test_env( genesis_account=acc1, genesis_minor_token_balances={self.GENESIS_TOKEN: 10000000}) state = create_default_shard_state(env=env) tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc1, value=0, gas=opcodes.GTXCOST, gas_token_id=self.genesis_token, transfer_token_id=MALICIOUS0, ) self.assertTrue(state.add_tx(tx)) b1 = state.create_block_to_mine(address=acc3) self.assertEqual(len(b1.tx_list), 1) state.finalize_and_add_block(b1) self.assertEqual(state.header_tip, b1.header) self.assertEqual( state.get_token_balance(id1.recipient, self.genesis_token), 10000000 - opcodes.GTXCOST, ) self.assertEqual(state.get_token_balance(acc1.recipient, MALICIOUS0), 0) # MALICIOUS0 shall not be in the dict self.assertNotEqual( state.get_balances(acc1.recipient), { self.genesis_token: 10000000 - opcodes.GTXCOST, MALICIOUS0: 0 }, ) self.assertEqual( state.get_balances(acc1.recipient), {self.genesis_token: 10000000 - opcodes.GTXCOST}, )
async def deploy_shard(endpoint, genesisId, data, network_id, shard): address = Address.create_from_identity(genesisId, shard) nonce = await endpoint.get_nonce(address) tx = create_transaction(address, genesisId.get_key(), nonce, data, network_id) tx_id = await endpoint.send_transaction(tx) while True: print( "shard={} tx={} contract=(waiting for tx to be confirmed)".format( shard, tx_id ) ) await asyncio.sleep(5) contract_address = await endpoint.get_contract_address(tx_id) if contract_address: break print("shard={} tx={} contract={}".format(shard, tx_id, contract_address)) return tx_id, contract_address
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, 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 _, 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_add_invalid_tx_fail(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) acc2 = Address.create_random_account(full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env) tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=999999999999999999999, # insane ) self.assertFalse(state.add_tx(tx)) self.assertEqual(len(state.tx_queue), 0)
async def fund_shard(endpoint, genesisId, to, data, network_id, shard): address = Address.create_from_identity(genesisId, shard) nonce = await endpoint.get_nonce(address) tx = create_transaction(address, genesisId.get_key(), nonce, to, data, network_id) tx_id = await endpoint.send_transaction(tx) while True: print("shard={} tx={} block=(pending)".format(shard, tx_id)) await asyncio.sleep(5) resp = await endpoint.get_transaction_receipt(tx_id) if resp: break height = int(resp["block_height"], 16) status = int(resp["status"], 16) print("shard={} tx={} block={} status={}".format(shard, tx_id, height, status)) return tx_id, height
def test_execute_tx(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) acc2 = Address.create_random_account(full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env) tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=12345, ) # adding this line to make sure `execute_tx` would reset `gas_used` state.evm_state.gas_used = state.evm_state.gas_limit res = state.execute_tx(tx, acc1) self.assertEqual(res, b"")
def test_stale_block_count(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) acc3 = Address.create_random_account(full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env) b1 = state.create_block_to_mine(address=acc3) b2 = state.create_block_to_mine(address=acc3) b2.header.create_time += 1 state.finalize_and_add_block(b1) self.assertEqual(state.db.get_block_count_by_height(1), 1) state.finalize_and_add_block(b2) self.assertEqual(state.db.get_block_count_by_height(1), 2)
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_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_perf_evm(): N = 5000 IDN = 10 print("Creating %d identities" % IDN) id_list = [] for i in range(IDN): id_list.append(Identity.create_random_identity()) acc_list = [] for i in range(IDN): acc_list.append(Address.create_from_identity(id_list[i])) print("Creating %d transactions..." % N) start_time = time.time() tx_list = [] from_list = [] for i in range(N): from_id = id_list[random.randint(0, IDN - 1)] to_addr = acc_list[random.randint(0, IDN - 1)] evm_tx = EvmTransaction( nonce=0, gasprice=1, startgas=2, to=to_addr.recipient, value=3, data=b"", from_full_shard_key=0, to_full_shard_key=0, network_id=1, ) evm_tx.sign(key=from_id.get_key()) tx_list.append(evm_tx) from_list.append(from_id.get_recipient()) duration = time.time() - start_time print("Creations PS: %.2f" % (N / duration)) print("Verifying transactions") start_time = time.time() for i in range(N): tx_list[i]._sender = None assert tx_list[i].sender == from_list[i] duration = time.time() - start_time print("Verifications PS: %.2f" % (N / duration))
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_root_chain_first_consensus(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) env0 = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) env1 = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state0 = create_default_shard_state(env=env0, shard_id=0) state1 = create_default_shard_state(env=env1, shard_id=1) # Add one block and prepare a fork b0 = state0.get_tip().create_block_to_append(address=acc1) b2 = state0.get_tip().create_block_to_append( address=Address.create_empty_account()) state0.finalize_and_add_block(b0) state0.finalize_and_add_block(b2) b1 = state1.get_tip().create_block_to_append() b1.finalize(evm_state=state1.run_block(b1)) # Create a root block containing the block with the x-shard tx state0.add_cross_shard_tx_list_by_minor_block_hash( h=b1.header.get_hash(), tx_list=CrossShardTransactionList(tx_list=[])) root_block = ( state0.root_tip.create_block_to_append().add_minor_block_header( b0.header).add_minor_block_header(b1.header).finalize()) state0.add_root_block(root_block) b00 = b0.create_block_to_append() state0.finalize_and_add_block(b00) self.assertEqual(state0.header_tip, b00.header) # Create another fork that is much longer (however not confirmed by root_block) b3 = b2.create_block_to_append() state0.finalize_and_add_block(b3) b4 = b3.create_block_to_append() state0.finalize_and_add_block(b4) self.assertGreater(b4.header.height, b00.header.height) self.assertEqual(state0.header_tip, b00.header)
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_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_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_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_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_estimate_gas(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) acc2 = Address.create_random_account(full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env) tx_gen = lambda data: create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=12345, data=data, ) tx = tx_gen(b"") estimate = state.estimate_gas(tx, acc1) self.assertEqual(estimate, 21000) tx = tx_gen(b"12123478123412348125936583475758") estimate = state.estimate_gas(tx, acc1) self.assertEqual(estimate, 23176)
def create_test_transaction( from_id, from_tx_id, to_address, amount=100, remaining=100, shard_id=0, output_index=0, code=Code.get_transfer_code(), ): acc1 = Address.create_from_identity(from_id, shard_id) tx = Transaction( in_list=[TransactionInput(from_tx_id, output_index)], code=code, out_list=[ TransactionOutput(acc1, remaining), TransactionOutput(to_address, amount), ], ) tx.sign([from_id.get_key()]) return tx
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_exceeding_xshard_limit(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) acc3 = Address.create_random_account(full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) # a huge number to make xshard tx limit become 0 so that no xshard tx can be # included in the block env.quark_chain_config.MAX_NEIGHBORS = 10**18 state = create_default_shard_state(env=env) # xshard tx tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=12345, gas=50000, ) self.assertTrue(state.add_tx(tx)) b1 = state.create_block_to_mine(address=acc3) self.assertEqual(len(b1.tx_list), 0) # inshard tx tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc3, value=12345, gas=50000, ) self.assertTrue(state.add_tx(tx)) b1 = state.create_block_to_mine(address=acc3) self.assertEqual(len(b1.tx_list), 1)
def test_fork_resolve(self): id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_id=0) env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state = create_default_shard_state(env=env, shard_id=0) b0 = state.get_tip().create_block_to_append() b1 = state.get_tip().create_block_to_append() state.finalize_and_add_block(b0) self.assertEqual(state.header_tip, b0.header) # Fork happens, first come first serve state.finalize_and_add_block(b1) self.assertEqual(state.header_tip, b0.header) # Longer fork happens, override existing one b2 = b1.create_block_to_append() state.finalize_and_add_block(b2) self.assertEqual(state.header_tip, b2.header)
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")