def run_test(self):
        block_number = 10

        for i in range(1, block_number):
            chosen_peer = random.randint(0, self.num_nodes - 1)
            block_hash = self.nodes[chosen_peer].generate(1, 0)
            self.log.info("generate block %s", block_hash)
        wait_for_block_count(self.nodes[0], block_number, timeout=30)
        sync_blocks(self.nodes, timeout=30)
        self.log.info("generated blocks received by all")

        self.stop_node(0, kill=True)
        self.log.info("node 0 stopped")
        block_hash = self.nodes[-1].generate(1, 0)
        self.log.info("generate block %s", block_hash)
        wait_for_block_count(self.nodes[1], block_number + 1)
        sync_blocks(self.nodes[1:], timeout=30)
        self.log.info("blocks sync success among running nodes")
        self.start_node(0)
        sync_blocks(self.nodes, timeout=30)
        self.log.info("Pass 1")

        for i in range(1, self.num_nodes):
            self.stop_node(i)
        self.nodes[0].add_p2p_connection(P2PInterface())
        network_thread_start()
        self.nodes[0].p2p.wait_for_status()
        gas_price = 1
        value = 1
        receiver_sk, _ = ec_random_keys()
        sender_key = default_config["GENESIS_PRI_KEY"]
        tx = create_transaction(pri_key=sender_key, receiver=privtoaddr(receiver_sk), value=value, nonce=0,
                                gas_price=gas_price)
        self.nodes[0].p2p.send_protocol_msg(Transactions(transactions=[tx]))
        self.log.debug("New tx %s: %s send value %d to %s", encode_hex(tx.hash), eth_utils.encode_hex(privtoaddr(sender_key))[-4:],
                       value, eth_utils.encode_hex(privtoaddr(receiver_sk))[-4:])
        def check_packed():
            client = RpcClient(self.nodes[0])
            client.generate_block(1)
            return checktx(self.nodes[0], tx.hash_hex())
        wait_until(lambda: check_packed())
        sender_addr = eth_utils.encode_hex(privtoaddr(sender_key))
        receiver_addr = eth_utils.encode_hex(privtoaddr(receiver_sk))
        sender_balance = default_config["TOTAL_COIN"] - value - gas_price * 21000
        # Generate 2 * CACHE_INDEX_STRIDE to start evicting anticone cache
        for _ in range(2000):
            self.nodes[0].generate(1, 0)
        assert_equal(parse_as_int(self.nodes[0].cfx_getBalance(sender_addr)), sender_balance)
        assert_equal(parse_as_int(self.nodes[0].cfx_getBalance(receiver_addr)), value)
        time.sleep(1)
        self.stop_node(0)
        self.start_node(0)
        self.log.info("Wait for node 0 to recover from crash")
        wait_until(lambda: parse_as_int(self.nodes[0].cfx_getBalance(sender_addr)) == sender_balance)
        wait_until(lambda: parse_as_int(self.nodes[0].cfx_getBalance(receiver_addr)) == value)
        self.log.info("Pass 2")
 def check_account(self, k, balance_map):
     addr = eth_utils.encode_hex(privtoaddr(k))
     try:
         balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
         bank_balance = parse_as_int(self.nodes[0].cfx_getBankBalance(addr))
     except Exception as e:
         self.log.info("Fail to get balance, error=%s", str(e))
         return False
     if balance + bank_balance == balance_map[k]:
         return True
     else:
         self.log.info("Remote balance:%d, local balance:%d",
                       balance + bank_balance, balance_map[k])
         time.sleep(1)
         return False
