Esempio n. 1
0
class Issue2235Test(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

    def setup_network(self):
        self.add_nodes(self.num_nodes)
        self.start_node(0, ["--archive"])
        self.rpc = RpcClient(self.nodes[0])

    def run_test(self):

        #                      ---
        #                  .- | A | <--- ...
        #           ---    |   ---
        # ... <--- | 0 | <-*
        #           ---    |   ---
        #                  .- | B | <--- ...
        #                      ---

        block_number_0 = int(self.rpc.block_by_epoch("latest_mined")['epochNumber'], 0)
        block_0 = self.rpc.block_by_epoch("latest_mined")['hash']

        block_a = self.rpc.generate_custom_block(parent_hash = block_0, referee = [], txs = [])
        block_b = self.rpc.generate_custom_block(parent_hash = block_0, referee = [], txs = [])

        # create pivot chain from 'A', make sure 'A' is executed
        parent_hash = block_a

        for _ in range(5):
            block = self.rpc.generate_custom_block(parent_hash = parent_hash, referee = [], txs = [])
            parent_hash = block

        block_after_0 = self.rpc.block_by_block_number(hex(block_number_0 + 1))["hash"]
        assert_equal(block_a, block_after_0)

        # switch pivot chain to 'B', make sure 'B' is executed
        parent_hash = block_b

        for _ in range(6):
            block = self.rpc.generate_custom_block(parent_hash = parent_hash, referee = [], txs = [])
            parent_hash = block

        block_after_0 = self.rpc.block_by_block_number(hex(block_number_0 + 1))["hash"]
        assert_equal(block_b, block_after_0)

        # switch pivot chain back to 'A', make sure 'A' is executed
        parent_hash = block_a

        for _ in range(7):
            block = self.rpc.generate_custom_block(parent_hash = parent_hash, referee = [], txs = [])
            parent_hash = block

        block_after_0 = self.rpc.block_by_block_number(hex(block_number_0 + 1))["hash"]
        assert_equal(block_a, block_after_0) # <<< (#2235)

        self.log.info("Pass")
Esempio n. 2
0
class Issue2229(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

        self.conf_parameters["generate_tx_period_us"] = "100000"
        self.conf_parameters["adaptive_weight_beta"] = "1"
        self.conf_parameters["timer_chain_block_difficulty_ratio"] = "3"
        self.conf_parameters["timer_chain_beta"] = "20"
        self.conf_parameters["era_epoch_count"] = "100"
        self.conf_parameters["dev_snapshot_epoch_count"] = "25"

    def setup_network(self):
        self.add_nodes(self.num_nodes)
        self.start_node(0, ["--archive"])
        self.rpc = RpcClient(self.nodes[0])

    def run_test(self):
        # check in current era
        block = self.rpc.block_by_epoch("latest_mined")
        assert_ne(block["blockNumber"], None)

        # create a few new eras
        parent_hash = block["hash"]

        for _ in range(500):
            parent_hash = self.rpc.generate_custom_block(parent_hash = parent_hash, referee = [], txs = [])
            parent_hash

        # check in old era
        block = self.rpc.block_by_hash(block["hash"])
        assert_ne(block["blockNumber"], None) # <<

        self.log.info("Pass")
Esempio n. 3
0
class Issue2159Test(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

        self.conf_parameters = {
            # make `cfx_getEpochReceipts` available through ws
            "public_rpc_apis": "\"cfx,debug\"",

            # limit max response payload size
            "jsonrpc_ws_max_payload_bytes": 1024,
        }

    def setup_network(self):
        self.add_nodes(self.num_nodes)
        self.start_node(FULLNODE, ["--archive"])

        # set up RPC over HTTP
        node = self.nodes[FULLNODE]
        self.rpc = RpcClient(node)

        # set up RPC over WS
        url = pubsub_url(node.index, node.rpchost, node.pubsubport)
        self.ws = WebSocketsClient(block_on(websockets.connect(url)))

        # wait for phase changes to complete
        self.nodes[FULLNODE].wait_for_phase(["NormalSyncPhase"])

    def run_test(self):
        # generate block with many transactions
        parent_hash = self.rpc.block_by_epoch("latest_mined")['hash']
        start_nonce = self.rpc.get_nonce(self.rpc.GENESIS_ADDR)
        txs = [self.rpc.new_tx(nonce=start_nonce + ii) for ii in range(0, 100)]
        hash = self.rpc.generate_custom_block(parent_hash=parent_hash,
                                              referee=[],
                                              txs=txs)
        epoch = self.rpc.block_by_hash(hash)["epochNumber"]

        # make sure block is executed
        self.rpc.generate_empty_blocks(5)

        # getting epoch receipts should result in error
        try:
            resp = block_on(
                self.ws.send(Request("cfx_getEpochReceipts", epoch)))
            assert False, "cfx_getEpochReceipts request should have failed"
        except ReceivedErrorResponseError as e:
            self.log.info(e.response)
            assert e.response.data.startswith("\"Oversized payload")
        except Exception as e:
            assert False, f"unexpected error: {e}"

        # this should succeed
        # resp = self.rpc.node.cfx_getEpochReceipts(epoch)

        self.log.info("Pass")
Esempio n. 4
0
    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_test(self):
        num_blocks = 200
        checkpoint_epoch = 100

        # Generate checkpoint on node[0]
        client = RpcClient(self.nodes[0])
        self.genesis_nonce = client.get_nonce(client.GENESIS_ADDR)
        for _ in range(num_blocks):
            txs = self._generate_txs(0, random.randint(5, 10))
            client.generate_block_with_fake_txs(txs)

        # 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
        # FIXME: we minus REWARD_EPOCH_COUNT here as a workaround.
        # FIXME: after the state boundary is implemented in consensus,
        # FIXME: this workaround should be removed.
        for i in range(1, checkpoint_epoch - 11):
            try:
                client.get_balance(client.GENESIS_ADDR, client.EPOCH_NUM(i))
                raise AssertionError(
                    "should not have 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, client.epoch_number() - 3):
            client.get_balance(client.GENESIS_ADDR, client.EPOCH_NUM(i))
Esempio n. 6
0
    def run_test(self):
        client = RpcClient(self.nodes[0])
        self.genesis = client.block_by_epoch("0x0", False)["hash"]

        self.test_same_ip_replace_always(client)
        self.test_subnet_quota(client)
Esempio n. 7
0
class LogFilteringTest(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

    def setup_network(self):
        self.setup_nodes()

    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        self.rpc = RpcClient(self.nodes[0])

        # apply filter, we expect no logs
        filter = Filter()
        result = self.rpc.get_logs(filter)
        assert_equal(result, [])

        # deploy 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()
        _, contractAddr = self.deploy_contract(sender, priv_key, bytecode)

        # apply filter, we expect a single log with 2 topics
        filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        logs0 = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs0)
        assert_equal(len(logs0), 1)

        assert_equal(len(logs0[0]["topics"]), 2)
        assert_equal(logs0[0]["topics"][0], CONSTRUCTED_TOPIC)
        assert_equal(logs0[0]["topics"][1], self.address_to_topic(sender))
        assert_equal(logs0[0]["data"], self.address_to_topic(sender))

        # call method
        receipt = self.call_contract(sender, priv_key, contractAddr, encode_hex_0x(keccak(b"foo()")), storage_limit=64)

        # apply filter, we expect two logs with 2 and 3 topics respectively
        filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        logs1 = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs1)
        assert_equal(len(logs1), 2)
        assert_equal(logs1[0], logs0[0])

        assert_equal(len(logs1[1]["topics"]), 3)
        assert_equal(logs1[1]["topics"][0], FOO_TOPIC)
        assert_equal(logs1[1]["topics"][1], self.address_to_topic(sender))
        assert_equal(logs1[1]["topics"][2], self.number_to_topic(1))

        # apply filter for specific block, we expect a single log with 3 topics
        filter = Filter(block_hashes=[receipt["blockHash"]])
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 1)
        assert_equal(logs[0], logs1[1])

        # call many times
        for ii in range(2, NUM_CALLS):
            self.call_contract(sender, priv_key, contractAddr, encode_hex_0x(keccak(b"foo()")), storage_limit=0)

        # apply filter, we expect NUM_CALLS log entries with increasing uint32 fields
        filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS)

        for ii in range(2, NUM_CALLS):
            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], FOO_TOPIC)
            assert(logs[ii]["topics"][1] == self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2], self.number_to_topic(ii))

        # apply filter for specific topics
        filter = Filter(topics=[CONSTRUCTED_TOPIC])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 1)

        filter = Filter(topics=[FOO_TOPIC])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS - 1)

        filter = Filter(topics=[None, self.address_to_topic(sender)])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS)

        # find logs with `FOO_TOPIC` as 1st topic and `3` or `4` as 3rd topic
        filter = Filter(topics=[FOO_TOPIC, None, [self.number_to_topic(3), self.number_to_topic(4)]])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 2)

        # apply filter with limit
        filter = Filter(limit=hex(NUM_CALLS // 2))
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS // 2)

        # apply filter with offset
        filter = Filter(offset=hex(NUM_CALLS // 4))
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 3 * NUM_CALLS // 4)

        # apply filter for specific contract address
        _, contractAddr2 = self.deploy_contract(sender, priv_key, bytecode)

        filter = Filter(address=[contractAddr])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS)

        filter = Filter(address=[contractAddr2])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 1)

        # apply filter to very first epoch, we expect no logs
        filter = Filter(from_epoch="earliest", to_epoch="earliest")
        result = self.rpc.get_logs(filter)
        assert_equal(result, [])

        # generate two blocks with `NUM_CALLS` transactions in each;
        # transactions will generate 2 logs each
        parent_hash = self.rpc.block_by_epoch("latest_mined")['hash']
        start_nonce = self.rpc.get_nonce(sender)

        txs1 = [self.rpc.new_contract_tx(receiver=contractAddr, data_hex=encode_hex_0x(keccak(b"bar()")), sender=sender, priv_key=priv_key, storage_limit=64, nonce = start_nonce + ii) for ii in range(0, NUM_CALLS)]
        block_hash_1 = self.rpc.generate_custom_block(parent_hash = parent_hash, referee = [], txs = txs1)
        epoch_1 = self.rpc.block_by_hash(block_hash_1)["epochNumber"]

        txs2 = [self.rpc.new_contract_tx(receiver=contractAddr, data_hex=encode_hex_0x(keccak(b"bar()")), sender=sender, priv_key=priv_key, storage_limit=64, nonce = start_nonce + NUM_CALLS + ii) for ii in range(0, NUM_CALLS)]
        block_hash_2 = self.rpc.generate_custom_block(parent_hash = block_hash_1, referee = [], txs = txs2)
        epoch_2 = self.rpc.block_by_hash(block_hash_2)["epochNumber"]

        txs = txs1
        txs.extend(txs2)

        # blocks not executed yet, filtering should fail
        # filter = Filter(block_hashes=[block_hash_1, block_hash_2], topics=[BAR_TOPIC])
        # assert_raises_rpc_error(None, None, self.rpc.get_logs, filter)

        # generate some more blocks to ensure our two blocks are executed
        self.rpc.generate_blocks(10)

        # filtering for these two blocks should return logs in correct order
        filter = Filter(block_hashes=[block_hash_1, block_hash_2], topics=[BAR_TOPIC])
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), 4 * NUM_CALLS)

        log_index = 0
        transaction_index = 0
        transaction_log_index = 0

        for ii in range(0, 4 * NUM_CALLS):
            assert_equal(logs[ii]["address"], contractAddr)
            assert_equal(logs[ii]["blockHash"], block_hash_1 if ii < 2 * NUM_CALLS else block_hash_2)
            assert_equal(logs[ii]["epochNumber"], epoch_1 if ii < 2 * NUM_CALLS else epoch_2)
            assert_equal(logs[ii]["transactionHash"], txs[ii // 2].hash_hex())

            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], BAR_TOPIC)
            assert_equal(logs[ii]["topics"][1], self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2], self.number_to_topic(ii))

            # logIndex:
            # 0, 1, 2, 3, 4, 6, 7, 8, ..., 2 * NUM_CALLS, 0, 1, 2, ...
            assert_equal(logs[ii]["logIndex"], hex(log_index % (2 * NUM_CALLS)))
            log_index += 1

            # transactionIndex:
            # 0, 0, 1, 1, 2, 2, 3, 3, ..., NUM_CALLS, 0, 0, 1, 1, ...
            assert_equal(logs[ii]["transactionIndex"], hex((transaction_index // 2) % NUM_CALLS))
            transaction_index += 1

            # transactionLogIndex:
            # 0, 1, 0, 1, 0, 1, 0, 1, ...
            assert_equal(logs[ii]["transactionLogIndex"], hex(transaction_log_index % 2))
            transaction_log_index += 1

        # block hash order should not affect log order
        filter = Filter(block_hashes=[block_hash_2, block_hash_1], topics=[BAR_TOPIC])
        logs2 = self.rpc.get_logs(filter)
        assert_equal(logs, logs2)

        # given a limit, we should receive the _last_ few logs
        filter = Filter(block_hashes=[block_hash_1, block_hash_2], limit = hex(3 * NUM_CALLS + NUM_CALLS // 2), topics=[BAR_TOPIC])
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), 3 * NUM_CALLS + NUM_CALLS // 2)

        for ii in range(0, 3 * NUM_CALLS + NUM_CALLS // 2):
            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], BAR_TOPIC)
            assert_equal(logs[ii]["topics"][1], self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2], self.number_to_topic(NUM_CALLS // 2 + ii))

        # given an offset and a limit, we should receive the corresponding logs
        filter = Filter(block_hashes=[block_hash_1, block_hash_2], offset = hex(NUM_CALLS // 2), limit = hex(NUM_CALLS // 2), topics=[BAR_TOPIC])
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), NUM_CALLS // 2)

        for ii in range(0, NUM_CALLS // 2):
            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], BAR_TOPIC)
            assert_equal(logs[ii]["topics"][1], self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2], self.number_to_topic(3 * NUM_CALLS + ii))

        filter = Filter(from_epoch = epoch_1, to_epoch = epoch_2, offset = hex(NUM_CALLS // 2), limit = hex(NUM_CALLS // 2), topics=[BAR_TOPIC])
        logs2 = self.rpc.get_logs(filter)
        assert_equal(logs, logs2)

        # test paging use case
        BATCH_SIZE = 7

        filter = Filter(block_hashes=[block_hash_1, block_hash_2], topics=[BAR_TOPIC])
        all_logs = self.rpc.get_logs(filter)

        collected_logs = []
        offset = 0

        while True:
            filter = Filter(block_hashes=[block_hash_1, block_hash_2], offset = hex(offset), limit = hex(BATCH_SIZE), topics=[BAR_TOPIC])
            logs = self.rpc.get_logs(filter)
            if len(logs) == 0: break
            collected_logs = logs + collected_logs
            offset += BATCH_SIZE

        assert_equal(collected_logs, all_logs)

        # get-logs-filter-max-epoch-range should limit the number of epochs queried.
        self.stop_node(0)
        self.start_node(0, ["--get-logs-filter-max-epoch-range", "16"])
        filter = Filter(from_epoch="0x0", to_epoch="0x0f", topics=[BAR_TOPIC])
        # should not raise error
        self.rpc.get_logs(filter)
        filter = Filter(from_epoch="0x0", to_epoch="0x10", topics=[BAR_TOPIC])
        assert_raises_rpc_error(None, None, self.rpc.get_logs, filter)

        self.log.info("Pass")

    def address_to_topic(self, address):
        return "0x" + address[2:].zfill(64)

    def number_to_topic(self, number):
        return "0x" + ("%x" % number).zfill(64)

    def deploy_contract(self, sender, priv_key, data_hex):
        c0 = self.rpc.get_collateral_for_storage(sender)
        tx = self.rpc.new_contract_tx(receiver="", data_hex=data_hex, sender=sender, priv_key=priv_key, storage_limit=512)
        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")
        address = receipt["contractCreated"]
        c1 = self.rpc.get_collateral_for_storage(sender)
        assert_equal(c1 - c0, 512 * COLLATERAL_UNIT_IN_DRIP)
        assert_is_hex_string(address)
        return receipt, address

    def call_contract(self, sender, priv_key, contract, data_hex, storage_limit):
        c0 = self.rpc.get_collateral_for_storage(sender)
        tx = self.rpc.new_contract_tx(receiver=contract, data_hex=data_hex, sender=sender, priv_key=priv_key, storage_limit=storage_limit)
        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")
        c1 = self.rpc.get_collateral_for_storage(sender)
        assert_equal(c1 - c0, storage_limit * COLLATERAL_UNIT_IN_DRIP)
        return receipt

    def assert_response_format_correct(self, response):
        assert_equal(type(response), list)
        for log in response:
            self.assert_log_format_correct(log)

    def assert_log_format_correct(self, log):
        assert_is_hex_string(log["address"])
        assert_is_hex_string(log["epochNumber"])
        assert_is_hex_string(log["logIndex"])
        assert_is_hex_string(log["transactionIndex"])
        assert_is_hex_string(log["transactionLogIndex"])

        assert_is_hash_string(log["blockHash"])
        assert_is_hash_string(log["transactionHash"])

        assert_equal(type(log["topics"]), list)
Esempio n. 8
0
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"]
    def run_test(self):
        num_blocks = 200
        snapshot_epoch = 150

        # Generate checkpoint on node[0]
        archive_node_client = RpcClient(self.nodes[0])
        self.genesis_nonce = archive_node_client.get_nonce(
            archive_node_client.GENESIS_ADDR)
        blocks_in_era = []
        for i in range(num_blocks):
            txs = self._generate_txs(0, random.randint(50, 100))
            block_hash = archive_node_client.generate_block_with_fake_txs(txs)
            if i >= snapshot_epoch:
                blocks_in_era.append(block_hash)
        sync_blocks(self.nodes[:-1])
        self.log.info("All archive nodes synced")

        # Start node[full_node_index] as full node to sync checkpoint
        # Change phase from CatchUpSyncBlockHeader to CatchUpCheckpoint
        # only when there is at least one connected peer.
        full_node_index = self.num_nodes - 1
        self.start_node(full_node_index, ["--full"], phase_to_wait=None)
        for i in range(self.num_nodes - 1):
            connect_nodes(self.nodes, full_node_index, i)

        self.log.info("Wait for full node to sync, index=%d", full_node_index)
        self.nodes[full_node_index].wait_for_phase(["NormalSyncPhase"],
                                                   wait_time=240)

        sync_blocks(self.nodes, sync_count=False)

        full_node_client = RpcClient(self.nodes[full_node_index])

        # At epoch 1, block header exists while body not synchronized
        try:
            print(
                full_node_client.block_by_epoch(full_node_client.EPOCH_NUM(1)))
        except ReceivedErrorResponseError as e:
            assert 'Internal error' == e.response.message

        # There is no state from epoch 1 to snapshot_epoch
        # Note, state of genesis epoch always exists
        assert full_node_client.epoch_number() >= snapshot_epoch
        wait_until(
            lambda: full_node_client.epoch_number() == archive_node_client.
            epoch_number() and full_node_client.epoch_number("latest_state") ==
            archive_node_client.epoch_number("latest_state"))
        # We have snapshot_epoch for state execution but
        # don't offer snapshot_epoch for Rpc clients.
        for i in range(1, snapshot_epoch + 1):
            try:
                full_node_client.get_balance(full_node_client.GENESIS_ADDR,
                                             full_node_client.EPOCH_NUM(i))
                raise AssertionError(
                    "should not have 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

        # Wait for execution to complete.
        time.sleep(1)

        # There should be states after checkpoint
        for i in range(snapshot_epoch + 1,
                       full_node_client.epoch_number() - 3):
            full_balance = full_node_client.get_balance(
                full_node_client.GENESIS_ADDR, full_node_client.EPOCH_NUM(i))
            archive_balance = archive_node_client.get_balance(
                archive_node_client.GENESIS_ADDR,
                archive_node_client.EPOCH_NUM(i))
            assert_equal(full_balance, archive_balance)

        # Blocks within execution defer (5 epochs) and reward_defer (12 epochs) do not have state_valid
        available_blocks = blocks_in_era[:-17]
        assert_blocks_valid(self.nodes[:-1], available_blocks)
        assert_blocks_valid(self.nodes[-1:], available_blocks)
Esempio n. 10
0
class LogFilteringTest(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1
        self.conf_parameters["dev_snapshot_epoch_count"] = str(
            SNAPSHOT_EPOCH_COUNT)

    def setup_network(self):
        self.add_nodes(self.num_nodes)
        self.start_node(0, ["--archive"])
        self.rpc = RpcClient(self.nodes[0])

    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        # 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()
        tx = self.rpc.new_contract_tx(receiver="",
                                      data_hex=bytecode,
                                      sender=sender,
                                      priv_key=priv_key,
                                      storage_limit=20000)
        assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex())
        receipt = self.rpc.get_transaction_receipt(tx.hash_hex())
        contractAddr = receipt["contractCreated"]
        assert_is_hex_string(contractAddr)

        #                              ---                        ---
        #           .-----------------| D |.... .----------------| H |.....
        #           V                  ---    | V                 ---     |
        #          ---      ---      ---      ---      ---      ---      ---
        # ... <-- | A | <- | B | <- | C | <- | E | <- | F | <- | G | <- | I | <- ...
        #          ---      ---      ---      ---      ---      ---      ---
        #
        #                 A --- B --- C --- D --- E --- F --- G --- H --- I
        # block number    0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |
        # epoch number    0  |  1  |  2  |     3     |  4  |  5  |     6     |

        start_nonce = self.rpc.get_nonce(self.rpc.GENESIS_ADDR)

        txs = [
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 0,
                                     sender=sender,
                                     priv_key=priv_key,
                                     storage_limit=64),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 1,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 2,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 3,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 4,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 5,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 6,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 7,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 8,
                                     sender=sender,
                                     priv_key=priv_key),
        ]

        block_0 = self.rpc.block_by_epoch("latest_mined")['hash']
        epoch_0 = int(self.rpc.block_by_hash(block_0)['epochNumber'], 0)
        block_number_0 = int(self.rpc.block_by_hash(block_0)['blockNumber'], 0)

        block_a = self.rpc.generate_custom_block(parent_hash=block_0,
                                                 referee=[],
                                                 txs=[txs[0]])
        block_b = self.rpc.generate_custom_block(parent_hash=block_a,
                                                 referee=[],
                                                 txs=[txs[1]])
        block_c = self.rpc.generate_custom_block(parent_hash=block_b,
                                                 referee=[],
                                                 txs=[txs[2]])
        block_d = self.rpc.generate_custom_block(parent_hash=block_a,
                                                 referee=[],
                                                 txs=[txs[3]])
        block_e = self.rpc.generate_custom_block(parent_hash=block_c,
                                                 referee=[block_d],
                                                 txs=[txs[4]])
        block_f = self.rpc.generate_custom_block(parent_hash=block_e,
                                                 referee=[],
                                                 txs=[txs[5]])
        block_g = self.rpc.generate_custom_block(parent_hash=block_f,
                                                 referee=[],
                                                 txs=[txs[6]])
        block_h = self.rpc.generate_custom_block(parent_hash=block_e,
                                                 referee=[],
                                                 txs=[txs[7]])
        block_i = self.rpc.generate_custom_block(parent_hash=block_g,
                                                 referee=[block_h],
                                                 txs=[txs[8]])

        # make sure transactions have been executed
        parent_hash = block_i

        for _ in range(5):
            block = self.rpc.generate_custom_block(parent_hash=parent_hash,
                                                   referee=[],
                                                   txs=[])
            parent_hash = block

        # check logs
        block_number_a = int(self.rpc.block_by_hash(block_a)['blockNumber'], 0)
        block_number_i = int(self.rpc.block_by_hash(block_i)['blockNumber'], 0)

        self.check_logs(block_number_a, block_number_i, sender)

        # check logs in old era
        for _ in range(10 * SNAPSHOT_EPOCH_COUNT):
            block = self.rpc.generate_custom_block(parent_hash=parent_hash,
                                                   referee=[],
                                                   txs=[])
            parent_hash = block

        self.check_logs(block_number_a, block_number_i, sender)

        self.log.info("Pass")

    def check_logs(self, first_block_number, last_block_number, sender):
        # check the number of logs returned for different ranges
        for from_block in range(first_block_number, last_block_number + 1):
            for to_block in range(from_block, last_block_number + 1):
                filter = Filter(from_block=hex(from_block),
                                to_block=hex(to_block))
                logs = self.rpc.get_logs(filter)
                assert_equal(len(logs), to_block - from_block + 1)

        # check the event parameters in each block
        for block_number in range(first_block_number, last_block_number + 1):
            logs = self.rpc.get_logs(
                Filter(from_block=hex(block_number),
                       to_block=hex(block_number)))
            assert_equal(len(logs), 1)
            assert_equal(logs[0]["topics"][0], FOO_TOPIC)
            assert_equal(logs[0]["topics"][1], address_to_topic(sender))
            assert_equal(
                logs[0]["topics"][2],
                number_to_topic(block_number - first_block_number + 1))
Esempio n. 11
0
class Issue2260(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

    def setup_network(self):
        self.add_nodes(self.num_nodes)
        self.start_node(0, ["--archive"])
        self.rpc = RpcClient(self.nodes[0])

    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        # 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()
        tx = self.rpc.new_contract_tx(receiver="",
                                      data_hex=bytecode,
                                      sender=sender,
                                      priv_key=priv_key,
                                      storage_limit=20000)
        assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex())
        receipt = self.rpc.get_transaction_receipt(tx.hash_hex())
        contractAddr = receipt["contractCreated"]
        assert_is_hex_string(contractAddr)

        #                              ---
        #           .-----------------| D |....
        #           V                  ---    |
        #          ---      ---      ---      ---
        # ... <-- | A | <- | B | <- | C | <- | E | <- ...
        #          ---      ---      ---      ---
        #
        #                 A --- B --- C --- D --- E
        # block number    0  |  1  |  2  |  3  |  4  |
        # epoch number    0  |  1  |  2  |     3     |

        start_nonce = self.rpc.get_nonce(self.rpc.GENESIS_ADDR)

        txs = [
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 0,
                                     sender=sender,
                                     priv_key=priv_key,
                                     storage_limit=64),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 1,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 2,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     nonce=start_nonce + 3,
                                     sender=sender,
                                     priv_key=priv_key),
        ]

        block_0 = self.rpc.block_by_epoch("latest_mined")['hash']
        epoch_0 = int(self.rpc.block_by_hash(block_0)['epochNumber'], 0)
        block_number_0 = int(self.rpc.block_by_hash(block_0)['blockNumber'], 0)

        block_a = self.rpc.generate_custom_block(parent_hash=block_0,
                                                 referee=[],
                                                 txs=[])
        block_b = self.rpc.generate_custom_block(parent_hash=block_a,
                                                 referee=[],
                                                 txs=[])
        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=txs[0:2])
        block_e = self.rpc.generate_custom_block(parent_hash=block_c,
                                                 referee=[block_d],
                                                 txs=txs[2:4])

        # 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

        # check logs
        block_number_a = int(self.rpc.block_by_hash(block_a)['blockNumber'], 0)
        block_number_d = int(self.rpc.block_by_hash(block_d)['blockNumber'], 0)

        filter = Filter(from_block=hex(block_number_a),
                        to_block=hex(block_number_d),
                        offset=hex(0),
                        limit=hex(1))
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), 1)
        assert_equal(logs[0]["topics"][2], number_to_topic(2))

        filter = Filter(from_block=hex(block_number_a),
                        to_block=hex(block_number_d),
                        offset=hex(1),
                        limit=hex(1))
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), 1)
        assert_equal(logs[0]["topics"][2], number_to_topic(1))

        filter = Filter(from_block=hex(block_number_a),
                        to_block=hex(block_number_d),
                        offset=hex(0),
                        limit=hex(2))
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), 2)
        assert_equal(logs[0]["topics"][2], number_to_topic(1))
        assert_equal(logs[1]["topics"][2], number_to_topic(2))

        self.log.info("Pass")
