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
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}
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