Exemplo n.º 1
0
class ClearAdminTest(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 8

    def setup_network(self):
        self.setup_nodes()
        connect_sample_nodes(self.nodes, self.log)
        sync_blocks(self.nodes)
        self.rpc = RpcClient(self.nodes[0])

    def run_test(self):
        start_p2p_connection(self.nodes)
        block_gen_thread = BlockGenThread(self.nodes, self.log)
        block_gen_thread.start()

        gas_price = 1
        gas = CONTRACT_DEFAULT_GAS
        genesis_key = default_config["GENESIS_PRI_KEY"]
        genesis_addr = encode_hex_0x(priv_to_addr(genesis_key))
        nonce = 0
        test_account_key = default_config["GENESIS_PRI_KEY_2"]
        test_account_addr = encode_hex_0x(priv_to_addr(test_account_key))
        null_addr = "0x0000000000000000000000000000000000000000"

        file_dir = os.path.dirname(os.path.realpath(__file__))
        control_contract_file_path = os.path.join(file_dir, "..",
                                                  "internal_contract",
                                                  "metadata",
                                                  "AdminControl.json")
        control_contract_dict = json.loads(
            open(control_contract_file_path, "r").read())
        admin_control_contract = get_contract_instance(
            contract_dict=control_contract_dict)
        admin_control_contract_addr = "0x0888000000000000000000000000000000000000"

        # Deploy a new instance of the create2factory other than the genesis block,
        # so that the admin is the genesis_addr, in order to test hijackAdmin function
        # in clear_admin_test_contract_addr.sol.
        self.tx_conf = {
            "from": Web3.toChecksumAddress(genesis_addr),
            "nonce": int_to_hex(nonce),
            "gas": int_to_hex(gas),
            "gasPrice": int_to_hex(gas_price),
            "chainId": 0
        }
        create2factory = get_contract_instance(
            abi_file=os.path.join(file_dir,
                                  "contracts/create2factory_abi.json"),
            bytecode_file=os.path.join(
                file_dir, "contracts/create2factory_bytecode.dat"),
        )
        raw_create = create2factory.constructor().buildTransaction(
            self.tx_conf)
        tx_data = decode_hex(raw_create["data"])
        tx_create = create_transaction(pri_key=genesis_key,
                                       receiver=b'',
                                       nonce=nonce,
                                       gas_price=gas_price,
                                       data=tx_data,
                                       gas=gas,
                                       value=0,
                                       storage_limit=1920)
        nonce += 1
        self.rpc.send_tx(tx_create, True)
        receipt = self.rpc.get_transaction_receipt(tx_create.hash_hex())
        create2factory_addr = receipt['contractCreated']

        # Clear admin by non-admin (fail)
        self.log.info("Test unable to clear admin by non-admin.")
        set_admin = admin_control_contract.functions \
            .setAdmin(Web3.toChecksumAddress(create2factory_addr), null_addr) \
            .buildTransaction({"to":admin_control_contract_addr, **self.tx_conf})
        tx_data = set_admin["data"]
        self.call_contract(test_account_addr, test_account_key,
                           admin_control_contract_addr, tx_data)
        assert_equal(self.rpc.get_admin(create2factory_addr), genesis_addr)

        clear_admin_test_contract = get_contract_instance(
            abi_file=os.path.join(file_dir,
                                  "contracts/clear_admin_at_creation.json"),
            bytecode_file=os.path.join(
                file_dir, "contracts/clear_admin_at_creation.bytecode"),
        )

        self.log.info("Test contract creation by itself")
        raw_create = clear_admin_test_contract.constructor().buildTransaction(
            self.tx_conf)
        tx_data = decode_hex(raw_create["data"])
        tx_create = create_transaction(pri_key=genesis_key,
                                       receiver=b'',
                                       nonce=nonce,
                                       gas_price=gas_price,
                                       data=tx_data,
                                       gas=gas,
                                       value=0,
                                       storage_limit=1920)
        nonce += 1
        self.rpc.send_tx(tx_create, True)
        receipt = self.rpc.get_transaction_receipt(tx_create.hash_hex())
        address = receipt["contractCreated"]
        self.log.info("  contract created at %s" % address)
        assert (address is not None)

        self.log.info(
            "Test clear admin at contract creation through create2factory")
        create_data = raw_create["data"]
        salt = 0
        data = create2factory.functions.deploy(create_data,
                                               salt).buildTransaction({
                                                   "to":
                                                   create2factory_addr,
                                                   **self.tx_conf
                                               })["data"]
        # Compute the contract address.
        clear_admin_test_contract_addr = Web3.toChecksumAddress(
            "0x" + self.rpc.call(create2factory_addr, data)[-40:])
        # Deploy the contract.
        self.call_contract(genesis_addr,
                           genesis_key,
                           create2factory_addr,
                           data,
                           value=0)
        assert_equal(self.rpc.get_admin(clear_admin_test_contract_addr),
                     null_addr)
        # The owner of create2factory_addr isn't hijacked.
        self.log.info("Test unable to hijack set admin.")
        assert_equal(self.rpc.get_admin(create2factory_addr), genesis_addr)

        self.log.info(
            "Test unable to hijack owner through deployAndHijackAdmin")
        # Create a new contract through deployAndHijackAdmin.
        new_contract_to_deploy = get_contract_instance(
            abi_file=os.path.join(file_dir, "contracts/blackhole.json"),
            bytecode_file=os.path.join(file_dir,
                                       "contracts/blackhole.bytecode"),
        )
        self.tx_conf["nonce"] = 1
        self.tx_conf["from"] = Web3.toChecksumAddress(test_account_addr)
        new_raw_create = new_contract_to_deploy.constructor().buildTransaction(
            self.tx_conf)
        create_data = new_raw_create["data"]
        data = clear_admin_test_contract.functions.deployAndHijackAdmin(
            create_data).buildTransaction({
                "to": clear_admin_test_contract_addr,
                **self.tx_conf
            })["data"]
        new_contract_addr = "0x" + self.rpc.call(
            clear_admin_test_contract_addr, data)[-40:]
        self.call_contract(test_account_addr,
                           test_account_key,
                           clear_admin_test_contract_addr,
                           data,
                           value=123)
        # Check owner of the new contract isn't the "evil address" or null address.
        assert_equal(self.rpc.get_admin(new_contract_addr), test_account_addr)

        self.log.info("Pass")

    def call_contract(self,
                      sender,
                      priv_key,
                      contract,
                      data_hex,
                      value=0,
                      storage_limit=10000,
                      gas=CONTRACT_DEFAULT_GAS):
        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,
                                      value=value,
                                      storage_limit=storage_limit,
                                      gas=gas)
        assert_equal(self.rpc.send_tx(tx, True), tx.hash_hex())
        receipt = self.rpc.get_transaction_receipt(tx.hash_hex())
        self.log.info("call_contract storage collateral change={}".format(
            (self.rpc.get_collateral_for_storage(sender) - c0) //
            COLLATERAL_UNIT_IN_DRIP))
        return receipt