Exemple #3
0
 def check_account(self, k, balance_map):
     addr = eth_utils.encode_hex(priv_to_addr(k))
     try:
         balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
         staking_balance = parse_as_int(self.nodes[0].cfx_getStakingBalance(addr))
         collateral_for_storage = parse_as_int(self.nodes[0].cfx_getCollateralForStorage(addr))
     except Exception as e:
         self.log.info("Fail to get balance, error=%s", str(e))
         return False
     if balance + staking_balance + collateral_for_storage == balance_map[k]:
         return True
     else:
         self.log.info("Remote balance:%d, local balance:%d", balance + staking_balance + collateral_for_storage, balance_map[k])
         time.sleep(1)
         return False
    def test_estimate_collateral(self):
        contract_addr = self.test_contract_deploy()
        (addr, priv_key) = self.rand_account()

        collateral = self.estimate_collateral(
            contract_addr="0x",
            data_hex=
            "0x60806040526000805534801561001457600080fd5b506040516101b73803806101b78339818101604052602081101561003757600080fd5b810190808051906020019092919050505080600081905550506101588061005f6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636d4ce63c146100465780637b0cb83914610064578063812600df1461006e575b600080fd5b61004e6100b0565b6040518082815260200191505060405180910390f35b61006c6100b9565b005b61009a6004803603602081101561008457600080fd5b810190808035906020019092919050505061010b565b6040518082815260200191505060405180910390f35b60008054905090565b3373ffffffffffffffffffffffffffffffffffffffff167ffceb437c298f40d64702ac26411b2316e79f3c28ffa60edfc891ad4fc8ab82ca6000546040518082815260200191505060405180910390a2565b60008160008082825401925050819055905091905056fea264697066735822122032510ec4ba70a57be7ecbd80920213f49c97b68e3264707e93d653ff2e37064a64736f6c63430006010033000000000000000000000000000000000000000000000000000000000000000a",
            sender=addr)
        assert_equal(parse_as_int(collateral), 408)

        tx = self.new_tx(sender=self.GENESIS_ADDR,
                         priv_key=self.GENESIS_PRI_KEY,
                         value=10**20,
                         receiver=addr)
        assert_equal(self.send_tx(tx, True), tx.hash_hex())
        assert_equal(self.get_balance(addr), 10**20)
        assert_equal(self.get_collateral_for_storage(addr), 0)

        # if you set the storage to 6, sender will pay collateral for storage
        collateral = self.estimate_collateral(
            contract_addr=contract_addr,
            data_hex=
            "0x60fe47b10000000000000000000000000000000000000000000000000000000000000006",
            sender=addr)
        assert_equal(parse_as_int(collateral), 64)
        assert_equal(self.get_collateral_for_storage(addr), 0)

        # send tx to set the storage from 5 to 6
        tx = self.new_contract_tx(
            receiver=contract_addr,
            data_hex=
            "0x60fe47b10000000000000000000000000000000000000000000000000000000000000006",
            sender=addr,
            priv_key=priv_key,
            storage_limit=64)
        assert_equal(self.send_tx(tx, True), tx.hash_hex())
        assert_equal(int(self.call(contract_addr, "0x6d4ce63c"), 0), 6)
        assert_equal(self.get_collateral_for_storage(addr), 10**18 // 16)

        # this time you don't need to pay collateral for storage even if you change the storage value
        collateral = self.estimate_collateral(
            contract_addr=contract_addr,
            data_hex=
            "0x60fe47b10000000000000000000000000000000000000000000000000000000000000007",
            sender=addr)
        assert_equal(parse_as_int(collateral), 0)
        assert_equal(self.get_collateral_for_storage(addr), 10**18 // 16)
    def run_test(self):
        start_p2p_connection(self.nodes)
        overall_generate_period_ms = 10
        report_progress_blocks = 100
        initial_chain_length = 20000

        # Attacker computation power ratio in the total power
        attacker_ratio = 0.4
        attacker_generate_period_ms = overall_generate_period_ms / attacker_ratio
        victim_generation_period_ms = overall_generate_period_ms / (
            1 - attacker_ratio)

        # attacker = self.nodes[0]
        victim = self.nodes[0]
        self.log.info(f"Generate initial {initial_chain_length} blocks")
        last_block = victim.generate_empty_blocks(initial_chain_length)[-1]
        last_height = parse_as_int(
            RpcClient(victim).block_by_hash(last_block)["height"])
        victim_handler = Victim("VICTIM",
                                victim,
                                victim_generation_period_ms,
                                self.log,
                                report_progress_blocks,
                                fixed_period=True)
        victim_handler.start()
        self.log.info("Victim started")
        attacker_handler = Attacker("ATTACKER", victim,
                                    attacker_generate_period_ms, self.log)
        attacker_handler.set_fork_point(last_block, last_height)
        attacker_handler.start()
        self.log.info("Attacker started")
        victim_handler.join()
    def run_test(self):
        self.rpc = RpcClient(self.nodes[0])
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))
        block_reward = 7000000000000000000

        # deploy storage test contract
        bytecode_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), CONTRACT_PATH)
        assert (os.path.isfile(bytecode_file))
        bytecode = open(bytecode_file).read()

        # 1. Produce an empty block
        self.rpc.generate_block()

        # 2. Deploy a contract: this will create 6 blocks and the first block contains 'create contract' transaction,
        # the other 5 blocks are empty.
        receipt, _ = self.deploy_contract(sender, priv_key, bytecode)

        # 3. Produce 10 empty blocks, and the miner's reward for the first block will be updated to world-state
        for _ in range(10): self.rpc.generate_block()
        balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author))
        count = self.nodes[0].getblockcount()
        expected = block_reward
        self.log.info("block count: %d, balance: %d, expected: %d", count, balance, expected)
        assert_equal(balance, expected)

        # 4. Produce 1 empty block, and the miner will receive reward for the second block. This block reward should
        # contains transaction fee.
        self.rpc.generate_blocks(1)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author))
        count = self.nodes[0].getblockcount()
        transaction_fee = parse_as_int(receipt['gasFee'])
        expected += block_reward + transaction_fee
        self.log.info("block count: %d, balance: %d, expected: %d, transaction_fee: %d", count, balance, expected,
                transaction_fee)
        assert_equal(balance, expected)

        # 5. Produce 1 empty block, and the miner will receive reward for the third empty block. This block reward
        # should contains storage maintenance fee.
        self.rpc.generate_blocks(1)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author))
        count = self.nodes[0].getblockcount()
        collateral_for_storage = self.rpc.get_collateral_for_storage(sender)
        storage_fee = collateral_for_storage * 4 // 100 // 63072000
        expected += block_reward + storage_fee
        self.log.info("block count: %d, balance: %d, expected: %d, collateral_for_storage: %d, storage_fee: %d", count,
                balance, expected, collateral_for_storage, storage_fee)
        assert_equal(balance, expected)

        # 6. Produce 1 empty block, and the miner will receive reward for the forth empty block. This block reward
        # should contains storage maintenance fee.
        self.rpc.generate_blocks(1)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(self.mining_author))
        count = self.nodes[0].getblockcount()
        collateral_for_storage = self.rpc.get_collateral_for_storage(sender)
        storage_fee = collateral_for_storage * 4 // 100 // 63072000
        expected += storage_fee + block_reward
        self.log.info("block count: %d, balance: %d, expected: %d, collateral_for_storage: %d, storage_fee: %d", count,
                balance, expected, collateral_for_storage, storage_fee)

        assert_equal(balance, expected)
    def run_test(self):
        start_p2p_connection(self.nodes)
        block_gen_thread = BlockGenThread(self.nodes, self.log)
        block_gen_thread.start()
        client = RpcClient(self.nodes[0])

        file_dir = os.path.dirname(os.path.realpath(__file__))

        self.log.info("Initializing contract")

        self.buggy_contract = get_contract_instance(source=os.path.join(
            file_dir, "contracts/reentrancy.sol"),
                                                    contract_name="Reentrance")
        self.exploit_contract = get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy_exploit.sol"),
            contract_name="ReentranceExploit")

        reentrancy_config_addr = Web3.toChecksumAddress(
            "0888000000000000000000000000000000000003")
        file_dir = os.path.dirname(os.path.realpath(__file__))
        control_contract_file_path = os.path.join(file_dir, "..",
                                                  "internal_contract",
                                                  "metadata",
                                                  "ReentrancyConfig.json")
        control_contract_dict = json.loads(
            open(control_contract_file_path, "r").read())
        control_contract = get_contract_instance(
            contract_dict=control_contract_dict)

        user1, _ = ec_random_keys()
        user1_addr = priv_to_addr(user1)
        user1_addr_hex = eth_utils.encode_hex(user1_addr)
        user2, _ = ec_random_keys()
        user2_addr = priv_to_addr(user2)
        user2_addr_hex = eth_utils.encode_hex(user2_addr)

        # setup balance
        value = (10**15 + 2000) * 10**18 + ReentrancyTest.REQUEST_BASE['gas']
        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user1_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user2_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        user1_balance = client.get_balance(user1_addr_hex)
        assert_equal(user1_balance, value)
        user2_balance_before_contract_construction = client.get_balance(
            user2_addr_hex)
        assert_equal(user2_balance_before_contract_construction, value)

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "constructor", [],
                                                  self.genesis_priv_key,
                                                  storage_limit=20000)
        buggy_addr = self.wait_for_tx([transaction],
                                      True)[0]['contractCreated']

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "constructor", [],
                                                  user2,
                                                  storage_limit=200000)
        exploit_addr = self.wait_for_tx([transaction],
                                        True)[0]['contractCreated']

        if self.mode == NO_PROTECTION:
            self.log.info("Disabling anti-reentrancy")
            self.call_contract_function(
                contract=control_contract,
                name="allowReentrancyByAdmin",
                args=[Web3.toChecksumAddress(buggy_addr), True],
                sender_key=self.genesis_priv_key,
                contract_addr=reentrancy_config_addr,
                storage_limit=64,
                wait=True,
                check_status=True)
            self.call_contract_function(
                contract=control_contract,
                name="allowReentrancyByAdmin",
                args=[Web3.toChecksumAddress(exploit_addr), True],
                sender_key=user2,
                contract_addr=reentrancy_config_addr,
                storage_limit=64,
                wait=True,
                check_status=True)

        user2_balance_after_contract_construction = client.get_balance(
            user2_addr_hex)
        self.log.debug("user2 balance contract created %s" %
                       user2_balance_after_contract_construction)
        assert_greater_than_or_equal(
            user2_balance_before_contract_construction,
            user2_balance_after_contract_construction)
        user2_refund_upper_bound = \
            user2_balance_before_contract_construction - \
            user2_balance_after_contract_construction

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "addBalance", [],
                                                  user1,
                                                  10**18,
                                                  buggy_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)
        transaction = self.call_contract_function(
            self.exploit_contract,
            "deposit", [Web3.toChecksumAddress(buggy_addr)],
            user2,
            10**18,
            exploit_addr,
            True,
            True,
            storage_limit=128)

        user1_balance = client.get_balance(user1_addr_hex)
        assert_greater_than_or_equal(user1_balance,
                                     899999999999999999999999950000000)
        user2_balance_after_deposit = client.get_balance(user2_addr_hex)
        # User2 paid storage collateral `vulnerable_contract` in deposit call.
        user2_refund_upper_bound += 3 * 10**18 // 16
        self.log.debug("user2 balance after deposit %s" %
                       user2_balance_after_deposit)
        assert_greater_than_or_equal(user2_balance_after_contract_construction,
                                     user2_balance_after_deposit + 10**18)
        assert_greater_than_or_equal(user2_balance_after_deposit,
                                     899999999999999999999999900000000)
        contract_balance = client.get_balance(buggy_addr)
        assert_equal(contract_balance, 2 * 10**18)
        user2_balance_in_contract = RpcClient(self.nodes[0]).call(
            buggy_addr,
            self.buggy_contract.functions.balanceOf(
                Web3.toChecksumAddress(exploit_addr)).buildTransaction({
                    "from":
                    user2_addr_hex,
                    "to":
                    buggy_addr,
                    "gas":
                    int_to_hex(CONTRACT_DEFAULT_GAS),
                    "gasPrice":
                    int_to_hex(1),
                    "chainId":
                    0
                })["data"])
        assert_equal(parse_as_int(user2_balance_in_contract), 10**18)

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "launch_attack", [],
                                                  user2,
                                                  0,
                                                  exploit_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)
        transaction = self.call_contract_function(self.exploit_contract,
                                                  "get_money", [],
                                                  user2,
                                                  0,
                                                  exploit_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)

        user1_balance = client.get_balance(user1_addr_hex)
        assert_greater_than_or_equal(user1_balance,
                                     899999999999999999999999950000000)
        contract_balance = client.get_balance(buggy_addr)
        attack_benefit = 0
        if self.mode == OLD_MODE:
            # In the old mode, the second withdraw_balance will fail.
            rest_balance, attacker_rest = 1 * CFX, 0
        elif self.mode == NEW_MODE:
            # In the new mode, the protection is closed.
            rest_balance, attacker_rest = 0, 0
            attack_benefit = 1 * CFX
        else:
            raise Exception("Unrecognized reentrancy test mode")
        assert_equal(contract_balance, rest_balance)

        user2_balance_in_contract = RpcClient(self.nodes[0]).call(
            buggy_addr,
            self.buggy_contract.functions.balanceOf(
                Web3.toChecksumAddress(exploit_addr)).buildTransaction({
                    "from":
                    user2_addr_hex,
                    "to":
                    buggy_addr,
                    "gas":
                    int_to_hex(CONTRACT_DEFAULT_GAS),
                    "gasPrice":
                    int_to_hex(1),
                    "chainId":
                    0
                })["data"])

        assert_equal(parse_as_int(user2_balance_in_contract), attacker_rest)
        self.log.debug("user2 balance in contract %s" %
                       user2_balance_in_contract)
        user2_balance_after_contract_destruct = client.get_balance(
            user2_addr_hex)
        self.log.debug("user2 balance after contract destruct %s" %
                       user2_balance_after_contract_destruct)
        assert_greater_than_or_equal(
            user2_balance_after_deposit + user2_refund_upper_bound + 10**18 -
            attacker_rest + attack_benefit,
            user2_balance_after_contract_destruct,
        )

        block_gen_thread.stop()
        block_gen_thread.join()
