def wait_for_tx(self, all_txs, check_status): for tx in all_txs: for i in range(3): try: retry = True while retry: try: wait_until( lambda: checktx(self.nodes[0], tx.hash_hex()), timeout=20) retry = False except CannotSendRequest: time.sleep(0.01) break except AssertionError as _: self.nodes[0].p2p.send_protocol_msg( Transactions(transactions=[tx])) if i == 2: raise AssertionError( "Tx {} not confirmed after 30 seconds".format( tx.hash_hex())) # After having optimistic execution, get_receipts may get receipts with not deferred block, these extra blocks # ensure that later get_balance can get correct executed balance for all transactions client = RpcClient(self.nodes[0]) for _ in range(5): client.generate_block() receipts = [ client.get_transaction_receipt(tx.hash_hex()) for tx in all_txs ] self.log.debug("Receipts received: {}".format(receipts)) if check_status: map(lambda x: assert_equal(x['outcomeStatus'], 0), receipts) return receipts
def test(self, num_senders, num_receivers, num_txs): self.log.debug("Initializing {} senders".format(num_senders)) senders = self.init_senders(num_senders) self.log.debug("Initializing {} receivers".format(num_receivers)) receivers = self.init_receivers(num_receivers) self.log.info("begin to send {} txs to nodes and generate blocks ...".format(num_txs)) txs = self.send_txs_async(senders, receivers, num_txs) # generate blocks to pack txs self.log.info("continue to generate blocks to pack all transactions ...") client = RpcClient(self.nodes[0]) retry = num_txs for sender in senders: while True: receipt = client.get_receipt(sender.last_tx_hash) if receipt is not None: break assert retry > 0, "some tx not stated yet even after {} retries".format(num_txs) retry -= 1 self.generate_block(num_txs) time.sleep(0.5) # After having optimistic execution, get_receipts may get receipts with not deferred block, these extra blocks # ensure that later get_balance can get correct executed balance for all transactions for _ in range(5): client.generate_block() self.log.info("sync up blocks among nodes ...") sync_blocks(self.nodes) # check DAG self.log.info("begin to validate DAG for all nodes ...") self.check_with_rpc(client.epoch_number) self.check_with_rpc(client.best_block_hash) self.check_with_rpc(client.gas_price) self.check_with_rpc(client.chain, True) # check receipt self.log.info("begin to validate transaction receipts ...") for idx in range(self.num_nodes): node_client = RpcClient(self.nodes[idx]) for tx_hash in [sent_tx.hash_hex() for sent_tx in txs]: receipt = node_client.get_receipt(tx_hash) assert_equal(receipt is None, False) # check balance and nonce for all accounts self.log.info("begin to validate balance and nonce ...") all_accounts = list(senders) all_accounts.extend(receivers) for idx in range(self.num_nodes): self.log.debug("validate for node %d", idx) node_client = RpcClient(self.nodes[idx]) for account in all_accounts: assert_equal(node_client.get_balance(account.address), account.balance) assert_equal(node_client.get_nonce(account.address), account.nonce)
def run_test(self): num_blocks = 200 checkpoint_epoch = 100 # Generate checkpoint on node[0] client = RpcClient(self.nodes[0]) genesis_nonce = client.get_nonce(client.GENESIS_ADDR) for _ in range(num_blocks): tx = client.new_tx(nonce=genesis_nonce) tx_hash = client.send_tx(tx) assert tx_hash == tx.hash_hex() genesis_nonce += 1 client.generate_block(100) # Start node[1] as full node to sync checkpoint # Change phase from CatchUpSyncBlockHeader to CatchUpCheckpoint # only when there is at least one connected peer. self.start_node(1, ["--full"], phase_to_wait=None) connect_nodes(self.nodes, 1, 0) # FIXME full node issue that hang at phase CatchUpRecoverBlockFromDbPhase self.nodes[1].wait_for_phase(["NormalSyncPhase"], wait_time=30) sync_blocks(self.nodes, sync_count=False) client = RpcClient(self.nodes[1]) # At epoch 1, block header exists while body not synchronized try: print(client.block_by_epoch(client.EPOCH_NUM(1))) except ReceivedErrorResponseError as e: assert 'Internal error' == e.response.message # There is no state from epoch 1 to checkpoint_epoch # Note, state of genesis epoch always exists assert client.epoch_number() >= checkpoint_epoch for i in range(1, checkpoint_epoch): try: client.get_balance(client.GENESIS_ADDR, client.EPOCH_NUM(i)) raise AssertionError( "should be not state for epoch {}".format(i)) except ReceivedErrorResponseError as e: assert "State for epoch" in e.response.message assert "does not exist" in e.response.message # State should exist at checkpoint client.get_balance(client.GENESIS_ADDR, client.EPOCH_NUM(checkpoint_epoch)) # There should be states after checkpoint for i in range(checkpoint_epoch + 1, client.epoch_number() - 3): client.get_balance(client.GENESIS_ADDR, client.EPOCH_NUM(i))
def run(self): try: client = RpcClient(self.nodes[self.i]) # Do not limit num tx in blocks, only limit it with block size h = client.generate_block(10000000, self.tx_n * self.tx_data_len) self.log.debug("node %d actually generate block %s", self.i, h) except Exception as e: self.log.error("Node %d fails to generate block", self.i) self.log.error(str(e))
def run_test(self): time.sleep(3) ip = self.nodes[0].ip port = self.nodes[0].rpcport self.w3 = Web3(Web3.HTTPProvider(f'http://{ip}:{port}/')) assert_equal(self.w3.isConnected(), True) account = self.w3.eth.account.privateKeyToAccount( '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709' ) sender = account.address self.cross_space_transfer(sender, 1 * 10**18) assert_equal(1 * 10**18, self.w3.eth.get_balance(sender)) receiver = Web3.toChecksumAddress( "10000000000000000000000000000000000000aa") signed = account.signTransaction({ "to": receiver, "value": 5 * 10**17, "gasPrice": 1, "gas": 21000, "nonce": 0, "chainId": 10 }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction( signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) client = RpcClient(self.nodes[0]) client.generate_block(1) client.generate_blocks(10) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) assert_equal(5 * 10**17, self.w3.eth.get_balance(receiver)) assert_equal(5 * 10**17 - 21000, self.w3.eth.get_balance(sender)) self.nodes[0].stop()
def run(self): try: client = RpcClient(self.nodes[self.i]) # Do not limit num tx in blocks, and block size is already limited by `max_block_size_in_bytes` start = time.time() h = client.generate_block(10000000, self.max_block_size) self.rpc_times.append(round(time.time() - start, 3)) self.log.debug("node %d actually generate block %s", self.i, h) except Exception as e: self.log.error("Node %d fails to generate block", self.i) self.log.error(str(e))
def run_test(self): client0 = RpcClient(self.nodes[0]) client1 = RpcClient(self.nodes[1]) genesis = client0.best_block_hash() self.log.info("Generating two initial blocks") a1 = client0.generate_block() a2 = client0.generate_block() block_a2 = client0.block_by_hash(a2) assert(int(block_a2['height'], 16) == 2) self.log.info("Generating two invalid blocks") invalid = self.nodes[0].generatefixedblock(genesis, [a2], 0, False, INITIAL_DIFFICULTY) invalid2 = self.nodes[0].generatefixedblock(a2, [invalid], 0, False, INITIAL_DIFFICULTY) self.log.info("Sync two nodes") connect_nodes(self.nodes, 0, 1) wait_until(lambda: self.nodes[1].getblockcount() >= 3, timeout = 10) self.log.info("Node0 block count " + str(self.nodes[0].getblockcount())) self.log.info("Node1 block count " + str(self.nodes[1].getblockcount())) self.log.info("Generating a block without referencing partial invalid blocks") b1 = client1.generate_block() block_b1 = client1.block_by_hash(b1) assert(block_b1['parentHash'] == a2) assert(len(block_b1['refereeHashes']) == 0) self.log.info("Sync two nodes") connect_nodes(self.nodes, 1, 0) wait_until(lambda: self.nodes[0].getblockcount() >= 6, timeout = 40) wait_until(lambda: self.nodes[1].getblockcount() >= 4, timeout = 40) timer_cnt = 0 diff = int(block_b1['difficulty'], 16) pow_qual = int(block_b1['powQuality'], 16) if diff * TIMER_RATIO <= pow_qual: timer_cnt = 1 self.log.info("Start timer tick " + str(timer_cnt)) while timer_cnt < TIMER_BETA: a = client0.generate_block() self.log.info("Generated a block " + a) block_a = client0.block_by_hash(a) assert(len(block_a['refereeHashes']) == 0) diff = int(block_a['difficulty'], 16) pow_qual = int(block_a['powQuality'], 16) if diff * TIMER_RATIO <= pow_qual: timer_cnt += 1 self.log.info("Timer increased to " + str(timer_cnt)) self.log.info("Sync two nodes") connect_nodes(self.nodes, 0, 1) sync_blocks(self.nodes) self.log.info("Node1 generating a block to reference two partial invalid blocks") b2 = client1.generate_block() block_b2 = client1.block_by_hash(b2) assert(len(block_b2['refereeHashes']) > 0) assert(block_b2['refereeHashes'][0] == invalid2) self.log.info("Pass!")
class StorageMaintenanceTest(ConfluxTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True self.mining_author = "0x10000000000000000000000000000000000000aa" self.conf_parameters = {"mining_author": "\"10000000000000000000000000000000000000aa\"", "mining_type": "'disable'" } self.gasPrice = 1 def setup_network(self): self.log.info("setup nodes ...") self.setup_nodes() def run_test(self): self.rpc = RpcClient(self.nodes[0]) priv_key = default_config["GENESIS_PRI_KEY"] sender = eth_utils.encode_hex(priv_to_addr(priv_key)) block_reward = 7000000000000000000 # deploy storage test contract bytecode_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), CONTRACT_PATH) assert (os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() # 1. Produce an empty block self.rpc.generate_block() # 2. Deploy a contract: this will create 6 blocks and the first block contains 'create contract' transaction, # the other 5 blocks are empty. receipt, _ = self.deploy_contract(sender, priv_key, bytecode) # 3. Produce 10 empty blocks, and the miner's reward for the first block will be updated to world-state for _ in range(10): self.rpc.generate_block() balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author)) count = self.nodes[0].getblockcount() expected = block_reward self.log.info("block count: %d, balance: %d, expected: %d", count, balance, expected) assert_equal(balance, expected) # 4. Produce 1 empty block, and the miner will receive reward for the second block. This block reward should # contains transaction fee. self.rpc.generate_blocks(1) balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author)) count = self.nodes[0].getblockcount() transaction_fee = parse_as_int(receipt['gasFee']) expected += block_reward + transaction_fee self.log.info("block count: %d, balance: %d, expected: %d, transaction_fee: %d", count, balance, expected, transaction_fee) assert_equal(balance, expected) # 5. Produce 1 empty block, and the miner will receive reward for the third empty block. This block reward # should contains storage maintenance fee. self.rpc.generate_blocks(1) balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author)) count = self.nodes[0].getblockcount() collateral_for_storage = self.rpc.get_collateral_for_storage(sender) storage_fee = collateral_for_storage * 4 // 100 // 63072000 expected += block_reward + storage_fee self.log.info("block count: %d, balance: %d, expected: %d, collateral_for_storage: %d, storage_fee: %d", count, balance, expected, collateral_for_storage, storage_fee) assert_equal(balance, expected) # 6. Produce 1 empty block, and the miner will receive reward for the forth empty block. This block reward # should contains storage maintenance fee. self.rpc.generate_blocks(1) balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author)) count = self.nodes[0].getblockcount() collateral_for_storage = self.rpc.get_collateral_for_storage(sender) storage_fee = collateral_for_storage * 4 // 100 // 63072000 expected += storage_fee + block_reward self.log.info("block count: %d, balance: %d, expected: %d, collateral_for_storage: %d, storage_fee: %d", count, balance, expected, collateral_for_storage, storage_fee) assert_equal(balance, expected) def deploy_contract(self, sender, priv_key, data_hex): tx = self.rpc.new_contract_tx(receiver="", data_hex=data_hex, sender=sender, priv_key=priv_key, nonce=None, gas_price=self.gasPrice, storage_limit=20000) assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex()) receipt = self.rpc.get_transaction_receipt(tx.hash_hex()) address = receipt["contractCreated"] assert_is_hex_string(address) return receipt, address
def check_packed(): client = RpcClient(self.nodes[0]) client.generate_block(1) return checktx(self.nodes[0], tx.hash_hex())
def run_test(self): sponsor_whitelist_contract_addr = Web3.toChecksumAddress( "0888000000000000000000000000000000000001") collateral_per_storage_key = COLLATERAL_UNIT_IN_DRIP * 64 upper_bound = 5 * 10**7 file_dir = os.path.dirname(os.path.realpath(__file__)) control_contract_file_path = os.path.join( file_dir, "..", "internal_contract", "metadata", "SponsorWhitelistControl.json") control_contract_dict = json.loads( open(control_contract_file_path, "r").read()) control_contract = get_contract_instance( contract_dict=control_contract_dict) test_contract = get_contract_instance( abi_file=os.path.join( file_dir, "contracts/commission_privilege_test_abi.json"), bytecode_file=os.path.join( file_dir, "contracts/commission_privilege_test_bytecode.dat"), ) start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_key = self.genesis_priv_key genesis_addr = encode_hex_0x(self.genesis_addr) self.log.info("genesis_addr={}".format(genesis_addr)) nonce = 0 gas_price = 1 gas = CONTRACT_DEFAULT_GAS block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() self.tx_conf = { "from": Web3.toChecksumAddress(genesis_addr), "nonce": int_to_hex(nonce), "gas": int_to_hex(gas), "gasPrice": int_to_hex(gas_price), "chainId": 0 } # Setup balance for node 0 node = self.nodes[0] client = RpcClient(node) (addr1, priv_key1) = client.rand_account() self.log.info("addr1={}".format(addr1)) tx = client.new_tx(sender=genesis_addr, priv_key=genesis_key, value=10**6, nonce=self.get_nonce(self.genesis_addr), receiver=addr1) client.send_tx(tx, True) assert_equal(client.get_balance(addr1), 10**6) # setup contract transaction = self.call_contract_function( contract=test_contract, name="constructor", args=[], sender_key=self.genesis_priv_key, storage_limit=20000) contract_addr = self.wait_for_tx([transaction], True)[0]['contractCreated'] self.log.info("contract_addr={}".format(contract_addr)) assert_equal(client.get_balance(contract_addr), 0) # sponsor the contract succeed b0 = client.get_balance(genesis_addr) self.call_contract_function( contract=control_contract, name="setSponsorForGas", args=[Web3.toChecksumAddress(contract_addr), upper_bound], value=10**18, sender_key=self.genesis_priv_key, contract_addr=sponsor_whitelist_contract_addr, wait=True) assert_equal(client.get_sponsor_balance_for_gas(contract_addr), 10**18) assert_equal(client.get_sponsor_for_gas(contract_addr), genesis_addr) assert_equal(client.get_sponsor_gas_bound(contract_addr), upper_bound) assert_equal(client.get_balance(genesis_addr), b0 - 10**18 - charged_of_huge_gas(gas)) # set privilege for addr1 b0 = client.get_balance(genesis_addr) c0 = client.get_collateral_for_storage(genesis_addr) transaction = self.call_contract_function( contract=test_contract, name="add", args=[Web3.toChecksumAddress(addr1)], sender_key=genesis_key, contract_addr=contract_addr, wait=True, check_status=True, storage_limit=64) assert_equal( client.get_balance(genesis_addr), b0 - charged_of_huge_gas(gas) - collateral_per_storage_key) assert_equal(client.get_collateral_for_storage(genesis_addr), c0 + collateral_per_storage_key) assert_equal( self.wait_for_tx([transaction], True)[0]['gasCoveredBySponsor'], False) # addr1 call contract with privilege without enough cfx for gas fee sb = client.get_sponsor_balance_for_gas(contract_addr) b1 = client.get_balance(addr1) transaction = self.call_contract_function(contract=test_contract, name="foo", args=[], sender_key=priv_key1, contract_addr=contract_addr, wait=True, check_status=True) assert_equal(client.get_balance(addr1), b1) assert_equal(client.get_sponsor_balance_for_gas(contract_addr), sb - charged_of_huge_gas(gas)) assert_equal( self.wait_for_tx([transaction], True)[0]['gasCoveredBySponsor'], True) # sponsor collateral for the contract succeed b0 = client.get_balance(genesis_addr) self.call_contract_function( contract=control_contract, name="setSponsorForCollateral", args=[Web3.toChecksumAddress(contract_addr)], value=10**18, # 1 CFX = 1KB sender_key=self.genesis_priv_key, contract_addr=sponsor_whitelist_contract_addr, wait=True) assert_equal(client.get_sponsor_balance_for_collateral(contract_addr), 10**18) assert_equal(client.get_sponsor_for_collateral(contract_addr), genesis_addr) assert_equal(client.get_balance(genesis_addr), b0 - 10**18 - charged_of_huge_gas(gas)) # addr1 call contract with privilege without enough cfx for storage sb = client.get_sponsor_balance_for_gas(contract_addr) b1 = client.get_balance(addr1) transaction = self.call_contract_function(contract=test_contract, name="foo", args=[], sender_key=priv_key1, contract_addr=contract_addr, wait=True, check_status=True, storage_limit=1024) assert_equal(client.get_balance(addr1), b1) assert_equal(client.get_sponsor_balance_for_gas(contract_addr), sb - charged_of_huge_gas(gas)) assert_equal( self.wait_for_tx([transaction], True)[0]['storageCoveredBySponsor'], True) # addr1 call with larger storage limit, should not packed transaction = self.call_contract_function(contract=test_contract, name="foo", args=[], sender_key=priv_key1, contract_addr=contract_addr, storage_limit=1025) for _ in range(10): client.generate_block() tx_info = self.nodes[0].txpool_txWithPoolInfo(transaction.hash_hex()) assert_equal(int(tx_info['local_nonce'], 16), 2) assert_equal(tx_info['local_balance_enough'], False) assert_equal(tx_info['packed'], False) # send 1025 * 10 ** 18 // 1024 CFX to addr1 tx = client.new_tx(sender=genesis_addr, priv_key=genesis_key, value=1025 * 10**18 // 1024, nonce=self.get_nonce(self.genesis_addr), receiver=addr1) client.send_tx(tx, True) assert_equal(client.get_balance(addr1), 10**6 + 1025 * 10**18 // 1024) for _ in range(10): client.generate_block() tx_info = self.nodes[0].txpool_txWithPoolInfo(transaction.hash_hex()) # Now addr1 pays for storage collateral by itself. assert_equal( self.wait_for_tx([transaction], True)[0]['storageCoveredBySponsor'], False) assert_equal(int(tx_info['local_nonce'], 16), 3) assert_equal(tx_info['packed'], True) self.log.info("Pass")
class PhantomTransactionTest(ConfluxTestFramework): def set_test_params(self): self.num_nodes = 1 self.conf_parameters["chain_id"] = str(10) self.conf_parameters["evm_chain_id"] = str(11) self.conf_parameters["evm_transaction_block_ratio"] = str(1) def setup_network(self): self.add_nodes(self.num_nodes) self.start_node(0, ["--archive"]) self.rpc = RpcClient(self.nodes[0]) ip = self.nodes[0].ip port = self.nodes[0].ethrpcport self.w3 = Web3(Web3.HTTPProvider(f'http://{ip}:{port}/')) assert_equal(self.w3.isConnected(), True) def run_test(self): # initialize Conflux account self.cfxPrivkey = default_config['GENESIS_PRI_KEY'] self.cfxAccount = self.rpc.GENESIS_ADDR print(f'Using Conflux account {self.cfxAccount}') # initialize EVM account self.evmAccount = self.w3.eth.account.privateKeyToAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef') print(f'Using EVM account {self.evmAccount.address}') self.cross_space_transfer(self.evmAccount.address, 1 * 10 ** 18) assert_equal(self.nodes[0].eth_getBalance(self.evmAccount.address), hex(1 * 10 ** 18)) # deploy Conflux space contract confluxContractAddr = self.deploy_conflux_space(CONFLUX_CONTRACT_PATH) print(f'Conflux contract: {confluxContractAddr}') # deploy EVM space contract evmContractAddr = self.deploy_evm_space(EVM_CONTRACT_PATH) print(f'EVM contract: {evmContractAddr}') # --- # .-----------------| D |.... # V --- | # --- --- --- --- # ... <-- | A | <- | B | <- | C | <- | E | <- ... # --- --- --- --- # # A --- B --- C --- D --- E # block number 0 | 1 | 2 | 3 | 4 | # epoch number 0 | 1 | 2 | 3 | cfx_next_nonce = self.rpc.get_nonce(self.cfxAccount) cfx_tx_hashes = [] evm_next_nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) evm_tx_hashes = [] def emitConflux(n): nonlocal cfx_next_nonce, cfx_tx_hashes data_hex = (encode_hex_0x(keccak(b"emitConflux(uint256)"))[:10] + encode_u256(n)) tx = self.rpc.new_contract_tx(receiver=confluxContractAddr, data_hex=data_hex, nonce = cfx_next_nonce, sender=self.cfxAccount, priv_key=self.cfxPrivkey) cfx_next_nonce += 1 cfx_tx_hashes.append(tx.hash_hex()) return tx def emitComplex(n): nonlocal cfx_next_nonce, cfx_tx_hashes data_hex = encode_hex_0x(keccak(b"emitComplex(uint256,bytes20)"))[:10] + encode_u256(n) + encode_bytes20(evmContractAddr.replace('0x', '')) tx = self.rpc.new_contract_tx(receiver=confluxContractAddr, data_hex=data_hex, nonce = cfx_next_nonce, sender=self.cfxAccount, priv_key=self.cfxPrivkey) cfx_next_nonce += 1 cfx_tx_hashes.append(tx.hash_hex()) return tx def emitEVM(n): nonlocal evm_next_nonce, evm_tx_hashes data_hex = (encode_hex_0x(keccak(b"emitEVM(uint256)"))[:10] + encode_u256(n)) tx, hash = self.construct_evm_tx(receiver=evmContractAddr, data_hex=data_hex, nonce = evm_next_nonce) evm_next_nonce += 1 evm_tx_hashes.append(hash) return tx # generate ledger block_0 = self.rpc.block_by_epoch("latest_mined")['hash'] block_a = self.rpc.generate_custom_block(parent_hash = block_0, referee = [], txs = [ emitConflux(11), emitEVM(12), emitComplex(13), ]) block_b = self.rpc.generate_custom_block(parent_hash = block_a, referee = [], txs = [ emitConflux(14), emitEVM(15), emitComplex(16), ]) block_c = self.rpc.generate_custom_block(parent_hash = block_b, referee = [], txs = []) block_d = self.rpc.generate_custom_block(parent_hash = block_a, referee = [], txs = [ emitConflux(21), emitEVM(22), emitComplex(23), ]) block_e = self.rpc.generate_custom_block(parent_hash = block_c, referee = [block_d], txs = [ emitConflux(24), emitEVM(25), emitComplex(26), ]) [epoch_a, block_number_a] = [self.rpc.block_by_hash(block_a)[key] for key in ['epochNumber', 'blockNumber']] [epoch_b, block_number_b] = [self.rpc.block_by_hash(block_b)[key] for key in ['epochNumber', 'blockNumber']] [epoch_d, block_number_d] = [self.rpc.block_by_hash(block_d)[key] for key in ['epochNumber', 'blockNumber']] [epoch_e, block_number_e] = [self.rpc.block_by_hash(block_e)[key] for key in ['epochNumber', 'blockNumber']] # make sure transactions have been executed parent_hash = block_e for _ in range(5): block = self.rpc.generate_custom_block(parent_hash = parent_hash, referee = [], txs = []) parent_hash = block for h in cfx_tx_hashes: receipt = self.rpc.get_transaction_receipt(h) assert_equal(receipt["outcomeStatus"], "0x0") for h in evm_tx_hashes: receipt = self.w3.eth.waitForTransactionReceipt(h) assert_equal(receipt["status"], 1) # TODO: add failing tx # --------------------------------------------------------------------- # Conflux perspective: # A: 2 txs (events: [11], [13, X, X, 13, X, X, 13]) X ~ internal contract event # B: 2 txs (events: [14], [16, X, X, 16, X, X, 16]) # C: / # D: 2 txs (events: [21], [23, X, X, 23, X, X, 23]) # E: 2 txs (events: [24], [26, X, X, 26, X, X, 26]) # block #A block = self.nodes[0].cfx_getBlockByHash(block_a, True) assert_equal(len(block["transactions"]), 2) block2 = self.nodes[0].cfx_getBlockByBlockNumber(block_number_a, True) assert_equal(block2, block) tx_hashes = self.nodes[0].cfx_getBlockByHash(block_a, False)["transactions"] assert_equal(len(tx_hashes), 2) for idx, tx in enumerate(block["transactions"]): # check returned hash assert_equal(tx["hash"], tx_hashes[idx]) # check indexing # assert_equal(tx["transactionIndex"], hex(idx)) # check cfx_getTransactionByHash assert_equal(tx, self.nodes[0].cfx_getTransactionByHash(tx["hash"])) receipts = self.nodes[0].cfx_getEpochReceipts(epoch_a) assert_equal(len(receipts), 1) # 1 block assert_equal(len(receipts[0]), 2) # 2 receipts receipts2 = self.nodes[0].cfx_getEpochReceipts(f'hash:{block_a}') assert_equal(receipts2, receipts) assert_equal(len(receipts[0][0]["logs"]), 1) assert_equal(receipts[0][0]["logs"][0]["data"], number_to_topic(11)) assert_equal(len(receipts[0][1]["logs"]), 7) assert_equal(receipts[0][1]["logs"][0]["data"], number_to_topic(13)) # Call, Outcome, ... assert_equal(receipts[0][1]["logs"][3]["data"], number_to_topic(13)) # Call, Outcome, ... assert_equal(receipts[0][1]["logs"][6]["data"], number_to_topic(13)) # TODO.... # --------------------------------------------------------------------- # EVM perspective: # A: 5 txs (events: [12], [], [13], [], [13, 13]) # B: 5 txs (events: [15], [], [16], [], [16, 16]) # C: / # E: 10 txs (events: [22], [], [23], [], [23, 23], [25], [], [26], [], [26, 26]) # block #A block = self.nodes[0].eth_getBlockByNumber(epoch_a, True) assert_equal(len(block["transactions"]), 5) block2 = self.nodes[0].eth_getBlockByHash(block_a, True) assert_equal(block2, block) count = int(self.nodes[0].eth_getBlockTransactionCountByNumber(epoch_a), 16) assert_equal(count, len(block["transactions"])) count = int(self.nodes[0].eth_getBlockTransactionCountByHash(block_a), 16) assert_equal(count, len(block["transactions"])) tx_hashes = self.nodes[0].eth_getBlockByNumber(epoch_a, False)["transactions"] assert_equal(len(tx_hashes), 5) for idx, tx in enumerate(block["transactions"]): # check returned hash assert_equal(tx["hash"], tx_hashes[idx]) # check indexing assert_equal(tx["transactionIndex"], hex(idx)) # check eth_getTransactionByHash assert_equal(tx, self.nodes[0].eth_getTransactionByHash(tx["hash"])) # TODO: check transaction details receipts = self.nodes[0].parity_getBlockReceipts(epoch_a) assert_equal(len(receipts), 5) receipts2 = self.nodes[0].parity_getBlockReceipts({ "blockHash": block_a }) assert_equal(receipts2, receipts) receipts2 = self.nodes[0].parity_getBlockReceipts({ "blockHash": block_a, "requireCanonical": True }) assert_equal(receipts2, receipts) receipts2 = self.nodes[0].parity_getBlockReceipts({ "blockHash": block_a, "requireCanonical": False }) assert_equal(receipts2, receipts) logIndex = 0 filter = { "fromBlock": epoch_a, "toBlock": epoch_a } logsFiltered = self.nodes[0].eth_getLogs(filter) assert_equal(len(logsFiltered), 4) for idx, receipt in enumerate(receipts): assert_equal(receipt["blockHash"], block_a) assert_equal(receipt["blockNumber"], epoch_a) assert_equal(receipt["contractAddress"], None) assert_equal(receipt["status"], "0x1") assert_equal(receipt["transactionHash"], tx_hashes[idx]) assert_equal(receipt["transactionIndex"], hex(idx)) # TODO: check logs bloom, cumulative gas used # check eth_getTransactionReceipt assert_equal(receipt, self.nodes[0].eth_getTransactionReceipt(receipt["transactionHash"])) for idx2, log in enumerate(receipt["logs"]): assert_equal(log["address"], evmContractAddr.lower()) assert_equal(log["blockHash"], block_a) assert_equal(log["blockNumber"], epoch_a) assert_equal(log["transactionHash"], tx_hashes[idx]) assert_equal(log["transactionIndex"], hex(idx)) assert_equal(log["logIndex"], hex(logIndex)) assert_equal(log["transactionLogIndex"], hex(idx2)) assert_equal(log["removed"], False) assert_equal(log, logsFiltered[logIndex]) logIndex += 1 assert_equal(len(receipts[0]["logs"]), 1) assert_equal(receipts[0]["logs"][0]["data"], number_to_topic(12)) assert_equal(len(receipts[1]["logs"]), 0) assert_equal(len(receipts[2]["logs"]), 1) assert_equal(receipts[2]["logs"][0]["data"], number_to_topic(13)) assert_equal(len(receipts[3]["logs"]), 0) assert_equal(len(receipts[4]["logs"]), 2) assert_equal(receipts[4]["logs"][0]["data"], number_to_topic(13)) assert_equal(receipts[4]["logs"][1]["data"], number_to_topic(13)) # block #D block = self.nodes[0].eth_getBlockByHash(block_d, True) assert_equal(block, None) count = self.nodes[0].eth_getBlockTransactionCountByHash(block_d) assert_equal(count, None) # block #E block = self.nodes[0].eth_getBlockByNumber(epoch_e, True) assert_equal(len(block["transactions"]), 10) block2 = self.nodes[0].eth_getBlockByHash(block_e, True) assert_equal(block2, block) count = int(self.nodes[0].eth_getBlockTransactionCountByNumber(epoch_e), 16) assert_equal(count, len(block["transactions"])) count = int(self.nodes[0].eth_getBlockTransactionCountByHash(block_e), 16) assert_equal(count, len(block["transactions"])) tx_hashes = self.nodes[0].eth_getBlockByNumber(epoch_e, False)["transactions"] assert_equal(len(tx_hashes), 10) for idx, tx in enumerate(block["transactions"]): # check returned hash assert_equal(tx["hash"], tx_hashes[idx]) # check indexing assert_equal(tx["transactionIndex"], hex(idx)) # check eth_getTransactionByHash assert_equal(tx, self.nodes[0].eth_getTransactionByHash(tx["hash"])) receipts = self.nodes[0].parity_getBlockReceipts(epoch_e) assert_equal(len(receipts), 10) receipts2 = self.nodes[0].parity_getBlockReceipts({ "blockHash": block_e }) assert_equal(receipts2, receipts) logIndex = 0 filter = { "fromBlock": epoch_e, "toBlock": epoch_e } logsFiltered = self.nodes[0].eth_getLogs(filter) assert_equal(len(logsFiltered), 8) for idx, receipt in enumerate(receipts): assert_equal(receipt["blockHash"], block_e) assert_equal(receipt["blockNumber"], epoch_e) assert_equal(receipt["contractAddress"], None) assert_equal(receipt["status"], "0x1") assert_equal(receipt["transactionHash"], tx_hashes[idx]) assert_equal(receipt["transactionIndex"], hex(idx)) # TODO: check logs bloom, cumulative gas used # check eth_getTransactionReceipt assert_equal(receipt, self.nodes[0].eth_getTransactionReceipt(receipt["transactionHash"])) for idx2, log in enumerate(receipt["logs"]): assert_equal(log["address"], evmContractAddr.lower()) assert_equal(log["blockHash"], block_e) assert_equal(log["blockNumber"], epoch_e) assert_equal(log["transactionHash"], tx_hashes[idx]) assert_equal(log["transactionIndex"], hex(idx)) assert_equal(log["logIndex"], hex(logIndex)) assert_equal(log["transactionLogIndex"], hex(idx2)) assert_equal(log["removed"], False) assert_equal(log, logsFiltered[logIndex]) logIndex += 1 assert_equal(len(receipts[0]["logs"]), 1) assert_equal(receipts[0]["logs"][0]["data"], number_to_topic(22)) assert_equal(len(receipts[1]["logs"]), 0) assert_equal(len(receipts[2]["logs"]), 1) assert_equal(receipts[2]["logs"][0]["data"], number_to_topic(23)) assert_equal(len(receipts[3]["logs"]), 0) assert_equal(len(receipts[4]["logs"]), 2) assert_equal(receipts[4]["logs"][0]["data"], number_to_topic(23)) assert_equal(receipts[4]["logs"][0]["data"], number_to_topic(23)) assert_equal(len(receipts[5]["logs"]), 1) assert_equal(receipts[5]["logs"][0]["data"], number_to_topic(25)) assert_equal(len(receipts[6]["logs"]), 0) assert_equal(len(receipts[7]["logs"]), 1) assert_equal(receipts[7]["logs"][0]["data"], number_to_topic(26)) assert_equal(len(receipts[8]["logs"]), 0) assert_equal(len(receipts[9]["logs"]), 2) assert_equal(receipts[9]["logs"][0]["data"], number_to_topic(26)) assert_equal(receipts[9]["logs"][0]["data"], number_to_topic(26)) # --------------------------------------------------------------------- # make sure pending transactions can be retrieved even before execution evm_next_nonce += 1 signed = self.evmAccount.signTransaction({ "to": evmContractAddr, "value": 0, "gasPrice": 1, "gas": 150000, "nonce": evm_next_nonce, "chainId": 11, "data": "0x", }) tx_hash = self.w3.eth.sendRawTransaction(signed["rawTransaction"]) tx = self.nodes[0].eth_getTransactionByHash(tx_hash.hex()) assert_ne(tx, None) self.log.info("Pass") def cross_space_transfer(self, to, value): to = to.replace('0x', '') tx = self.rpc.new_tx( value=value, receiver="0x0888000000000000000000000000000000000006", data=decode_hex(f"0xda8d5daf{to}000000000000000000000000"), nonce=self.rpc.get_nonce(self.cfxAccount), gas=1000000, ) self.rpc.send_tx(tx, True) def deploy_conflux_space(self, bytecode_path): bytecode_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), bytecode_path) assert(os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() tx = self.rpc.new_contract_tx(receiver="", data_hex=bytecode, sender=self.cfxAccount, priv_key=self.cfxPrivkey, storage_limit=20000) assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex()) receipt = self.rpc.get_transaction_receipt(tx.hash_hex()) assert_equal(receipt["outcomeStatus"], "0x0") addr = receipt["contractCreated"] assert_is_hex_string(addr) return addr def deploy_evm_space(self, bytecode_path): bytecode_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), bytecode_path) assert(os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) signed = self.evmAccount.signTransaction({ "to": None, "value": 0, "gasPrice": 1, "gas": 500000, "nonce": nonce, "chainId": 11, "data": bytecode, }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction(signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) self.rpc.generate_block(1) self.rpc.generate_blocks(20, 1) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) addr = receipt["contractAddress"] return addr def construct_evm_tx(self, receiver, data_hex, nonce): signed = self.evmAccount.signTransaction({ "to": receiver, "value": 0, "gasPrice": 1, "gas": 150000, "nonce": nonce, "chainId": 11, "data": data_hex, }) tx = [nonce, 1, 150000, bytes.fromhex(receiver.replace('0x', '')), 0, bytes.fromhex(data_hex.replace('0x', '')), signed["v"], signed["r"], signed["s"]] return tx, signed["hash"]
class CrossSpaceLogFilteringTest(ConfluxTestFramework): def set_test_params(self): self.num_nodes = 1 self.conf_parameters["evm_chain_id"] = str(10) self.conf_parameters["evm_transaction_block_ratio"] = str(1) def setup_network(self): self.add_nodes(self.num_nodes) self.start_node(0, ["--archive"]) self.rpc = RpcClient(self.nodes[0]) ip = self.nodes[0].ip port = self.nodes[0].rpcport self.w3 = Web3(Web3.HTTPProvider(f'http://{ip}:{port}/')) assert_equal(self.w3.isConnected(), True) def run_test(self): # initialize Conflux account self.cfxPrivkey = default_config['GENESIS_PRI_KEY'] self.cfxAccount = self.rpc.GENESIS_ADDR print(f'Using Conflux account {self.cfxAccount}') # initialize EVM account self.evmAccount = self.w3.eth.account.privateKeyToAccount( '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' ) print(f'Using EVM account {self.evmAccount.address}') self.cross_space_transfer(self.evmAccount.address, 1 * 10**18) assert_equal(self.nodes[0].eth_getBalance(self.evmAccount.address), hex(1 * 10**18)) # deploy Conflux space contract confluxContractAddr = self.deploy_conflux_space(CONFLUX_CONTRACT_PATH) print(f'Conflux contract: {confluxContractAddr}') # deploy EVM space contract evmContractAddr = self.deploy_evm_space(EVM_CONTRACT_PATH) print(f'EVM contract: {evmContractAddr}') # --- # .-----------------| D |.... # V --- | # --- --- --- --- # ... <-- | A | <- | B | <- | C | <- | E | <- ... # --- --- --- --- # # A --- B --- C --- D --- E # block number 0 | 1 | 2 | 3 | 4 | # epoch number 0 | 1 | 2 | 3 | cfx_next_nonce = self.rpc.get_nonce(self.cfxAccount) cfx_tx_hashes = [] evm_next_nonce = self.w3.eth.getTransactionCount( self.evmAccount.address) evm_tx_hashes = [] def emitConflux(n): nonlocal cfx_next_nonce, cfx_tx_hashes data_hex = (encode_hex_0x(keccak(b"emitConflux(uint256)"))[:10] + encode_u256(n)) tx = self.rpc.new_contract_tx(receiver=confluxContractAddr, data_hex=data_hex, nonce=cfx_next_nonce, sender=self.cfxAccount, priv_key=self.cfxPrivkey) cfx_next_nonce += 1 cfx_tx_hashes.append(tx.hash_hex()) return tx def emitBoth(n): nonlocal cfx_next_nonce, cfx_tx_hashes data_hex = encode_hex_0x( keccak(b"emitBoth(uint256,bytes20)"))[:10] + encode_u256( n) + encode_bytes20(evmContractAddr.replace('0x', '')) tx = self.rpc.new_contract_tx(receiver=confluxContractAddr, data_hex=data_hex, nonce=cfx_next_nonce, sender=self.cfxAccount, priv_key=self.cfxPrivkey) cfx_next_nonce += 1 cfx_tx_hashes.append(tx.hash_hex()) return tx def emitEVM(n): nonlocal evm_next_nonce, evm_tx_hashes data_hex = (encode_hex_0x(keccak(b"emitEVM(uint256)"))[:10] + encode_u256(n)) tx, hash = self.construct_evm_tx(receiver=evmContractAddr, data_hex=data_hex, nonce=evm_next_nonce) evm_next_nonce += 1 evm_tx_hashes.append(hash) return tx # generate ledger block_0 = self.rpc.block_by_epoch("latest_mined")['hash'] block_a = self.rpc.generate_custom_block(parent_hash=block_0, referee=[], txs=[ emitConflux(11), emitBoth(12), emitEVM(13), ]) block_b = self.rpc.generate_custom_block(parent_hash=block_a, referee=[], txs=[ emitConflux(14), emitBoth(15), emitEVM(16), ]) block_c = self.rpc.generate_custom_block(parent_hash=block_b, referee=[], txs=[]) block_d = self.rpc.generate_custom_block(parent_hash=block_a, referee=[], txs=[ emitConflux(21), emitBoth(22), emitEVM(23), ]) block_e = self.rpc.generate_custom_block(parent_hash=block_c, referee=[block_d], txs=[ emitConflux(24), emitBoth(25), emitEVM(26), ]) epoch_a = self.rpc.block_by_hash(block_a)['epochNumber'] epoch_b = self.rpc.block_by_hash(block_b)['epochNumber'] epoch_e = self.rpc.block_by_hash(block_e)['epochNumber'] # make sure transactions have been executed parent_hash = block_e for _ in range(5): block = self.rpc.generate_custom_block(parent_hash=parent_hash, referee=[], txs=[]) parent_hash = block for h in cfx_tx_hashes: receipt = self.rpc.get_transaction_receipt(h) assert_equal(receipt["outcomeStatus"], "0x0") for h in evm_tx_hashes: receipt = self.w3.eth.waitForTransactionReceipt(h) assert_equal(receipt["status"], 1) # check Conflux events filter = Filter(topics=[TEST_EVENT_TOPIC], from_epoch=epoch_a, to_epoch=epoch_e) logs = self.rpc.get_logs(filter) assert_equal(len(logs), 8) # --------------- 1 block per epoch --------------- # check EVM events # we expect 4 events: #12, #13, #15, #16 filter = { "topics": [TEST_EVENT_TOPIC], "fromBlock": epoch_a, "toBlock": epoch_b } logs = self.nodes[0].eth_getLogs(filter) assert_equal(len(logs), 4) # emitBoth: TestEvent(12) assert_equal(logs[0]["data"], number_to_topic(12)) assert_equal(logs[0]["address"], evmContractAddr.lower()) assert_equal(logs[0]["blockHash"], block_a) assert_equal(logs[0]["blockNumber"], epoch_a) assert_equal(logs[0]["transactionHash"], cfx_tx_hashes[1]) # TODO: should use phantom tx here # assert_equal(logs[0]["logIndex"], '0x0') # assert_equal(logs[0]["transactionIndex"], '0x0') # assert_equal(logs[0]["transactionLogIndex"], '0x0') assert_equal(logs[0]["removed"], False) # emitEVM: TestEvent(13) assert_equal(logs[1]["data"], number_to_topic(13)) assert_equal(logs[1]["address"], evmContractAddr.lower()) assert_equal(logs[1]["blockHash"], block_a) assert_equal(logs[1]["blockNumber"], epoch_a) assert_equal(logs[1]["transactionHash"], evm_tx_hashes[0].hex()) # assert_equal(logs[1]["logIndex"], '0x1') # assert_equal(logs[1]["transactionIndex"], '0x1') assert_equal(logs[1]["transactionLogIndex"], '0x0') assert_equal(logs[1]["removed"], False) # emitBoth: TestEvent(15) assert_equal(logs[2]["data"], number_to_topic(15)) assert_equal(logs[2]["address"], evmContractAddr.lower()) assert_equal(logs[2]["blockHash"], block_b) assert_equal(logs[2]["blockNumber"], epoch_b) assert_equal(logs[2]["transactionHash"], cfx_tx_hashes[3]) # TODO: should use phantom tx here # assert_equal(logs[2]["logIndex"], '0x0') # assert_equal(logs[2]["transactionIndex"], '0x0') # assert_equal(logs[2]["transactionLogIndex"], '0x0') assert_equal(logs[2]["removed"], False) # emitEVM: TestEvent(16) assert_equal(logs[3]["data"], number_to_topic(16)) assert_equal(logs[3]["address"], evmContractAddr.lower()) assert_equal(logs[3]["blockHash"], block_b) assert_equal(logs[3]["blockNumber"], epoch_b) assert_equal(logs[3]["transactionHash"], evm_tx_hashes[1].hex()) # assert_equal(logs[3]["logIndex"], '0x1') # assert_equal(logs[3]["transactionIndex"], '0x1') assert_equal(logs[3]["transactionLogIndex"], '0x0') assert_equal(logs[3]["removed"], False) # --------------- 2 blocks per epoch --------------- # check EVM events # we expect 4 events: #22, #23, #25, #26 filter = { "topics": [TEST_EVENT_TOPIC], "fromBlock": epoch_e, "toBlock": epoch_e } logs = self.nodes[0].eth_getLogs(filter) assert_equal(len(logs), 4) # emitBoth: TestEvent(22) assert_equal(logs[0]["data"], number_to_topic(22)) assert_equal(logs[0]["address"], evmContractAddr.lower()) assert_equal(logs[0]["blockHash"], block_e) assert_equal(logs[0]["blockNumber"], epoch_e) assert_equal(logs[0]["transactionHash"], cfx_tx_hashes[5]) # TODO: should use phantom tx here # assert_equal(logs[0]["logIndex"], '0x0') # assert_equal(logs[0]["transactionIndex"], '0x0') # assert_equal(logs[0]["transactionLogIndex"], '0x0') assert_equal(logs[0]["removed"], False) # emitEVM: TestEvent(23) assert_equal(logs[1]["data"], number_to_topic(23)) assert_equal(logs[1]["address"], evmContractAddr.lower()) assert_equal(logs[1]["blockHash"], block_e) assert_equal(logs[1]["blockNumber"], epoch_e) assert_equal(logs[1]["transactionHash"], evm_tx_hashes[2].hex()) # assert_equal(logs[1]["logIndex"], '0x1') # assert_equal(logs[1]["transactionIndex"], '0x1') assert_equal(logs[1]["transactionLogIndex"], '0x0') assert_equal(logs[1]["removed"], False) # emitBoth: TestEvent(25) assert_equal(logs[2]["data"], number_to_topic(25)) assert_equal(logs[2]["address"], evmContractAddr.lower()) assert_equal(logs[2]["blockHash"], block_e) assert_equal(logs[2]["blockNumber"], epoch_e) assert_equal(logs[2]["transactionHash"], cfx_tx_hashes[7]) # TODO: should use phantom tx here # assert_equal(logs[2]["logIndex"], '0x2') # assert_equal(logs[2]["transactionIndex"], '0x2') # assert_equal(logs[2]["transactionLogIndex"], '0x0') assert_equal(logs[2]["removed"], False) # emitEVM: TestEvent(26) assert_equal(logs[3]["data"], number_to_topic(26)) assert_equal(logs[3]["address"], evmContractAddr.lower()) assert_equal(logs[3]["blockHash"], block_e) assert_equal(logs[3]["blockNumber"], epoch_e) assert_equal(logs[3]["transactionHash"], evm_tx_hashes[3].hex()) # assert_equal(logs[3]["logIndex"], '0x3') # assert_equal(logs[3]["transactionIndex"], '0x3') assert_equal(logs[3]["transactionLogIndex"], '0x0') assert_equal(logs[3]["removed"], False) # --------------- other fields --------------- # filter by block hash filter = {"topics": [TEST_EVENT_TOPIC], "blockHash": block_c} logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(logs_2, []) filter = { "topics": [TEST_EVENT_TOPIC], "blockHash": block_d } # from EVM perspective, D does not exist assert_raises_rpc_error(None, None, self.nodes[0].eth_getLogs, filter) filter = {"topics": [TEST_EVENT_TOPIC], "blockHash": block_e} logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(logs_2, logs) # filter limit filter = { "topics": [TEST_EVENT_TOPIC], "blockHash": block_e, "limit": 1 } logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(logs_2, [logs[-1]]) # "earliest", "latest" filter = { "topics": [TEST_EVENT_TOPIC], "fromBlock": "earliest", "toBlock": "latest" } logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(len(logs_2), 8) filter = { "topics": [TEST_EVENT_TOPIC], "fromBlock": "earliest", "toBlock": "latest", "limit": 4 } logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(logs_2, logs) # address filter = {"address": confluxContractAddr} logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(logs_2, []) filter = {"address": evmContractAddr} logs_2 = self.nodes[0].eth_getLogs(filter) assert_equal(len(logs_2), 8) self.log.info("Pass") def cross_space_transfer(self, to, value): to = to.replace('0x', '') tx = self.rpc.new_tx( value=value, receiver="0x0888000000000000000000000000000000000006", data=decode_hex(f"0xda8d5daf{to}000000000000000000000000"), nonce=self.rpc.get_nonce(self.cfxAccount), gas=1000000, ) self.rpc.send_tx(tx, True) def deploy_conflux_space(self, bytecode_path): bytecode_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), bytecode_path) assert (os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() tx = self.rpc.new_contract_tx(receiver="", data_hex=bytecode, sender=self.cfxAccount, priv_key=self.cfxPrivkey, storage_limit=20000) assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex()) receipt = self.rpc.get_transaction_receipt(tx.hash_hex()) assert_equal(receipt["outcomeStatus"], "0x0") addr = receipt["contractCreated"] assert_is_hex_string(addr) return addr def deploy_evm_space(self, bytecode_path): bytecode_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), bytecode_path) assert (os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) signed = self.evmAccount.signTransaction({ "to": None, "value": 0, "gasPrice": 1, "gas": 210000, "nonce": nonce, "chainId": 10, "data": bytecode, }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction( signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) self.rpc.generate_block(1) self.rpc.generate_blocks(20, 1) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) addr = receipt["contractAddress"] return addr def construct_evm_tx(self, receiver, data_hex, nonce): signed = self.evmAccount.signTransaction({ "to": receiver, "value": 0, "gasPrice": 1, "gas": 150000, "nonce": nonce, "chainId": 10, "data": data_hex, }) tx = [ nonce, 1, 150000, bytes.fromhex(receiver.replace('0x', '')), 0, bytes.fromhex(data_hex.replace('0x', '')), signed["v"], signed["r"], signed["s"] ] return tx, signed["hash"]
def run_test(self): time.sleep(3) ip = self.nodes[0].ip port = self.nodes[0].ethrpcport self.w3 = Web3(Web3.HTTPProvider(f'http://{ip}:{port}/')) assert_equal(self.w3.isConnected(), True) account = self.w3.eth.account.privateKeyToAccount( '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709' ) sender = account.address self.cross_space_transfer(sender, 1 * 10**18) assert_equal(1 * 10**18, self.w3.eth.get_balance(sender)) self.test_deploy_1820() # Send eip-155 transaction receiver = Web3.toChecksumAddress( "10000000000000000000000000000000000000aa") signed = account.signTransaction({ "to": receiver, "value": 1 * 10**17, "gasPrice": 1, "gas": 21000, "nonce": 0, "chainId": 10 }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction( signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) client = RpcClient(self.nodes[0]) client.generate_block(1) client.generate_blocks(10) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) # Send pre eip-155 transaction signed = account.signTransaction({ "to": receiver, "value": 1 * 10**17, "gasPrice": 1, "gas": 21000, "nonce": 1 }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction( signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) client.generate_block(1) client.generate_blocks(10) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) assert_equal(2 * 10**17, self.w3.eth.get_balance(receiver)) assert_equal(8 * 10**17 - 42000, self.w3.eth.get_balance(sender)) # Send to transaction mapped_sender = keccak_256(self.genesis_addr).digest()[-20:] receiver = Web3.toChecksumAddress(mapped_sender.hex()) signed = account.signTransaction({ "to": receiver, "value": 2 * 10**17, "gasPrice": 1, "gas": 21000, "nonce": 2 }) self.w3.eth.sendRawTransaction(signed["rawTransaction"]) client = RpcClient(self.nodes[0]) client.generate_block(1) client.generate_blocks(10) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) assert_equal(2 * 10**17, self.w3.eth.get_balance(mapped_sender)) # Withdraw transaction self.cross_space_withdraw(1 * 10**17) assert_equal(1 * 10**17, self.w3.eth.get_balance(mapped_sender)) # Send transaction with large chain-id, should not panic. signed = account.signTransaction({ "to": receiver, "value": 1 * 10**17, "gasPrice": 1, "gas": 21000, "nonce": 3, "chainId": 2**33 }) assert_raises(ValueError, self.w3.eth.sendRawTransaction, signed["rawTransaction"]) self.nodes[0].stop()
class CrossSpaceLogFilteringTest(ConfluxTestFramework): def set_test_params(self): self.num_nodes = 1 self.conf_parameters["evm_chain_id"] = str(10) def setup_network(self): self.add_nodes(self.num_nodes) self.start_node(0, ["--archive"]) self.rpc = RpcClient(self.nodes[0]) self.cfxPrivkey = default_config['GENESIS_PRI_KEY'] self.cfxAccount = self.rpc.GENESIS_ADDR print(f'Using Conflux account {self.cfxAccount}') ip = self.nodes[0].ip port = self.nodes[0].rpcport self.w3 = Web3(Web3.HTTPProvider(f'http://{ip}:{port}/')) assert_equal(self.w3.isConnected(), True) def run_test(self): # initialize EVM account self.evmAccount = self.w3.eth.account.privateKeyToAccount( '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' ) print(f'Using EVM account {self.evmAccount.address}') self.cross_space_transfer(self.evmAccount.address, 1 * 10**18) assert_equal(self.nodes[0].eth_getBalance(self.evmAccount.address), hex(1 * 10**18)) # deploy Conflux space contract confluxContractAddr = self.deploy_conflux_space(CONFLUX_CONTRACT_PATH) print(f'Conflux contract: {confluxContractAddr}') # deploy EVM space contract evmContractAddr = self.deploy_evm_space(EVM_CONTRACT_PATH) print(f'EVM contract: {evmContractAddr}') # #1: call emitConflux(1) # this will emit 1 event in the Conflux space data_hex = encode_hex_0x( keccak(b"emitConflux(uint256)"))[:10] + encode_u256(1) receipt = self.call_conflux_space(confluxContractAddr, data_hex) assert_equal(len(receipt["logs"]), 1) assert_equal(receipt["logs"][0]["data"], number_to_topic(1)) # TestEvent(1) # #2: call emitBoth(2) # this will emit 2 events in the Conflux space (our contract + internal contract) and 1 event in the EVM space data_hex = encode_hex_0x( keccak(b"emitBoth(uint256,bytes20)"))[:10] + encode_u256( 2) + encode_bytes20(evmContractAddr.replace('0x', '')) receipt = self.call_conflux_space(confluxContractAddr, data_hex) assert_equal(len(receipt["logs"]), 2) assert_equal(receipt["logs"][0]["data"], number_to_topic(2)) # TestEvent(2) # NOTE: EVM-space events are not returned here # #3: call emitEVM(3) # this will emit 1 event in the EVM space data_hex = encode_hex_0x( keccak(b"emitEVM(uint256)"))[:10] + encode_u256(3) receipt = self.call_evm_space(evmContractAddr, data_hex) assert_equal(len(receipt["logs"]), 1) assert_equal(receipt["logs"][0]["data"], number_to_topic(3)) # TestEvent(3) # NOTE: EVM-space events are not returned here # check Conflux events # we expect two events from #1 and #2 filter = Filter(topics=[TEST_EVENT_TOPIC], from_epoch="earliest", to_epoch="latest_state") logs = self.rpc.get_logs(filter) assert_equal(len(logs), 2) assert_equal(logs[0]["data"], number_to_topic(1)) # TestEvent(1) assert_equal(logs[1]["data"], number_to_topic(2)) # TestEvent(2) # check EVM events # we expect two events from #2 and #3 filter = { "topics": [TEST_EVENT_TOPIC], "fromBlock": "earliest", "toBlock": "latest" } logs = self.nodes[0].eth_getLogs(filter) assert_equal(len(logs), 2) assert_equal(logs[0]["data"], number_to_topic(2)) # TestEvent(2) assert_equal(logs[0]["address"], evmContractAddr.lower()) assert_equal(logs[0]["removed"], False) assert_equal(logs[1]["data"], number_to_topic(3)) # TestEvent(3) assert_equal(logs[1]["address"], evmContractAddr.lower()) assert_equal(logs[1]["removed"], False) # TODO(thegaram): add more detailed tests once we have more control over block production # - events in pivot and non-pivot blocks # - log.blockHash and log.blockNumber should correspond to pivot block # - logIndex, transactionIndex, transactionLogIndex self.log.info("Pass") def cross_space_transfer(self, to, value): to = to.replace('0x', '') tx = self.rpc.new_tx( value=value, receiver="0x0888000000000000000000000000000000000006", data=decode_hex(f"0xda8d5daf{to}000000000000000000000000"), nonce=self.rpc.get_nonce(self.cfxAccount), gas=1000000, ) self.rpc.send_tx(tx, True) def deploy_conflux_space(self, bytecode_path): bytecode_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), bytecode_path) assert (os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() tx = self.rpc.new_contract_tx(receiver="", data_hex=bytecode, sender=self.cfxAccount, priv_key=self.cfxPrivkey, storage_limit=20000) assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex()) receipt = self.rpc.get_transaction_receipt(tx.hash_hex()) assert_equal(receipt["outcomeStatus"], "0x0") addr = receipt["contractCreated"] assert_is_hex_string(addr) return addr def call_conflux_space(self, receiver, data_hex): tx = self.rpc.new_contract_tx( receiver=receiver, data_hex=data_hex, sender=self.cfxAccount, priv_key=self.cfxPrivkey, ) assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex()) receipt = self.rpc.get_transaction_receipt(tx.hash_hex()) assert_equal(receipt["outcomeStatus"], "0x0") return receipt def deploy_evm_space(self, bytecode_path): bytecode_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), bytecode_path) assert (os.path.isfile(bytecode_file)) bytecode = open(bytecode_file).read() nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) signed = self.evmAccount.signTransaction({ "to": None, "value": 0, "gasPrice": 1, "gas": 210000, "nonce": nonce, "chainId": 10, "data": bytecode, }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction( signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) self.rpc.generate_block(1) self.rpc.generate_blocks(20, 1) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) addr = receipt["contractAddress"] return addr def call_evm_space(self, to, data): nonce = self.w3.eth.getTransactionCount(self.evmAccount.address) signed = self.evmAccount.signTransaction({ "to": to, "value": 0, "gasPrice": 1, "gas": 150000, "nonce": nonce, "chainId": 10, "data": data, }) tx_hash = signed["hash"] return_tx_hash = self.w3.eth.sendRawTransaction( signed["rawTransaction"]) assert_equal(tx_hash, return_tx_hash) self.rpc.generate_block(1) self.rpc.generate_blocks(20, 1) receipt = self.w3.eth.waitForTransactionReceipt(tx_hash) assert_equal(receipt["status"], 1) return receipt