Exemplo n.º 2
0
class P2PTest(ConfluxTestFramework):
    def set_test_params(self):
        self.num_nodes = 8

    def setup_network(self):
        self.setup_nodes()
        connect_sample_nodes(self.nodes, self.log)
        sync_blocks(self.nodes)

    def run_test(self):
        file_dir = os.path.dirname(os.path.realpath(__file__))
        erc20_contract = get_contract_instance(
            abi_file=os.path.join(file_dir, "contracts/erc20_abi.json"),
            bytecode_file=os.path.join(file_dir,
                                       "contracts/erc20_bytecode.dat"),
        )

        gas_price = 1
        gas = CONTRACT_DEFAULT_GAS

        start_p2p_connection(self.nodes)

        self.log.info("Initializing contract")
        genesis_key = default_config["GENESIS_PRI_KEY"]
        genesis_addr = encode_hex_0x(priv_to_addr(genesis_key))
        nonce = 0
        block_gen_thread = BlockGenThread(self.nodes, self.log)
        block_gen_thread.start()
        self.tx_conf = {
            "from": Web3.toChecksumAddress(genesis_addr),
            "nonce": int_to_hex(nonce),
            "gas": int_to_hex(gas),
            "gasPrice": int_to_hex(gas_price),
            "chainId": 0
        }
        raw_create = erc20_contract.constructor().buildTransaction(
            self.tx_conf)
        tx_data = decode_hex(raw_create["data"])
        tx_create = create_transaction(pri_key=genesis_key,
                                       receiver=b'',
                                       nonce=nonce,
                                       gas_price=gas_price,
                                       data=tx_data,
                                       gas=gas,
                                       value=0,
                                       storage_limit=1920)
        self.client = RpcClient(self.nodes[0])
        c0 = self.client.get_collateral_for_storage(genesis_addr)
        self.client.send_tx(tx_create, True)
        receipt = self.client.get_transaction_receipt(tx_create.hash_hex())
        c1 = self.client.get_collateral_for_storage(genesis_addr)
        assert_equal(c1 - c0, 1920 * 10**18 / 1024)
        contract_addr = receipt['contractCreated']
        self.log.info("Contract " + str(contract_addr) +
                      " created, start transferring tokens")

        tx_n = 10
        self.tx_conf["to"] = contract_addr
        nonce += 1
        balance_map = {genesis_key: 1000000 * 10**18}
        sender_key = genesis_key
        all_txs = []
        for i in range(tx_n):
            value = int((balance_map[sender_key] -
                         ((tx_n - i) * 21000 * gas_price)) * random.random())
            receiver_sk, _ = ec_random_keys()
            balance_map[receiver_sk] = value
            tx_data = decode_hex(
                erc20_contract.functions.transfer(
                    Web3.toChecksumAddress(
                        encode_hex(priv_to_addr(receiver_sk))),
                    value).buildTransaction(self.tx_conf)["data"])
            tx = create_transaction(pri_key=sender_key,
                                    receiver=decode_hex(self.tx_conf["to"]),
                                    value=0,
                                    nonce=nonce,
                                    gas=gas,
                                    gas_price=gas_price,
                                    data=tx_data,
                                    storage_limit=64)
            r = random.randint(0, self.num_nodes - 1)
            self.nodes[r].p2p.send_protocol_msg(
                Transactions(transactions=[tx]))
            nonce += 1
            balance_map[sender_key] -= value
            all_txs.append(tx)
        self.log.info("Wait for transactions to be executed")
        self.wait_for_tx(all_txs)
        self.log.info("Check final token balance")
        for sk in balance_map:
            addr = priv_to_addr(sk)
            assert_equal(self.get_balance(erc20_contract, addr),
                         balance_map[sk])
        c2 = self.client.get_collateral_for_storage(genesis_addr)
        assert_equal(c2 - c1, 64 * tx_n * 10**18 / 1024)
        block_gen_thread.stop()
        block_gen_thread.join()
        sync_blocks(self.nodes)
        self.log.info("Pass")

    def get_balance(self, contract, token_address):
        tx = contract.functions.balanceOf(
            Web3.toChecksumAddress(
                encode_hex(token_address))).buildTransaction(self.tx_conf)
        result = self.client.call(tx["to"], tx["data"])
        balance = bytes_to_int(decode_hex(result))
        self.log.debug("address=%s, balance=%s", encode_hex(token_address),
                       balance)
        return balance