pub_keys_map = {}
for i in range(start_block_number, end_block_number + 1, 1000):
    start = i
    end = min(i + 999, end_block_number + 1)
    print(start, end)
    logs = client.get_logs(filter=Filter(from_block=hex(start), to_block=hex(end), address=["0x0888000000000000000000000000000000000005"], networkid=1))
    print("logs=", logs)
    for log in logs:
        pos_identifier = log["topics"][1]
        if log["topics"][0] == REGISTER_TOPIC:
            bls_pub_key, vrf_pub_key = eth_abi.decode_abi(["bytes", "bytes"], decode_hex(log["data"]))
            pub_keys_map[pos_identifier] = (encode_hex_0x(bls_pub_key), encode_hex_0x(vrf_pub_key))
            print(pub_keys_map[pos_identifier])
        elif log["topics"][0] == INCREASE_STAKE_TOPIC:
            assert pos_identifier in pub_keys_map
            voting_power_map[pos_identifier] += parse_as_int(log["data"])
with open(os.path.join(cwd, "public_keys"), "w") as f:
    for pos_identifier in pub_keys_map.keys():
        f.write(",".join([pub_keys_map[pos_identifier][0][2:], pub_keys_map[pos_identifier][1][2:], str(voting_power_map[pos_identifier])]) + "\n")
