def test_xshard_tx_sent(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) 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, shard_id=0) env1 = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state1 = create_default_shard_state(env=env1, shard_id=1) # Add a root block to update block gas limit so that xshard tx can be included root_block = ( state.root_tip.create_block_to_append().add_minor_block_header( state.header_tip).add_minor_block_header( state1.header_tip).finalize()) state.add_root_block(root_block) tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=888888, gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST, ) state.add_tx(tx) b1 = state.create_block_to_mine(address=acc3) self.assertEqual(len(b1.tx_list), 1) self.assertEqual(state.evm_state.gas_used, 0) # Should succeed state.finalize_and_add_block(b1) self.assertEqual(len(state.evm_state.xshard_list), 1) self.assertEqual( state.evm_state.xshard_list[0], CrossShardTransactionDeposit( tx_hash=tx.get_hash(), from_address=acc1, to_address=acc2, value=888888, gas_price=1, ), ) self.assertEqual( state.get_balance(id1.recipient), 10000000 - 888888 - opcodes.GTXCOST - opcodes.GTXXSHARDCOST, ) # Make sure the xshard gas is not used by local block self.assertEqual(state.evm_state.gas_used, opcodes.GTXCOST + opcodes.GTXXSHARDCOST) # GTXXSHARDCOST is consumed by remote shard self.assertEqual(state.get_balance(acc3.recipient), opcodes.GTXCOST // 2)
def test_serialization_and_deserialization(self): cstor_params = { "tx_hash": bytes(32), "from_address": Address.create_random_account(1), "to_address": Address.create_random_account(1), "value": 123, "gas_price": 456, "gas_token_id": 789, "transfer_token_id": 101, } deposit_deprecated = CrossShardTransactionDepositDeprecated( **cstor_params) deposit_v0 = CrossShardTransactionDepositV0(**cstor_params) deposit_v1 = CrossShardTransactionDeposit(**cstor_params) testcases = [ (CrossShardTransactionDeprecatedList([deposit_deprecated]), None), (CrossShardTransactionListV0([deposit_v0]), None), (CrossShardTransactionList([deposit_v1]), 55), ] for ls, refund_rate_update in testcases: if refund_rate_update: ls.tx_list[0].refund_rate = refund_rate_update else: refund_rate_update = 100 # default refund rate, for comparison deserialized = CrossShardTransactionList.from_data(ls.serialize()) self.assertIsInstance(deserialized, CrossShardTransactionList) self.assertEqual(len(deserialized.tx_list), 1) deposit = deserialized.tx_list[0] self.assertIsInstance(deposit, CrossShardTransactionDeposit) self.assertEqual(deposit.refund_rate, refund_rate_update) # serialize and deserialize again deposit_deserialized_again = CrossShardTransactionDeposit.deserialize( deposit.serialize()) self.assertIsInstance(deposit_deserialized_again, CrossShardTransactionDeposit) self.assertEqual(deposit_deserialized_again.refund_rate, refund_rate_update)
def test_xshard_native_token_gas_received(self): qeth = token_id_encode("QETHXX") id1 = Identity.create_random_identity() acc1 = Address.create_from_identity(id1, full_shard_key=0) acc2 = Address.create_from_identity(id1, full_shard_key=16) acc3 = Address.create_random_account(full_shard_key=0) env0 = get_test_env( genesis_account=acc1, genesis_minor_token_balances={"QETHXX": 9999999}, shard_size=64, ) env1 = get_test_env( genesis_account=acc1, genesis_minor_token_balances={"QETHXX": 9999999}, shard_size=64, ) state0 = create_default_shard_state(env=env0, shard_id=0) state1 = create_default_shard_state(env=env1, shard_id=16) # Add a root block to allow later minor blocks referencing this root block to # be broadcasted root_block = ( state0.root_tip.create_block_to_append() .add_minor_block_header(state0.header_tip) .add_minor_block_header(state1.header_tip) .finalize() ) state0.add_root_block(root_block) state1.add_root_block(root_block) # Add one block in shard 0 b0 = state0.create_block_to_mine() state0.finalize_and_add_block(b0) b1 = state1.get_tip().create_block_to_append() b1.header.hash_prev_root_block = root_block.header.get_hash() tx = create_transfer_transaction( shard_state=state1, key=id1.get_key(), from_address=acc2, to_address=acc1, value=8888888, gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST, gas_price=2, gas_token_id=qeth, transfer_token_id=qeth, ) b1.add_tx(tx) # Add a x-shard tx from remote peer state0.add_cross_shard_tx_list_by_minor_block_hash( h=b1.header.get_hash(), tx_list=CrossShardTransactionList( tx_list=[ CrossShardTransactionDeposit( tx_hash=tx.get_hash(), from_address=acc2, to_address=acc1, value=8888888, gas_price=2, gas_token_id=self.genesis_token, transfer_token_id=qeth, ) ] ), ) # Create a root block containing the block with the x-shard tx 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) # Add b0 and make sure all x-shard tx's are added b2 = state0.create_block_to_mine(address=acc3) state0.finalize_and_add_block(b2) self.assertEqual( state0.get_token_balance(acc1.recipient, qeth), 9999999 + 8888888 ) # Half coinbase collected by root + tx fee self.assertEqual( state0.get_token_balance(acc3.recipient, self.genesis_token), self.get_after_tax_reward(self.shard_coinbase + opcodes.GTXXSHARDCOST * 2), ) # X-shard gas used self.assertEqual( state0.evm_state.xshard_receive_gas_used, opcodes.GTXXSHARDCOST )
def test_xshard_native_token_gas_sent(self): """x-shard transfer QETH using QETH as gas """ qeth = token_id_encode("QETHXX") 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) acc3 = Address.create_random_account(full_shard_key=0) env = get_test_env( genesis_account=acc1, genesis_minor_token_balances={"QETHXX": 9999999}, charge_gas_reserve=True, ) state = create_default_shard_state(env=env, shard_id=0) env1 = get_test_env(genesis_account=acc1, genesis_minor_token_balances={}) state1 = create_default_shard_state(env=env1, shard_id=1) # Add a root block to update block gas limit so that xshard tx can be included root_block = ( state.root_tip.create_block_to_append() .add_minor_block_header(state.header_tip) .add_minor_block_header(state1.header_tip) .finalize() ) state.add_root_block(root_block) tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=8888888, gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST, gas_token_id=qeth, transfer_token_id=qeth, ) state.add_tx(tx) b1 = state.create_block_to_mine(address=acc3) self.assertEqual(len(b1.tx_list), 1) self.assertEqual(state.evm_state.gas_used, 0) # Should succeed state.finalize_and_add_block(b1) self.assertEqual(len(state.evm_state.xshard_list), 1) self.assertEqual( state.evm_state.xshard_list[0], CrossShardTransactionDeposit( tx_hash=tx.get_hash(), from_address=acc1, to_address=acc2, value=8888888, gas_price=1, gas_token_id=self.genesis_token, transfer_token_id=qeth, ), ) self.assertEqual( state.get_token_balance(id1.recipient, qeth), 9999999 - 8888888 - (opcodes.GTXCOST + opcodes.GTXXSHARDCOST), ) # Make sure the xshard gas is not used by local block self.assertEqual(state.evm_state.gas_used, opcodes.GTXCOST) # block coinbase for mining is still in genesis_token + xshard fee self.assertEqual( state.get_token_balance(acc3.recipient, self.genesis_token), self.get_after_tax_reward(self.shard_coinbase + opcodes.GTXCOST), )
def test_xshard_native_token_sent(self): """x-shard transfer QETH using genesis_token as gas """ QETH = token_id_encode("QETHXX") 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) acc3 = Address.create_random_account(full_shard_key=0) env = get_test_env( genesis_account=acc1, genesis_minor_token_balances={ self.GENESIS_TOKEN: 10000000, "QETHXX": 999999, }, ) state = create_default_shard_state(env=env, shard_id=0) env1 = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000) state1 = create_default_shard_state(env=env1, shard_id=1) # Add a root block to update block gas limit so that xshard tx can be included root_block = ( state.root_tip.create_block_to_append().add_minor_block_header( state.header_tip).add_minor_block_header( state1.header_tip).finalize()) state.add_root_block(root_block) tx = create_transfer_transaction( shard_state=state, key=id1.get_key(), from_address=acc1, to_address=acc2, value=888888, gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST, gas_token_id=self.genesis_token, transfer_token_id=QETH, ) state.add_tx(tx) b1 = state.create_block_to_mine(address=acc3) self.assertEqual(len(b1.tx_list), 1) self.assertEqual(state.evm_state.gas_used, 0) # Should succeed state.finalize_and_add_block(b1) self.assertEqual(len(state.evm_state.xshard_list), 1) self.assertEqual( state.evm_state.xshard_list[0], CrossShardTransactionDeposit( tx_hash=tx.get_hash(), from_address=acc1, to_address=acc2, value=888888, gas_price=1, gas_token_id=self.genesis_token, transfer_token_id=QETH, ), ) self.assertEqual( state.get_token_balance(id1.recipient, self.genesis_token), 10000000 - (opcodes.GTXCOST + opcodes.GTXXSHARDCOST), ) self.assertEqual(state.get_token_balance(id1.recipient, QETH), 999999 - 888888) # Make sure the xshard gas is not used by local block self.assertEqual(state.evm_state.gas_used, opcodes.GTXCOST + opcodes.GTXXSHARDCOST) # GTXXSHARDCOST is consumed by remote shard self.assertEqual( state.get_token_balance(acc3.recipient, self.genesis_token), self.getAfterTaxReward(opcodes.GTXCOST + self.shard_coinbase), )
def test_xshard_for_two_root_blocks(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) acc3 = Address.create_random_account(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 a root block to allow later minor blocks referencing this root block to # be broadcasted root_block = ( state0.root_tip.create_block_to_append().add_minor_block_header( state0.header_tip).add_minor_block_header( state1.header_tip).finalize()) state0.add_root_block(root_block) state1.add_root_block(root_block) # Add one block in shard 0 b0 = state0.create_block_to_mine() state0.finalize_and_add_block(b0) b1 = state1.get_tip().create_block_to_append() b1.header.hash_prev_root_block = root_block.header.get_hash() tx = create_transfer_transaction( shard_state=state1, key=id1.get_key(), from_address=acc2, to_address=acc1, value=888888, gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST, ) b1.add_tx(tx) # Add a x-shard tx from state1 state0.add_cross_shard_tx_list_by_minor_block_hash( h=b1.header.get_hash(), tx_list=CrossShardTransactionList(tx_list=[ CrossShardTransactionDeposit( tx_hash=tx.get_hash(), from_address=acc2, to_address=acc1, value=888888, gas_price=2, ) ]), ) # Create a root block containing the block with the x-shard tx root_block0 = ( 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_block0) b2 = state0.get_tip().create_block_to_append() state0.finalize_and_add_block(b2) b3 = b1.create_block_to_append() b3.header.hash_prev_root_block = root_block.header.get_hash() # Add a x-shard tx from state1 state0.add_cross_shard_tx_list_by_minor_block_hash( h=b3.header.get_hash(), tx_list=CrossShardTransactionList(tx_list=[ CrossShardTransactionDeposit( tx_hash=bytes(32), from_address=acc2, to_address=acc1, value=385723, gas_price=3, ) ]), ) root_block1 = ( state0.root_tip.create_block_to_append().add_minor_block_header( b2.header).add_minor_block_header(b3.header).finalize()) state0.add_root_block(root_block1) # Test x-shard gas limit when create_block_to_mine b5 = state0.create_block_to_mine(address=acc3, gas_limit=0) # Current algorithm allows at least one root block to be included self.assertEqual(b5.header.hash_prev_root_block, root_block0.header.get_hash()) b6 = state0.create_block_to_mine(address=acc3, gas_limit=opcodes.GTXXSHARDCOST) self.assertEqual(b6.header.hash_prev_root_block, root_block0.header.get_hash()) # There are two x-shard txs: one is root block coinbase with zero gas, and anonther is from shard 1 b7 = state0.create_block_to_mine(address=acc3, gas_limit=2 * opcodes.GTXXSHARDCOST) self.assertEqual(b7.header.hash_prev_root_block, root_block1.header.get_hash()) b8 = state0.create_block_to_mine(address=acc3, gas_limit=3 * opcodes.GTXXSHARDCOST) self.assertEqual(b8.header.hash_prev_root_block, root_block1.header.get_hash()) # Add b0 and make sure all x-shard tx's are added b4 = state0.create_block_to_mine(address=acc3) self.assertEqual(b4.header.hash_prev_root_block, root_block1.header.get_hash()) state0.finalize_and_add_block(b4) self.assertEqual(state0.get_balance(acc1.recipient), 10000000 + 888888 + 385723) # Half collected by root self.assertEqual(state0.get_balance(acc3.recipient), opcodes.GTXXSHARDCOST * (2 + 3) // 2) # Check gas used for receiving x-shard tx self.assertEqual(state0.evm_state.gas_used, 18000) self.assertEqual(state0.evm_state.xshard_receive_gas_used, 18000)
def test_xshard_tx_received_exclude_non_neighbor(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=3) acc3 = Address.create_random_account(full_shard_id=0) env0 = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000, shard_size=64) env1 = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000, shard_size=64) state0 = create_default_shard_state(env=env0, shard_id=0) state1 = create_default_shard_state(env=env1, shard_id=3) # Add one block in shard 0 b0 = state0.create_block_to_mine() state0.finalize_and_add_block(b0) b1 = state1.get_tip().create_block_to_append() tx = create_transfer_transaction( shard_state=state1, key=id1.get_key(), from_address=acc2, to_address=acc1, value=888888, gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST, gas_price=2, ) b1.add_tx(tx) # Add a x-shard tx from remote peer state0.add_cross_shard_tx_list_by_minor_block_hash( h=b1.header.get_hash(), tx_list=CrossShardTransactionList(tx_list=[ CrossShardTransactionDeposit( tx_hash=tx.get_hash(), from_address=acc2, to_address=acc1, value=888888, gas_price=2, ) ]), ) # Create a root block containing the block with the x-shard tx 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) # Add b0 and make sure all x-shard tx's are added b2 = state0.create_block_to_mine(address=acc3) state0.finalize_and_add_block(b2) self.assertEqual(state0.get_balance(acc1.recipient), 10000000) # Half collected by root self.assertEqual(state0.get_balance(acc3.recipient), 0) # X-shard gas used evmState0 = state0.evm_state self.assertEqual(evmState0.xshard_receive_gas_used, 0)