Esempio n. 12
0
class LogFilteringTest(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

    def setup_network(self):
        self.setup_nodes()

    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        self.rpc = RpcClient(self.nodes[0])

        # apply filter, we expect no logs
        filter = Filter()
        result = self.rpc.get_logs(filter)
        assert_equal(result, [])

        # deploy 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()
        _, contractAddr = self.deploy_contract(sender, priv_key, bytecode)

        # apply filter, we expect a single log with 2 topics
        filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        logs0 = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs0)
        assert_equal(len(logs0), 1)

        assert_equal(len(logs0[0]["topics"]), 2)
        assert_equal(logs0[0]["topics"][0], CONSTRUCTED_TOPIC)
        assert_equal(logs0[0]["topics"][1], self.address_to_topic(sender))
        assert_equal(logs0[0]["data"], self.address_to_topic(sender))

        # call method
        receipt = self.call_contract(sender,
                                     priv_key,
                                     contractAddr,
                                     encode_hex_0x(keccak(b"foo()")),
                                     storage_limit=64)

        # apply filter, we expect two logs with 2 and 3 topics respectively
        filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        logs1 = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs1)
        assert_equal(len(logs1), 2)
        assert_equal(logs1[0], logs0[0])

        assert_equal(len(logs1[1]["topics"]), 3)
        assert_equal(logs1[1]["topics"][0], CALLED_TOPIC)
        assert_equal(logs1[1]["topics"][1], self.address_to_topic(sender))
        assert_equal(logs1[1]["topics"][2], self.number_to_topic(1))

        # apply filter for specific block, we expect a single log with 3 topics
        filter = Filter(block_hashes=[receipt["blockHash"]])
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 1)
        assert_equal(logs[0], logs1[1])

        # call many times
        for ii in range(2, NUM_CALLS):
            self.call_contract(sender,
                               priv_key,
                               contractAddr,
                               encode_hex_0x(keccak(b"foo()")),
                               storage_limit=0)

        # apply filter, we expect NUM_CALLS log entries with increasing uint32 fields
        filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS)

        for ii in range(2, NUM_CALLS):
            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], CALLED_TOPIC)
            assert (logs[ii]["topics"][1] == self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2], self.number_to_topic(ii))

        # apply filter for specific topics
        filter = Filter(topics=[CONSTRUCTED_TOPIC])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 1)

        filter = Filter(topics=[CALLED_TOPIC])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS - 1)

        filter = Filter(topics=[None, self.address_to_topic(sender)])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS)

        # find logs with `CALLED_TOPIC` as 1st topic and `3` or `4` as 3rd topic
        filter = Filter(topics=[
            CALLED_TOPIC, None,
            [self.number_to_topic(3),
             self.number_to_topic(4)]
        ])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 2)

        # apply filter with limit
        filter = Filter(limit=hex(NUM_CALLS // 2))
        logs = self.rpc.get_logs(filter)

        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS // 2)

        # apply filter for specific contract address
        _, contractAddr2 = self.deploy_contract(sender, priv_key, bytecode)

        filter = Filter(address=[contractAddr])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), NUM_CALLS)

        filter = Filter(address=[contractAddr2])
        logs = self.rpc.get_logs(filter)
        self.assert_response_format_correct(logs)
        assert_equal(len(logs), 1)

        # apply filter to very first epoch, we expect no logs
        filter = Filter(from_epoch="earliest", to_epoch="earliest")
        result = self.rpc.get_logs(filter)
        assert_equal(result, [])

        # generate two blocks with `NUM_CALLS` valid logs in each
        parent_hash = self.rpc.block_by_epoch("latest_mined")['hash']
        start_nonce = self.rpc.get_nonce(sender)

        txs = [
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     sender=sender,
                                     priv_key=priv_key,
                                     storage_limit=64,
                                     nonce=start_nonce + ii)
            for ii in range(0, NUM_CALLS)
        ]
        block_hash_1 = self.rpc.generate_custom_block(parent_hash=parent_hash,
                                                      referee=[],
                                                      txs=txs)

        txs = [
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(keccak(b"foo()")),
                                     sender=sender,
                                     priv_key=priv_key,
                                     storage_limit=64,
                                     nonce=start_nonce + NUM_CALLS + ii)
            for ii in range(0, NUM_CALLS)
        ]
        block_hash_2 = self.rpc.generate_custom_block(parent_hash=block_hash_1,
                                                      referee=[],
                                                      txs=txs)

        # blocks not executed yet, filtering should fail
        filter = Filter(block_hashes=[block_hash_1, block_hash_2])
        assert_raises_rpc_error(None, None, self.rpc.get_logs, filter)

        # generate some more blocks to ensure our two blocks are executed
        self.rpc.generate_blocks(10)

        # filtering for these two blocks should return logs in correct order
        filter = Filter(block_hashes=[block_hash_1, block_hash_2])
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), 2 * NUM_CALLS)

        for ii in range(0, 2 * NUM_CALLS):
            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], CALLED_TOPIC)
            assert (logs[ii]["topics"][1] == self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2],
                         self.number_to_topic(ii + NUM_CALLS))

        # block hash order should not affect log order
        filter = Filter(block_hashes=[block_hash_2, block_hash_1])
        logs2 = self.rpc.get_logs(filter)
        assert_equal(logs, logs2)

        # given a limit, we should receive the _last_ few logs
        filter = Filter(block_hashes=[block_hash_1, block_hash_2],
                        limit=hex(NUM_CALLS + NUM_CALLS // 2))
        logs = self.rpc.get_logs(filter)
        assert_equal(len(logs), NUM_CALLS + NUM_CALLS // 2)

        for ii in range(0, NUM_CALLS + NUM_CALLS // 2):
            assert_equal(len(logs[ii]["topics"]), 3)
            assert_equal(logs[ii]["topics"][0], CALLED_TOPIC)
            assert (logs[ii]["topics"][1] == self.address_to_topic(sender))
            assert_equal(logs[ii]["topics"][2],
                         self.number_to_topic(ii + NUM_CALLS + NUM_CALLS // 2))

        self.log.info("Pass")

    def address_to_topic(self, address):
        return "0x" + address[2:].zfill(64)

    def number_to_topic(self, number):
        return "0x" + ("%x" % number).zfill(64)

    def deploy_contract(self, sender, priv_key, data_hex):
        c0 = self.rpc.get_collateral_for_storage(sender)
        tx = self.rpc.new_contract_tx(receiver="",
                                      data_hex=data_hex,
                                      sender=sender,
                                      priv_key=priv_key,
                                      storage_limit=253)
        assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex())
        receipt = self.rpc.get_transaction_receipt(tx.hash_hex())
        assert_equal(receipt["outcomeStatus"], 0)
        address = receipt["contractCreated"]
        c1 = self.rpc.get_collateral_for_storage(sender)
        assert_equal(c1 - c0, 253 * 10**18 // 1024)
        assert_is_hex_string(address)
        return receipt, address

    def call_contract(self, sender, priv_key, contract, data_hex,
                      storage_limit):
        c0 = self.rpc.get_collateral_for_storage(sender)
        tx = self.rpc.new_contract_tx(receiver=contract,
                                      data_hex=data_hex,
                                      sender=sender,
                                      priv_key=priv_key,
                                      storage_limit=storage_limit)
        assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex())
        receipt = self.rpc.get_transaction_receipt(tx.hash_hex())
        assert_equal(receipt["outcomeStatus"], 0)
        c1 = self.rpc.get_collateral_for_storage(sender)
        assert_equal(c1 - c0, storage_limit * 10**18 // 1024)
        return receipt

    def assert_response_format_correct(self, response):
        assert_equal(type(response), list)
        for log in response:
            self.assert_log_format_correct(log)

    def assert_log_format_correct(self, log):
        assert_is_hex_string(log["address"])
        assert_is_hex_string(log["epochNumber"])
        assert_is_hex_string(log["logIndex"])
        assert_is_hex_string(log["transactionIndex"])
        assert_is_hex_string(log["transactionLogIndex"])

        assert_is_hash_string(log["blockHash"])
        assert_is_hash_string(log["transactionHash"])

        assert_equal(type(log["topics"]), list)
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"]
Esempio n. 14
0
class ContextInternalContractTest(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 1

    def setup_network(self):
        self.add_nodes(self.num_nodes)
        self.start_node(0, ["--archive"])
        self.rpc = RpcClient(self.nodes[0])

    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        # 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()
        tx = self.rpc.new_contract_tx(receiver="",
                                      data_hex=bytecode,
                                      sender=sender,
                                      priv_key=priv_key,
                                      storage_limit=20000)
        assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex())
        receipt = self.rpc.get_transaction_receipt(tx.hash_hex())
        contractAddr = receipt["contractCreated"]
        assert_is_hex_string(contractAddr)

        #                      ---        ---        ---        ---
        #                  .- | A | <--- | C | <--- | D | <--- | E | <--- ...
        #           ---    |   ---        ---        ---        ---
        # ... <--- | P | <-*                          .
        #           ---    |   ---                    .
        #                  .- | B | <..................
        #                      ---

        #               0 --- A --- C --- B --- D ---
        # block number: x  | x+1 | x+2 | x+3 | x+4 |
        # epoch number: y  | y+1 | y+2 |   y + 3   |

        start_nonce = self.rpc.get_nonce(self.rpc.GENESIS_ADDR)

        epoch_number_p = int(
            self.rpc.block_by_epoch("latest_mined")['epochNumber'], 0)
        block_number_p = int(
            self.rpc.block_by_epoch("latest_mined")['epochNumber'], 0)
        assert_equal(epoch_number_p, block_number_p)

        block_p = self.rpc.block_by_epoch("latest_mined")['hash']

        txs = [
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getBlockNumber()")),
                                     nonce=start_nonce + 0,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getEpochNumber()")),
                                     nonce=start_nonce + 1,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getBlockNumber()")),
                                     nonce=start_nonce + 2,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getEpochNumber()")),
                                     nonce=start_nonce + 3,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getBlockNumber()")),
                                     nonce=start_nonce + 4,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getEpochNumber()")),
                                     nonce=start_nonce + 5,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getBlockNumber()")),
                                     nonce=start_nonce + 6,
                                     sender=sender,
                                     priv_key=priv_key),
            self.rpc.new_contract_tx(receiver=contractAddr,
                                     data_hex=encode_hex_0x(
                                         keccak(b"getEpochNumber()")),
                                     nonce=start_nonce + 7,
                                     sender=sender,
                                     priv_key=priv_key),
        ]

        block_a = self.rpc.generate_custom_block(parent_hash=block_p,
                                                 referee=[],
                                                 txs=txs[0:2])
        block_c = self.rpc.generate_custom_block(parent_hash=block_a,
                                                 referee=[],
                                                 txs=txs[2:4])
        block_b = self.rpc.generate_custom_block(parent_hash=block_p,
                                                 referee=[],
                                                 txs=txs[4:6])
        block_d = self.rpc.generate_custom_block(parent_hash=block_c,
                                                 referee=[block_b],
                                                 txs=txs[6:8])

        # make sure transactions have been executed
        parent_hash = block_d

        for _ in range(5):
            block = self.rpc.generate_custom_block(parent_hash=parent_hash,
                                                   referee=[],
                                                   txs=[])
            parent_hash = block

        # transactions in block A
        # note: topic-1 of each log is the emitted block/epoch number
        block_number_a = int(
            self.rpc.get_transaction_receipt(
                txs[0].hash_hex())['logs'][0]['topics'][1], 16)
        epoch_number_a = int(
            self.rpc.get_transaction_receipt(
                txs[1].hash_hex())['logs'][0]['topics'][1], 16)

        assert_equal(block_number_a, block_number_p + 1)
        assert_equal(epoch_number_a, epoch_number_p + 1)

        # transactions in block B
        block_number_b = int(
            self.rpc.get_transaction_receipt(
                txs[4].hash_hex())['logs'][0]['topics'][1], 16)
        epoch_number_b = int(
            self.rpc.get_transaction_receipt(
                txs[5].hash_hex())['logs'][0]['topics'][1], 16)

        assert_equal(block_number_b, block_number_p + 3)
        assert_equal(epoch_number_b, epoch_number_p + 3)

        # transactions in block C
        block_number_c = int(
            self.rpc.get_transaction_receipt(
                txs[2].hash_hex())['logs'][0]['topics'][1], 16)
        epoch_number_c = int(
            self.rpc.get_transaction_receipt(
                txs[3].hash_hex())['logs'][0]['topics'][1], 16)

        assert_equal(block_number_c, block_number_p + 2)
        assert_equal(epoch_number_c, epoch_number_p + 2)

        # transactions in block d
        block_number_d = int(
            self.rpc.get_transaction_receipt(
                txs[6].hash_hex())['logs'][0]['topics'][1], 16)
        epoch_number_d = int(
            self.rpc.get_transaction_receipt(
                txs[7].hash_hex())['logs'][0]['topics'][1], 16)

        assert_equal(block_number_d, block_number_p + 4)
        assert_equal(epoch_number_d, epoch_number_p + 3)

        self.log.info("Pass")