cfx_block_hash = client.block_by_block_number(hex(end_block_number))["hash"]
initial_seed = encode_hex(keccak(hexstr=cfx_block_hash[2:]+bitcoin_block_hash))
tg_config_gen = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../target/release/pos-genesis-tool")
check_output([tg_config_gen, "frompub", "--initial-seed={}".format(initial_seed),"public_keys"], cwd=cwd)
waypoint = open(os.path.join(cwd, "waypoint_config"), "r").readlines()[0]
conf_file = open(os.path.join(cwd, "pos_config.yaml"), "w")
conf_file.write(f"""
base:
  #data_dir: ./pos_db
  role: validator
  waypoint:
    from_config: {waypoint}
Exemple #9
0
    def run_test(self):
        genesis_key = default_config["GENESIS_PRI_KEY"]
        receiver_sk, _ = ec_random_keys()
        receiver_addr = priv_to_addr(receiver_sk)
        client = RpcClient(self.nodes[0])

        value = 100000000
        tx = create_transaction(pri_key=genesis_key,
                                receiver=receiver_addr,
                                value=value,
                                nonce=0,
                                gas_price=1,
                                epoch_height=0)
        client.send_tx(tx)
        block_gen_thread = BlockGenThread(self.nodes,
                                          self.log,
                                          interval_base=0.1)
        block_gen_thread.start()
        self.log.info(
            "Wait for the first transaction to go through with epoch_height = 0..."
        )
        wait_until(lambda: parse_as_int(self.nodes[0].cfx_getBalance(
            eth_utils.encode_hex(receiver_addr))) == value)
        self.log.info("Wait for generating more than 50 epochs")
        wait_until(lambda: parse_as_int(
            client.block_by_hash(client.best_block_hash())['height']) > 50)
        block_gen_thread.stop()
        self.log.info("Now block count:%d", self.nodes[0].getblockcount())

        tx = create_transaction(pri_key=genesis_key,
                                receiver=receiver_addr,
                                value=value,
                                nonce=1,
                                gas_price=1,
                                epoch_height=0)
        try:
            client.send_tx(tx)
            self.log.info("Bad transaction not rejected!")
            assert (False)
        except ReceivedErrorResponseError:
            self.log.info("Bad transaction rejected.")
        except:
            self.log.info("Unexpected error!")
            assert (False)
        assert (parse_as_int(self.nodes[0].cfx_getBalance(
            eth_utils.encode_hex(receiver_addr))) == value)

        epoch_height = parse_as_int(
            client.block_by_hash(client.best_block_hash())['height'])
        tx = create_transaction(pri_key=genesis_key,
                                receiver=receiver_addr,
                                value=value,
                                nonce=1,
                                gas_price=1,
                                epoch_height=epoch_height)
        client.send_tx(tx)
        block_gen_thread = BlockGenThread(self.nodes,
                                          self.log,
                                          interval_base=0.1)
        block_gen_thread.start()
        self.log.info(
            "Wait for the first transaction to go through with epoch_height = "
            + str(epoch_height) + "...")
        wait_until(lambda: parse_as_int(self.nodes[0].cfx_getBalance(
            eth_utils.encode_hex(receiver_addr))) == 2 * value)
        block_gen_thread.stop()
        self.log.info("Now block count:%d", self.nodes[0].getblockcount())
        self.log.info("Pass!")
    def run_test(self):
        start_p2p_connection(self.nodes)
        block_gen_thread = BlockGenThread(self.nodes, self.log)
        block_gen_thread.start()

        file_dir = os.path.dirname(os.path.realpath(__file__))

        self.log.info("Initializing contract")

        self.buggy_contract = get_contract_instance(source=os.path.join(
            file_dir, "contracts/reentrancy.sol"),
                                                    contract_name="Reentrance")
        self.exploit_contract = get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy_exploit.sol"),
            contract_name="ReentranceExploit")

        user1, _ = ec_random_keys()
        user1_addr = priv_to_addr(user1)
        user1_addr_hex = eth_utils.encode_hex(user1_addr)
        user2, _ = ec_random_keys()
        user2_addr = priv_to_addr(user2)
        user2_addr_hex = eth_utils.encode_hex(user2_addr)

        # setup balance
        value = (10**15 + 2000) * 10**18 + ReentrancyTest.REQUEST_BASE['gas']
        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user1_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user2_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        user1_balance = parse_as_int(
            self.nodes[0].cfx_getBalance(user1_addr_hex))
        assert_equal(user1_balance, value)
        user2_balance_before_contract_construction = parse_as_int(
            self.nodes[0].cfx_getBalance(user2_addr_hex))
        assert_equal(user2_balance_before_contract_construction, value)

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "constructor", [],
                                                  self.genesis_priv_key,
                                                  storage_limit=20000)
        contract_addr = self.wait_for_tx([transaction],
                                         True)[0]['contractCreated']

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "constructor", [],
                                                  user2,
                                                  storage_limit=200000)
        exploit_addr = self.wait_for_tx([transaction],
                                        True)[0]['contractCreated']
        user2_balance_after_contract_construction = parse_as_int(
            self.nodes[0].cfx_getBalance(user2_addr_hex))
        self.log.debug("user2 balance contract created %s" %
                       user2_balance_after_contract_construction)
        assert_greater_than_or_equal(
            user2_balance_before_contract_construction,
            user2_balance_after_contract_construction)
        user2_refund_upper_bound = \
            user2_balance_before_contract_construction - \
            user2_balance_after_contract_construction

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "addBalance", [],
                                                  user1,
                                                  10**18,
                                                  contract_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)
        transaction = self.call_contract_function(
            self.exploit_contract,
            "deposit", [Web3.toChecksumAddress(contract_addr)],
            user2,
            10**18,
            exploit_addr,
            True,
            True,
            storage_limit=128)

        user1_balance = parse_as_int(
            self.nodes[0].cfx_getBalance(user1_addr_hex))
        assert_greater_than_or_equal(user1_balance,
                                     899999999999999999999999950000000)
        user2_balance_after_deposit = parse_as_int(
            self.nodes[0].cfx_getBalance(user2_addr_hex))
        # User2 paid storage collateral `vulnerable_contract` in deposit call.
        user2_refund_upper_bound += 10**18 // 16
        self.log.debug("user2 balance after deposit %s" %
                       user2_balance_after_deposit)
        assert_greater_than_or_equal(user2_balance_after_contract_construction,
                                     user2_balance_after_deposit + 10**18)
        assert_greater_than_or_equal(user2_balance_after_deposit,
                                     899999999999999999999999900000000)
        contract_balance = parse_as_int(
            self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(contract_balance, 2 * 10**18)
        user2_balance_in_contract = RpcClient(self.nodes[0]).call(
            contract_addr,
            self.buggy_contract.functions.balanceOf(
                Web3.toChecksumAddress(exploit_addr)).buildTransaction({
                    "from":
                    user2_addr_hex,
                    "to":
                    contract_addr,
                    "gas":
                    int_to_hex(CONTRACT_DEFAULT_GAS),
                    "gasPrice":
                    int_to_hex(1),
                    "chainId":
                    0
                })["data"])
        assert_equal(parse_as_int(user2_balance_in_contract), 10**18)

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "launch_attack", [],
                                                  user2,
                                                  0,
                                                  exploit_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)
        transaction = self.call_contract_function(self.exploit_contract,
                                                  "get_money", [],
                                                  user2,
                                                  0,
                                                  exploit_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)

        user1_balance = parse_as_int(
            self.nodes[0].cfx_getBalance(user1_addr_hex))
        assert_greater_than_or_equal(user1_balance,
                                     899999999999999999999999950000000)
        contract_balance = parse_as_int(
            self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(contract_balance, 1 * 10**18)

        user2_balance_in_contract = RpcClient(self.nodes[0]).call(
            contract_addr,
            self.buggy_contract.functions.balanceOf(
                Web3.toChecksumAddress(exploit_addr)).buildTransaction({
                    "from":
                    user2_addr_hex,
                    "to":
                    contract_addr,
                    "gas":
                    int_to_hex(CONTRACT_DEFAULT_GAS),
                    "gasPrice":
                    int_to_hex(1),
                    "chainId":
                    0
                })["data"])

        assert_equal(parse_as_int(user2_balance_in_contract), 0)
        self.log.debug("user2 balance in contract %s" %
                       user2_balance_in_contract)
        user2_balance_after_contract_destruct = parse_as_int(
            self.nodes[0].cfx_getBalance(user2_addr_hex))
        self.log.debug("user2 balance after contract destruct %s" %
                       user2_balance_after_contract_destruct)
        assert_greater_than_or_equal(
            user2_balance_after_contract_destruct,
            user2_balance_after_deposit + user2_refund_upper_bound + 10**18)

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

        file_dir = os.path.dirname(os.path.realpath(__file__))

        self.log.info("Initializing contract")

        self.buggy_contract = get_contract_instance(source=os.path.join(
            file_dir, "contracts/reentrancy.sol"),
                                                    contract_name="Reentrance")
        self.exploit_contract = get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy_exploit.sol"),
            contract_name="ReentranceExploit")

        user1, _ = ec_random_keys()
        user1_addr = priv_to_addr(user1)
        user2, _ = ec_random_keys()
        user2_addr = priv_to_addr(user2)

        # setup balance
        value = (10**15 + 2000) * 10**18 + ReentrancyTest.REQUEST_BASE['gas']
        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user1_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user2_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, value)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, value)

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "constructor", [],
                                                  self.genesis_priv_key,
                                                  storage_limit=20000)
        contract_addr = self.wait_for_tx([transaction],
                                         True)[0]['contractCreated']

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "constructor", [],
                                                  user2,
                                                  storage_limit=200000)
        exploit_addr = self.wait_for_tx([transaction],
                                        True)[0]['contractCreated']

        transaction = self.call_contract_function(
            self.buggy_contract,
            "addBalance", [],
            user1,
            100000000000000000000000000000000,
            contract_addr,
            True,
            True,
            storage_limit=128)
        transaction = self.call_contract_function(
            self.exploit_contract,
            "deposit", [Web3.toChecksumAddress(contract_addr)],
            user2,
            100000000000000000000000000000000,
            exploit_addr,
            True,
            True,
            storage_limit=128)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     899999999999999999999999950000000)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     899999999999999999999999900000000)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(balance, 200000000000000000000000000000000)

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "launch_attack", [],
                                                  user2,
                                                  0,
                                                  exploit_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)
        transaction = self.call_contract_function(self.exploit_contract,
                                                  "get_money", [],
                                                  user2,
                                                  0,
                                                  exploit_addr,
                                                  True,
                                                  True,
                                                  storage_limit=128)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     899999999999999999999999950000000)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     1099999999999999999999999800000000)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(balance, 0)

        block_gen_thread.stop()
        block_gen_thread.join()
    def run_test(self):
        self.log.propagate = False

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

        solc = Solc()
        file_dir = os.path.dirname(os.path.realpath(__file__))

        self.log.info("Initializing contract")

        self.buggy_contract = solc.get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy.sol"),
            contract_name="Reentrance")
        self.exploit_contract = solc.get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy_exploit.sol"),
            contract_name="ReentranceExploit")

        user1, _ = ec_random_keys()
        user1_addr = privtoaddr(user1)
        user2, _ = ec_random_keys()
        user2_addr = privtoaddr(user2)
        # tx = create_transaction(
        #     pri_key=self.default_account_key,
        #     receiver=privtoaddr(buggy_contract_owner),
        #     value=1000000000000000000000000000000000,
        #     nonce=self.get_nonce(privtoaddr(self.default_account_key)),
        #     gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        # self.send_transaction(tx, True, False)

        tx = create_transaction(pri_key=self.default_account_key,
                                receiver=user1_addr,
                                value=1000000000000000000000000000000000,
                                nonce=self.get_nonce(
                                    privtoaddr(self.default_account_key)),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        tx = create_transaction(pri_key=self.default_account_key,
                                receiver=user2_addr,
                                value=1000000000000000000000000000000000,
                                nonce=self.get_nonce(
                                    privtoaddr(self.default_account_key)),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, 1000000000000000000000000000000000)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, 1000000000000000000000000000000000)

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "constructor", [],
                                                  self.default_account_key)
        contract_addr = self.wait_for_tx([transaction],
                                         True)[0]['contractCreated']

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "constructor", [], user2)
        exploit_addr = self.wait_for_tx([transaction],
                                        True)[0]['contractCreated']

        transaction = self.call_contract_function(
            self.buggy_contract, "addBalance", [], user1,
            100000000000000000000000000000000, contract_addr, True, True)
        transaction = self.call_contract_function(
            self.exploit_contract, "deposit",
            [Web3.toChecksumAddress(contract_addr)], user2,
            100000000000000000000000000000000, exploit_addr, True, True)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, 899999999999999999999999950000000)
        addr = eth_utils.encode_hex(user2_addr)
        assert_equal(balance, 899999999999999999999999950000000)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(balance, 200000000000000000000000000000000)

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "launch_attack", [], user2,
                                                  0, exploit_addr, True, True)
        transaction = self.call_contract_function(self.exploit_contract,
                                                  "get_money", [], user2, 0,
                                                  exploit_addr, True, True)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, 899999999999999999999999950000000)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, 1099999999999999999999999800000000)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(balance, 0)

        block_gen_thread.stop()
        block_gen_thread.join()
    def run_test(self):
        # Pos contract enabled, stake and register in the first hard-fork phase.
        client = RpcClient(self.nodes[self.num_nodes - 1])
        client.generate_empty_blocks(300)
        sync_blocks(self.nodes)
        for node in self.nodes[:-1]:
            client = RpcClient(node)
            pos_identifier, _ = client.wait_for_pos_register()
            sync_blocks(self.nodes)
        client = RpcClient(self.nodes[self.num_nodes - 1])

        # generate blocks until we are after pos initialization and before pos start.
        best_epoch = client.epoch_number()
        client.generate_empty_blocks(600 - best_epoch)
        sync_blocks(self.nodes)

        voting_power_map = {}
        pub_keys_map = {}
        logs = client.get_logs(filter=Filter(from_epoch="earliest", to_epoch="latest_state", address=["0x0888000000000000000000000000000000000005"]))
        for log in logs:
            pos_identifier = log["topics"][1]
            if log["topics"][0] == REGISTER_TOPIC:
                bls_pub_key, vrf_pub_key = eth_abi.decode_abi(["bytes", "bytes"], decode_hex(log["data"]))
                pub_keys_map[pos_identifier] = (encode_hex_0x(bls_pub_key), encode_hex_0x(vrf_pub_key))
            elif log["topics"][0] == INCREASE_STAKE_TOPIC:
                assert pos_identifier in pub_keys_map
                voting_power_map[pos_identifier] = parse_as_int(log["data"])
        with open(os.path.join(self.options.tmpdir, "public_keys"), "w") as f:
            for pos_identifier in pub_keys_map.keys():
                f.write(",".join([pub_keys_map[pos_identifier][0][2:], pub_keys_map[pos_identifier][1][2:], str(voting_power_map[pos_identifier])]) + "\n")
        initialize_tg_config(self.options.tmpdir, len(self.nodes), len(self.nodes), DEFAULT_PY_TEST_CHAIN_ID, pkfile="public_keys")

        # generate blocks until pos start
        self.nodes[0].generate_empty_blocks(500)
        sync_blocks(self.nodes)
        pos_identifier, _ = client.wait_for_pos_register()
        client.generate_empty_blocks(400)
        sync_blocks(self.nodes)
        time.sleep(2)

        latest_pos_ref = self.latest_pos_ref()
        for i in range(55):
            print(i)
            if i == 10:
                self.stop_node(5, clean=True)
                self.start_node(5, phase_to_wait=None)
                self.nodes[5].wait_for_recovery(["NormalSyncPhase"], 30)
            if i == 12:
                self.maybe_restart_node(5, 1, 0)
            if i == 15:
                assert_equal(int(client.pos_get_account(pos_identifier)["status"]["availableVotes"], 0), 2000)
                client.pos_retire_self()
            if i == 30:
                self.maybe_restart_node(5, 1, 1)
            # Retire node 3 after 5 min.
            # Generate enough PoW block for PoS to progress
            self.nodes[0].generate_empty_blocks(60)
            # Leave some time for PoS to reach consensus
            time.sleep(3)
            self.nodes[0].generate_empty_blocks(1)
            new_pos_ref = self.latest_pos_ref()
            if i >= 10:
                assert_ne(latest_pos_ref, new_pos_ref)

        client.wait_for_unstake(client.node.pow_sk)
        assert client.get_balance(eth_utils.encode_hex(priv_to_addr(client.node.pow_sk))) > 10000 * 10**18
        assert_equal(int(client.pos_get_account(pos_identifier)["status"]["availableVotes"], 0), 0)
    def run_test(self):
        self.log.propagate = False

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

        solc = Solc()
        file_dir = os.path.dirname(os.path.realpath(__file__))

        self.log.info("Initializing contract")

        self.buggy_contract = solc.get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy.sol"),
            contract_name="Reentrance")
        self.exploit_contract = solc.get_contract_instance(
            source=os.path.join(file_dir, "contracts/reentrancy_exploit.sol"),
            contract_name="ReentranceExploit")

        user1, _ = ec_random_keys()
        user1_addr = privtoaddr(user1)
        user2, _ = ec_random_keys()
        user2_addr = privtoaddr(user2)

        # setup balance
        value = (10**15 + 2000) * 10**18 + ReentrancyTest.REQUEST_BASE['gas']
        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user1_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        tx = create_transaction(pri_key=self.genesis_priv_key,
                                receiver=user2_addr,
                                value=value,
                                nonce=self.get_nonce(self.genesis_addr),
                                gas_price=ReentrancyTest.REQUEST_BASE['gas'])
        self.send_transaction(tx, True, False)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, value)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_equal(balance, value)

        # lock balance in bank
        node = self.nodes[0]
        client = RpcClient(node)
        staking_contract = solc.get_contract_instance(
            abi_file=os.path.join(
                file_dir, "contracts/storage_interest_staking_abi.json"),
            bytecode_file=os.path.join(
                file_dir, "contracts/storage_interest_staking_bytecode.dat"),
        )
        staking_contract_addr = Web3.toChecksumAddress(
            "443c409373ffd5c0bec1dddb7bec830856757b65")
        tx_conf = copy.deepcopy(ReentrancyTest.REQUEST_BASE)
        tx_conf['to'] = staking_contract_addr
        tx_data = decode_hex(
            staking_contract.functions.deposit(
                2000 * 10**18).buildTransaction(tx_conf)["data"])
        tx1 = client.new_tx(value=0,
                            sender=eth_utils.encode_hex(user1_addr),
                            receiver=staking_contract_addr,
                            nonce=self.get_nonce(user1_addr),
                            data=tx_data,
                            gas=ReentrancyTest.REQUEST_BASE['gas'],
                            gas_price=ReentrancyTest.REQUEST_BASE['gasPrice'],
                            priv_key=eth_utils.encode_hex(user1))
        tx2 = client.new_tx(value=0,
                            sender=eth_utils.encode_hex(user2_addr),
                            receiver=staking_contract_addr,
                            nonce=self.get_nonce(user2_addr),
                            data=tx_data,
                            gas=ReentrancyTest.REQUEST_BASE['gas'],
                            gas_price=ReentrancyTest.REQUEST_BASE['gasPrice'],
                            priv_key=eth_utils.encode_hex(user2))
        client.send_tx(tx1)
        client.send_tx(tx2)
        self.wait_for_tx([tx1, tx2], False)

        transaction = self.call_contract_function(self.buggy_contract,
                                                  "constructor", [],
                                                  self.genesis_priv_key)
        contract_addr = self.wait_for_tx([transaction],
                                         True)[0]['contractCreated']

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "constructor", [], user2)
        exploit_addr = self.wait_for_tx([transaction],
                                        True)[0]['contractCreated']

        transaction = self.call_contract_function(
            self.buggy_contract, "addBalance", [], user1,
            100000000000000000000000000000000, contract_addr, True, True)
        transaction = self.call_contract_function(
            self.exploit_contract, "deposit",
            [Web3.toChecksumAddress(contract_addr)], user2,
            100000000000000000000000000000000, exploit_addr, True, True)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     899999999999999999999999950000000)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     899999999999999999999999900000000)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(balance, 200000000000000000000000000000000)

        transaction = self.call_contract_function(self.exploit_contract,
                                                  "launch_attack", [], user2,
                                                  0, exploit_addr, True, True)
        transaction = self.call_contract_function(self.exploit_contract,
                                                  "get_money", [], user2, 0,
                                                  exploit_addr, True, True)

        addr = eth_utils.encode_hex(user1_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     899999999999999999999999950000000)
        addr = eth_utils.encode_hex(user2_addr)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
        assert_greater_than_or_equal(balance,
                                     1099999999999999999999999800000000)
        balance = parse_as_int(self.nodes[0].cfx_getBalance(contract_addr))
        assert_equal(balance, 0)

        block_gen_thread.stop()
        block_gen_thread.join()
def process_chain(chain):
    for i in range(len(chain)):
        chain[i][1] = parse_as_int(chain[i][1])
    return chain