def run_test(self): # Prevent easysolc from configuring the root logger to print to stderr self.log.propagate = False solc = Solc() # erc20_contract = solc.get_contract_instance(source=os.path.dirname(os.path.realpath(__file__)) + "/erc20.sol", contract_name="FixedSupplyToken") file_dir = os.path.dirname(os.path.realpath(__file__)) erc20_contract = solc.get_contract_instance( abi_file = os.path.join(file_dir, "contracts/erc20_abi.json"), bytecode_file = os.path.join(file_dir, "contracts/erc20_bytecode.dat"), ) start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_key = default_config["GENESIS_PRI_KEY"] genesis_addr = privtoaddr(genesis_key) nonce = 0 gas_price = 1 gas = 50000000 block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() self.tx_conf = {"from":Web3.toChecksumAddress(encode_hex_0x(genesis_addr)), "nonce":int_to_hex(nonce), "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0} raw_create = erc20_contract.constructor().buildTransaction(self.tx_conf) tx_data = decode_hex(raw_create["data"]) tx_create = create_transaction(pri_key=genesis_key, receiver=b'', nonce=nonce, gas_price=gas_price, data=tx_data, gas=gas, value=0) self.nodes[0].p2p.send_protocol_msg(Transactions(transactions=[tx_create])) self.wait_for_tx([tx_create]) self.log.info("Contract created, start transfering tokens") tx_n = 10 self.tx_conf["to"] = Web3.toChecksumAddress(encode_hex_0x(sha3_256(rlp.encode([genesis_addr, nonce]))[-20:])) nonce += 1 balance_map = {genesis_key: 1000000 * 10**18} sender_key = genesis_key all_txs = [] for i in range(tx_n): value = int((balance_map[sender_key] - ((tx_n - i) * 21000 * gas_price)) * random.random()) receiver_sk, _ = ec_random_keys() balance_map[receiver_sk] = value tx_data = decode_hex(erc20_contract.functions.transfer(Web3.toChecksumAddress(encode_hex(privtoaddr(receiver_sk))), value).buildTransaction(self.tx_conf)["data"]) tx = create_transaction(pri_key=sender_key, receiver=decode_hex(self.tx_conf["to"]), value=0, nonce=nonce, gas=gas, gas_price=gas_price, data=tx_data) r = random.randint(0, self.num_nodes - 1) self.nodes[r].p2p.send_protocol_msg(Transactions(transactions=[tx])) nonce += 1 balance_map[sender_key] -= value all_txs.append(tx) self.log.info("Wait for transactions to be executed") self.wait_for_tx(all_txs) self.log.info("Check final token balance") for sk in balance_map: addr = privtoaddr(sk) assert_equal(self.get_balance(erc20_contract, addr, nonce), balance_map[sk]) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) self.log.info("Pass")
def run_test(self): file_dir = os.path.dirname(os.path.realpath(__file__)) storage_contract = get_contract_instance( abi_file=os.path.join(file_dir, "contracts/simple_storage.abi"), bytecode_file=os.path.join(file_dir, "contracts/simple_storage.dat"), ) start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_addr = self.genesis_addr self.log.info("genesis_addr={}".format(encode_hex_0x(genesis_addr))) block_gen_thread = BlockGenThread(self.nodes, self.log, interval_fixed=1) block_gen_thread.start() client = RpcClient(self.nodes[0]) tx = client.new_tx(value=int(0.625 * CFX) + GDrip, receiver=self.eth_hex_addr, nonce=self.get_nonce(genesis_addr)) client.send_tx(tx, True) assert_equal(client.get_balance(self.eth_hex_addr), int(0.625 * CFX) + GDrip) # deploy contract self.log.info("Deploying contract") tx = self.call_contract_function( contract=storage_contract, name="constructor", args=[], sender_key=self.eth_priv_key, eth_tx=True, ) wait_until(lambda: self.nodes[1].tx_inspect(tx.hash_hex())['exist'], timeout=10) block_gen_thread.stop() client.generate_blocks(40) block_hash = client.generate_custom_block(client.best_block_hash(), [], [tx]) wait_until(lambda: client.best_block_hash() == block_hash, timeout=10) client.generate_blocks(40) BlockGenThread(self.nodes, self.log, interval_fixed=1).start() receipt = self.wait_for_tx([tx])[0] assert_greater_than_or_equal(int(receipt['epochNumber'], 0), 80) self.log.info("All test done")
def run_test(self): genesis_key = default_config["GENESIS_PRI_KEY"] balance_map = {genesis_key: default_config["TOTAL_COIN"]} self.log.info("Initial State: (sk:%d, addr:%s, balance:%d)", bytes_to_int(genesis_key), eth_utils.encode_hex(priv_to_addr(genesis_key)), balance_map[genesis_key]) nonce_map = {genesis_key: 0} # '''Check if transaction from uncommitted new address can be accepted''' # tx_n = 5 # receiver_sk = genesis_key gas_price = 1 # for i in range(tx_n): # sender_key = receiver_sk # value = int((balance_map[sender_key] - ((tx_n - i) * 21000 * gas_price)) * random.random()) # nonce = nonce_map[sender_key] # receiver_sk, _ = ec_random_keys() # nonce_map[receiver_sk] = 0 # balance_map[receiver_sk] = value # tx = create_transaction(pri_key=sender_key, receiver=privtoaddr(receiver_sk), value=value, nonce=nonce, # gas_price=gas_price) # r = random.randint(0, self.num_nodes - 1) # self.nodes[r].p2p.send_protocol_msg(Transactions(transactions=[tx])) # nonce_map[sender_key] = nonce + 1 # balance_map[sender_key] -= value + gas_price * 21000 # self.log.debug("New tx %s: %s send value %d to %s, sender balance:%d, receiver balance:%d", encode_hex(tx.hash), eth_utils.encode_hex(privtoaddr(sender_key))[-4:], # value, eth_utils.encode_hex(privtoaddr(receiver_sk))[-4:], balance_map[sender_key], balance_map[receiver_sk]) # self.log.debug("Send Transaction %s to node %d", encode_hex(tx.hash), r) # time.sleep(random.random() / 10 * self.delay_factor) block_gen_thread = BlockGenThread(self.nodes, self.log, interval_base=self.delay_factor) block_gen_thread.start() # for k in balance_map: # self.log.info("Check account sk:%s addr:%s", bytes_to_int(k), eth_utils.encode_hex(privtoaddr(k))) # wait_until(lambda: self.check_account(k, balance_map), timeout=60*self.delay_factor) # self.log.info("Pass 1") # self.register_test("general_1.json") '''Test Random Transactions''' all_txs = [] tx_n = 1000 account_n = 10 # Initialize new accounts new_keys = set() for _ in range(account_n): value = int(balance_map[genesis_key] * 0.5) receiver_sk, _ = ec_random_keys() new_keys.add(receiver_sk) tx = create_transaction(pri_key=genesis_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce_map[genesis_key], gas_price=gas_price) self.nodes[0].p2p.send_protocol_msg( Transactions(transactions=[tx])) balance_map[receiver_sk] = value nonce_map[genesis_key] += 1 balance_map[genesis_key] -= value + gas_price * 21000 wait_for_account_stable() for key in new_keys: nonce_map[key] = wait_for_initial_nonce_for_privkey( self.nodes[0], key) self.log.info( "start to generate %d transactions with about %d seconds", tx_n, tx_n / 10 / 2 * self.delay_factor) for i in range(tx_n): sender_key = random.choice(list(balance_map)) nonce = nonce_map[sender_key] value = 1 receiver_sk = random.choice(list(balance_map)) balance_map[receiver_sk] += value # not enough transaction fee (gas_price * gas_limit) should not happen for now assert balance_map[sender_key] >= value + gas_price * 21000 tx = create_transaction(pri_key=sender_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) r = random.randint(0, self.num_nodes - 1) self.nodes[r].p2p.send_protocol_msg( Transactions(transactions=[tx])) all_txs.append(tx) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 self.log.debug( "New tx %s: %s send value %d to %s, sender balance:%d, receiver balance:%d nonce:%d", encode_hex(tx.hash), eth_utils.encode_hex(priv_to_addr(sender_key))[-4:], value, eth_utils.encode_hex(priv_to_addr(receiver_sk))[-4:], balance_map[sender_key], balance_map[receiver_sk], nonce) self.log.debug("Send Transaction %s to node %d", encode_hex(tx.hash), r) time.sleep(random.random() / 10 * self.delay_factor) for k in balance_map: self.log.info("Account %s with balance:%s", bytes_to_int(k), balance_map[k]) for tx in all_txs: self.log.debug("Wait for tx to confirm %s", tx.hash_hex()) for i in range(3): try: retry = True while retry: try: wait_until( lambda: checktx(self.nodes[0], tx.hash_hex()), timeout=60 * self.delay_factor) retry = False except CannotSendRequest: time.sleep(0.01) break except AssertionError as _: self.nodes[0].p2p.send_protocol_msg( Transactions(transactions=[tx])) if i == 2: raise AssertionError( "Tx {} not confirmed after 30 seconds".format( tx.hash_hex())) for k in balance_map: self.log.info("Check account sk:%s addr:%s", bytes_to_int(k), eth_utils.encode_hex(priv_to_addr(k))) wait_until(lambda: self.check_account(k, balance_map), timeout=60 * self.delay_factor) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes, timeout=60 * self.delay_factor) self.log.info("Pass") self.register_test("general_2.json")
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): genesis_key = default_config["GENESIS_PRI_KEY"] balance_map = {genesis_key: default_config["TOTAL_COIN"]} self.log.info("Initial State: (sk:%d, addr:%s, balance:%d)", bytes_to_int(genesis_key), eth_utils.encode_hex(privtoaddr(genesis_key)), balance_map[genesis_key]) nonce_map = {genesis_key: 0} '''Check if transaction from uncommitted new address can be accepted''' tx_n = 5 receiver_sk = genesis_key gas_price = 1 for i in range(tx_n): sender_key = receiver_sk value = int((balance_map[sender_key] - ((tx_n - i) * 21000 * gas_price)) * random.random()) nonce = nonce_map[sender_key] receiver_sk, _ = ec_random_keys() nonce_map[receiver_sk] = 0 balance_map[receiver_sk] = value tx = create_transaction(pri_key=sender_key, receiver=privtoaddr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) r = random.randint(0, self.num_nodes - 1) self.nodes[r].p2p.send_protocol_msg( Transactions(transactions=[tx])) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 self.log.debug( "New tx %s: %s send value %d to %s, sender balance:%d, receiver balance:%d", encode_hex(tx.hash), eth_utils.encode_hex(privtoaddr(sender_key))[-4:], value, eth_utils.encode_hex(privtoaddr(receiver_sk))[-4:], balance_map[sender_key], balance_map[receiver_sk]) self.log.debug("Send Transaction %s to node %d", encode_hex(tx.hash), r) time.sleep(random.random() / 100) block_gen_thread = BlockGenThread(self.nodes, self.log, interval_base=0.2) block_gen_thread.start() for k in balance_map: self.log.info("Check account sk:%s addr:%s", bytes_to_int(k), eth_utils.encode_hex(privtoaddr(k))) wait_until(lambda: self.check_account(k, balance_map)) self.log.info("Pass 1") '''Test Random Transactions''' all_txs = [] tx_n = 1000 self.log.info( "start to generate %d transactions with about %d seconds", tx_n, tx_n / 100 / 2) for i in range(tx_n): sender_key = random.choice(list(balance_map)) nonce = nonce_map[sender_key] data = b'' rand_n = random.random() gas = 21000 if rand_n < 0.1 and balance_map[sender_key] > 21000 * 4 * tx_n: value = int(balance_map[sender_key] * 0.5) receiver_sk, _ = ec_random_keys() receiver = privtoaddr(receiver_sk) nonce_map[receiver_sk] = 0 balance_map[receiver_sk] = value elif rand_n > 0.9 and balance_map[sender_key] > 21000 * 4 * tx_n: value = 0 receiver = b'' data = bytes([ 96, 128, 96, 64, 82, 52, 128, 21, 97, 0, 16, 87, 96, 0, 128, 253, 91, 80, 96, 5, 96, 0, 129, 144, 85, 80, 96, 230, 128, 97, 0, 39, 96, 0, 57, 96, 0, 243, 254, 96, 128, 96, 64, 82, 96, 4, 54, 16, 96, 67, 87, 96, 0, 53, 124, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 4, 128, 99, 96, 254, 71, 177, 20, 96, 72, 87, 128, 99, 109, 76, 230, 60, 20, 96, 127, 87, 91, 96, 0, 128, 253, 91, 52, 128, 21, 96, 83, 87, 96, 0, 128, 253, 91, 80, 96, 125, 96, 4, 128, 54, 3, 96, 32, 129, 16, 21, 96, 104, 87, 96, 0, 128, 253, 91, 129, 1, 144, 128, 128, 53, 144, 96, 32, 1, 144, 146, 145, 144, 80, 80, 80, 96, 167, 86, 91, 0, 91, 52, 128, 21, 96, 138, 87, 96, 0, 128, 253, 91, 80, 96, 145, 96, 177, 86, 91, 96, 64, 81, 128, 130, 129, 82, 96, 32, 1, 145, 80, 80, 96, 64, 81, 128, 145, 3, 144, 243, 91, 128, 96, 0, 129, 144, 85, 80, 80, 86, 91, 96, 0, 128, 84, 144, 80, 144, 86, 254, 161, 101, 98, 122, 122, 114, 48, 88, 32, 181, 24, 13, 149, 253, 195, 129, 48, 40, 237, 71, 246, 44, 124, 223, 112, 139, 118, 192, 219, 9, 64, 67, 245, 51, 180, 42, 67, 13, 49, 62, 21, 0, 41 ]) gas = 10000000 else: value = 1 receiver_sk = random.choice(list(balance_map)) receiver = privtoaddr(receiver_sk) balance_map[receiver_sk] += value # not enough transaction fee (gas_price * gas_limit) should not happen for now assert balance_map[sender_key] >= value + gas_price * 21000 tx = create_transaction(pri_key=sender_key, receiver=receiver, value=value, nonce=nonce, gas_price=gas_price, data=data, gas=gas) r = random.randint(0, self.num_nodes - 1) self.nodes[r].p2p.send_protocol_msg( Transactions(transactions=[tx])) all_txs.append(tx) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * gas self.log.debug( "New tx %s: %s send value %d to %s, sender balance:%d, receiver balance:%d nonce:%d", encode_hex(tx.hash), eth_utils.encode_hex(privtoaddr(sender_key))[-4:], value, eth_utils.encode_hex(privtoaddr(receiver_sk))[-4:], balance_map[sender_key], balance_map[receiver_sk], nonce) self.log.debug("Send Transaction %s to node %d", encode_hex(tx.hash), r) time.sleep(random.random() / 100) for k in balance_map: self.log.info("Account %s with balance:%s", bytes_to_int(k), balance_map[k]) for tx in all_txs: self.log.debug("Wait for tx to confirm %s", tx.hash_hex()) for i in range(3): try: retry = True while retry: try: wait_until( lambda: checktx(self.nodes[0], tx.hash_hex()), timeout=120) retry = False except CannotSendRequest: time.sleep(0.01) break except AssertionError as _: self.nodes[0].p2p.send_protocol_msg( Transactions(transactions=[tx])) if i == 2: raise AssertionError( "Tx {} not confirmed after 30 seconds".format( tx.hash_hex())) for k in balance_map: self.log.info("Check account sk:%s addr:%s", bytes_to_int(k), eth_utils.encode_hex(privtoaddr(k))) wait_until(lambda: self.check_account(k, balance_map)) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) self.log.info("Pass")
def run_test(self): file_dir = os.path.dirname(os.path.realpath(__file__)) erc20_contract = get_contract_instance( abi_file=os.path.join(file_dir, "contracts/erc20_abi.json"), bytecode_file=os.path.join(file_dir, "contracts/erc20_bytecode.dat"), ) gas_price = 1 gas = CONTRACT_DEFAULT_GAS start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_key = default_config["GENESIS_PRI_KEY"] genesis_addr = encode_hex_0x(priv_to_addr(genesis_key)) nonce = 0 block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() self.tx_conf = { "from": Web3.toChecksumAddress(genesis_addr), "nonce": int_to_hex(nonce), "gas": int_to_hex(gas), "gasPrice": int_to_hex(gas_price), "chainId": 0 } raw_create = erc20_contract.constructor().buildTransaction( self.tx_conf) tx_data = decode_hex(raw_create["data"]) tx_create = create_transaction(pri_key=genesis_key, receiver=b'', nonce=nonce, gas_price=gas_price, data=tx_data, gas=gas, value=0, storage_limit=1920) client = RpcClient(self.nodes[0]) c0 = client.get_collateral_for_storage(genesis_addr) client.send_tx(tx_create, True) receipt = client.get_transaction_receipt(tx_create.hash_hex()) c1 = client.get_collateral_for_storage(genesis_addr) assert_equal(c1 - c0, 1920 * 10**18 / 1024) contract_addr = receipt['contractCreated'] self.log.info("Contract " + str(contract_addr) + " created, start transferring tokens") tx_n = 10 self.tx_conf["to"] = contract_addr nonce += 1 balance_map = {genesis_key: 1000000 * 10**18} sender_key = genesis_key all_txs = [] for i in range(tx_n): value = int((balance_map[sender_key] - ((tx_n - i) * 21000 * gas_price)) * random.random()) receiver_sk, _ = ec_random_keys() balance_map[receiver_sk] = value tx_data = decode_hex( erc20_contract.functions.transfer( Web3.toChecksumAddress( encode_hex(priv_to_addr(receiver_sk))), value).buildTransaction(self.tx_conf)["data"]) tx = create_transaction(pri_key=sender_key, receiver=decode_hex(self.tx_conf["to"]), value=0, nonce=nonce, gas=gas, gas_price=gas_price, data=tx_data, storage_limit=64) r = random.randint(0, self.num_nodes - 1) self.nodes[r].p2p.send_protocol_msg( Transactions(transactions=[tx])) nonce += 1 balance_map[sender_key] -= value all_txs.append(tx) self.log.info("Wait for transactions to be executed") self.wait_for_tx(all_txs) self.log.info("Check final token balance") for sk in balance_map: addr = priv_to_addr(sk) assert_equal(self.get_balance(erc20_contract, addr, nonce), balance_map[sk]) c2 = client.get_collateral_for_storage(genesis_addr) assert_equal(c2 - c1, 64 * tx_n * 10**18 / 1024) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) self.log.info("Pass")
def 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()
def run_test(self): # Start mininode connection default_node = DefaultNode() self.node = default_node kwargs = {} args = {} kwargs['dstport'] = 32323 kwargs['dstaddr'] = '127.0.0.1' default_node.peer_connect(*args, **kwargs) network_thread_start() default_node.wait_for_status() # Start rpc connection self.rpc_client = RpcClient(get_simple_rpc_proxy( "http://127.0.0.1:12537")) node_id = self.rpc_client.get_node_id() self.log.info("get nodeid %s", eth_utils.encode_hex(node_id)) block_gen_thread = BlockGenThread([self.rpc_client.node], self.log, num_txs = 100, interval_fixed=0.2) block_gen_thread.start() genesis_key = default_config["GENESIS_PRI_KEY"] balance_map = {genesis_key: default_config["TOTAL_COIN"]} self.log.info("Initial State: (sk:%d, addr:%s, balance:%d)", bytes_to_int(genesis_key), eth_utils.encode_hex(priv_to_addr(genesis_key)), balance_map[genesis_key]) nonce_map = {genesis_key: 0} '''Test Random Transactions''' all_txs = [] tx_n = 10000 gas_price = 1 self.log.info("start to generate %d transactions with about %d seconds", tx_n, tx_n/10/2) for i in range(tx_n): if i % 1000 == 0: self.log.info("generated %d tx", i) sender_key = random.choice(list(balance_map)) nonce = nonce_map[sender_key] if random.random() < 0.1 and balance_map[sender_key] > 21000 * 4 * tx_n: value = int(balance_map[sender_key] * 0.5) receiver_sk, _ = ec_random_keys() nonce_map[receiver_sk] = 0 balance_map[receiver_sk] = value else: value = 1 receiver_sk = random.choice(list(balance_map)) balance_map[receiver_sk] += value # not enough transaction fee (gas_price * gas_limit) should not happen for now assert balance_map[sender_key] >= value + gas_price * 21000 tx = create_transaction(pri_key=sender_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) all_txs.append(tx) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 i = 0 for tx in all_txs: i += 1 if i % 1000 == 0: self.log.info("Sent %d tx", i) self.node.send_protocol_msg(Transactions(transactions=[tx])) for k in balance_map: wait_until(lambda: self.check_account(k, balance_map)) block_gen_thread.stop() block_gen_thread.join() self.log.info("Pass") while True: pass
def run_test(self): # Prevent easysolc from configuring the root logger to print to stderr self.log.propagate = False solc = Solc() file_dir = os.path.dirname(os.path.realpath(__file__)) 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"), ) start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_key = default_config["GENESIS_PRI_KEY"] genesis_addr = privtoaddr(genesis_key) nonce = 0 gas_price = 1 gas = 50000000 block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() self.tx_conf = { "from": Web3.toChecksumAddress(encode_hex_0x(genesis_addr)), "nonce": int_to_hex(nonce), "gas": int_to_hex(gas), "gasPrice": int_to_hex(gas_price), "chainId": 0 } # Setup balance for node 0 node = self.nodes[0] client = RpcClient(node) (addr, priv_key) = client.rand_account() self.log.info("addr=%s priv_key=%s", addr, priv_key) tx = client.new_tx(value=5 * 10**18, receiver=addr, nonce=0) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(node.cfx_getBalance(addr), hex(5000000000000000000)) assert_equal(node.cfx_getBankBalance(addr), hex(0)) self.tx_conf["to"] = Web3.toChecksumAddress( "443c409373ffd5c0bec1dddb7bec830856757b65") # deposit 10**18 tx_data = decode_hex( staking_contract.functions.deposit(10**18).buildTransaction( self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], nonce=0, gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(node.cfx_getBankBalance(addr), hex(10**18)) # withdraw 5 * 10**17 tx_data = decode_hex( staking_contract.functions.withdraw(5 * 10**17).buildTransaction( self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], nonce=1, gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(node.cfx_getBankBalance(addr), hex(5 * 10**17)) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) self.log.info("Pass")
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): # Start mininode connection self.node = self.nodes[0] start_p2p_connection([self.node]) block_gen_thread = BlockGenThread([self.node], self.log, num_txs=10000, interval_fixed=0.2) block_gen_thread.start() tx_n = 100000 generate = False if generate: f = open("encoded_tx", "wb") '''Test Random Transactions''' genesis_key = default_config["GENESIS_PRI_KEY"] balance_map = {genesis_key: default_config["TOTAL_COIN"]} nonce_map = {genesis_key: 0} all_txs = [] gas_price = 1 account_n = 10 # Initialize new accounts new_keys = set() for _ in range(account_n): value = int(balance_map[genesis_key] * 0.5) receiver_sk, _ = ec_random_keys() new_keys.add(receiver_sk) tx = create_transaction(pri_key=genesis_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce_map[genesis_key], gas_price=gas_price) all_txs.append(tx) balance_map[receiver_sk] = value nonce_map[genesis_key] += 1 balance_map[genesis_key] -= value + gas_price * 21000 wait_for_account_stable() for key in new_keys: nonce_map[key] = wait_for_initial_nonce_for_privkey( self.nodes[0], key) self.log.info("start to generate %d transactions", tx_n) for i in range(tx_n): if i % 1000 == 0: self.log.debug("generated %d tx", i) sender_key = random.choice(list(balance_map)) if sender_key not in nonce_map: nonce_map[sender_key] = wait_for_initial_nonce_for_privkey( self.nodes[0], sender_key) nonce = nonce_map[sender_key] value = 1 receiver_sk = random.choice(list(balance_map)) balance_map[receiver_sk] += value # not enough transaction fee (gas_price * gas_limit) should not happen for now assert balance_map[sender_key] >= value + gas_price * 21000 tx = create_transaction(pri_key=sender_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) self.log.debug( "%s send %d to %s nonce=%d balance: sender=%s, receiver=%s", encode_hex(priv_to_addr(sender_key)), value, encode_hex(priv_to_addr(receiver_sk)), nonce, balance_map[sender_key], balance_map[receiver_sk]) all_txs.append(tx) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 encoded_txs = [] batch_tx = [] i = 0 for tx in all_txs: batch_tx.append(tx) i += 1 if i % 1000 == 0: encoded = rlp.encode(Transactions(transactions=batch_tx)) encoded_txs.append(encoded) batch_tx = [] pickle.dump(encoded_txs, f) pickle.dump(balance_map, f) else: f = open("encoded_tx", "rb") encoded_txs = pickle.load(f) balance_map = pickle.load(f) f.close() start_time = datetime.datetime.now() for encoded in encoded_txs: self.node.p2p.send_protocol_packet( int_to_bytes(TRANSACTIONS) + encoded) for k in balance_map: wait_until(lambda: self.check_account(k, balance_map)) end_time = datetime.datetime.now() time_used = (end_time - start_time).total_seconds() block_gen_thread.stop() block_gen_thread.join() self.log.info("Time used: %f seconds", time_used) self.log.info("Tx per second: %f", tx_n / time_used)
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 run_test(self): # Start mininode connection self.node = self.nodes[0] start_p2p_connection([self.node]) block_gen_thread = BlockGenThread([self.node], self.log, num_txs=10000, interval_fixed=0.02) block_gen_thread.start() tx_n = 500000 batch_size = 10 send_tps = 20000 all_txs = [] gas_price = 1 account_n = 1000 generate = False if generate: f = open("encoded_tx", "wb") '''Test Random Transactions''' self.log.info("Setting up genesis secrets") balance_map = {} nonce_map = {} account_i = 0 for prikey_str in open( self.conf_parameters["genesis_secrets"][1:-1], "r").readlines(): prikey = decode_hex(prikey_str[:-1]) balance_map[prikey] = 10000000000000000000000 nonce_map[prikey] = 0 account_i += 1 if account_i == account_n: break # genesis_key = default_config["GENESIS_PRI_KEY"] # balance_map = {genesis_key: default_config["TOTAL_COIN"]} # nonce_map = {genesis_key: 0} # # Initialize new accounts # new_keys = set() # for _ in range(account_n): # value = int(balance_map[genesis_key] / (account_n * 2)) # receiver_sk, _ = ec_random_keys() # new_keys.add(receiver_sk) # tx = create_transaction(pri_key=genesis_key, receiver=priv_to_addr(receiver_sk), value=value, # nonce=nonce_map[genesis_key], gas_price=gas_price) # all_txs.append(tx) # balance_map[receiver_sk] = value # nonce_map[genesis_key] += 1 # balance_map[genesis_key] -= value + gas_price * 21000 # wait_for_account_stable() # for key in new_keys: # nonce_map[key] = wait_for_initial_nonce_for_privkey(self.nodes[0], key) self.log.info("start to generate %d transactions", tx_n) account_list = list(balance_map) for i in range(tx_n): if i % 1000 == 0: self.log.info("generated %d tx", i) sender_key = random.choice(account_list) if sender_key not in nonce_map: nonce_map[sender_key] = wait_for_initial_nonce_for_privkey( self.nodes[0], sender_key) nonce = nonce_map[sender_key] value = 1 receiver_sk = random.choice(account_list) balance_map[receiver_sk] += value # not enough transaction fee (gas_price * gas_limit) should not happen for now assert balance_map[sender_key] >= value + gas_price * 21000 tx = create_transaction(pri_key=sender_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) # self.log.debug("%s send %d to %s nonce=%d balance: sender=%s, receiver=%s", encode_hex(priv_to_addr(sender_key)), value, encode_hex(priv_to_addr(receiver_sk)), nonce, balance_map[sender_key], balance_map[receiver_sk]) all_txs.append(tx) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 encoded_txs = [] batch_tx = [] i = 0 for tx in all_txs: batch_tx.append(tx) i += 1 if i % batch_size == 0: encoded = rlp.encode(Transactions(transactions=batch_tx)) encoded_txs.append(encoded) batch_tx = [] pickle.dump(encoded_txs, f) pickle.dump(balance_map, f) else: f = open("encoded_tx", "rb") encoded_txs = pickle.load(f) balance_map = pickle.load(f) f.close() start_time = time.time() i = 0 for encoded in encoded_txs: i += 1 if i * batch_size % send_tps == 0: time_used = time.time() - start_time time.sleep(i * batch_size / send_tps - time_used) self.node.p2p.send_protocol_packet(encoded + int_to_bytes(TRANSACTIONS)) self.log.info( f"Time used to send {tx_n} transactions in {i} iterations: {time_used}" ) for k in balance_map: wait_until(lambda: self.check_account(k, balance_map), timeout=600) time_used = time.time() - start_time block_gen_thread.stop() block_gen_thread.join() self.log.info("Time used: %f seconds", time_used) self.log.info("Tx per second: %f", tx_n / time_used)
def run_test(self): start_p2p_connection(self.nodes) block_gen_thread = BlockGenThread(self.nodes, self.log, interval_base=0.2) block_gen_thread.start() genesis_key = default_config["GENESIS_PRI_KEY"] tx_n = 100 gas_price = 1 shard_balance = [] for s in range(self.n_shard): ''' Send random transactions to this shard s ''' shard_nodes = self.nodes[s * self.shard_size:(s + 1) * self.shard_size] # We can not use genesis accounts in two shards, because they may generate transactions # that are valid in another shard and breaks our assertion about the final shard state. start_sk, _ = ec_random_keys() value = default_config["TOTAL_COIN"] - 21000 tx = create_transaction(pri_key=genesis_key, receiver=priv_to_addr(start_sk), value=value, nonce=0, gas_price=gas_price) shard_nodes[0].p2p.send_protocol_msg( Transactions(transactions=[tx])) balance_map = {start_sk: value} nonce_map = { start_sk: wait_for_initial_nonce_for_privkey(shard_nodes[0], start_sk) } account_n = 10 # Initialize new accounts new_keys = set() for _ in range(account_n): value = max(int(balance_map[start_sk] * random.random()), 21000 * tx_n) receiver_sk, _ = ec_random_keys() new_keys.add(receiver_sk) tx = create_transaction(pri_key=start_sk, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce_map[start_sk], gas_price=gas_price) shard_nodes[0].p2p.send_protocol_msg( Transactions(transactions=[tx])) balance_map[receiver_sk] = value nonce_map[start_sk] += 1 balance_map[start_sk] -= value + gas_price * 21000 wait_for_account_stable() for key in new_keys: nonce_map[key] = wait_for_initial_nonce_for_privkey( shard_nodes[0], key) for i in range(tx_n): sender_key = random.choice(list(balance_map)) nonce = nonce_map[sender_key] value = 0 receiver_sk = random.choice(list(balance_map)) balance_map[receiver_sk] += value tx = create_transaction(pri_key=sender_key, receiver=priv_to_addr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) r = random.randint(0, self.shard_size - 1) shard_nodes[r].p2p.send_protocol_msg( Transactions(transactions=[tx])) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 self.log.info( "New tx %s: %s send value %d to %s, sender balance:%d, receiver balance:%d", encode_hex(tx.hash), eth_utils.encode_hex(priv_to_addr(sender_key))[-4:], value, eth_utils.encode_hex(priv_to_addr(receiver_sk))[-4:], balance_map[sender_key], balance_map[receiver_sk]) self.log.debug("Send Transaction %s to node %d", encode_hex(tx.hash), r) time.sleep(random.random() / 10) for k in balance_map: self.log.info("Check account sk:%s addr:%s", bytes_to_int(k), eth_utils.encode_hex(priv_to_addr(k))) wait_until( lambda: self.check_account(k, balance_map, shard_nodes[0])) shard_balance.append(balance_map) def epochCheck(node): r = node.cfx_epochNumber() return int(r, 0) > 110 wait_until(lambda: epochCheck(self.nodes[0])) wait_until( lambda: epochCheck(self.nodes[int(self.num_nodes / self.n_shard)])) for s in range(self.n_shard): for idx in range(self.shard_size): connect_nodes(self.nodes, s * self.shard_size - 1 + idx, s * self.shard_size + idx) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) ''' Check if the balance state of every node matches ''' success_shard = -1 # use the state of node 0 to find the winning shard for s in range(self.n_shard): balance_map = shard_balance[s] unmatch = False for k in balance_map: if not self.check_account(k, balance_map, self.nodes[0]): unmatch = True self.log.info( "Final balance does not match shard %s, check next", s) break if unmatch: continue success_shard = s break assert success_shard != -1, "The final state of node 0 matches no shard state" self.log.info("Shard %s succeeds", success_shard) for i in range(1, self.num_nodes): balance_map = shard_balance[success_shard] for k in balance_map: if not self.check_account(k, balance_map, self.nodes[i]): raise AssertionError( "Final balance of node {} does not match node 0, sender={}" .format(i, k)) self.log.info("Pass")
def run_test(self): file_dir = os.path.dirname(os.path.realpath(__file__)) storage_contract = get_contract_instance( abi_file=os.path.join(file_dir, "contracts/simple_storage.abi"), bytecode_file=os.path.join(file_dir, "contracts/simple_storage.dat"), ) start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_addr = self.genesis_addr self.log.info("genesis_addr={}".format(encode_hex_0x(genesis_addr))) block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() client = RpcClient(self.nodes[0]) client1 = RpcClient(self.nodes[1]) tx = client.new_tx(value=int(0.625 * CFX) + GDrip, receiver=self.eth_hex_addr, nonce=self.get_nonce(genesis_addr)) client.send_tx(tx, True) assert_equal(client.get_balance(self.eth_hex_addr), int(0.625 * CFX) + GDrip) # deploy pay contract block_gen_thread.stop( ) # stop the block generation to test transaction relay. time.sleep(3) self.log.info("Deploying contract") tx = self.call_contract_function( contract=storage_contract, name="constructor", args=[], sender_key=self.eth_priv_key, eth_tx=True, ) assert_equal(tx["epoch_height"], 0xffff_ffff_ffff_ffff) wait_until(lambda: self.nodes[1].txpool_txWithPoolInfo(tx.hash_hex())[ 'exist'], timeout=5) block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() receipt = self.wait_for_tx([tx], True)[0] assert_equal(int(receipt["storageCollateralized"], 0), 640) contract_addr = receipt['contractCreated'] self.log.info("contract_addr={}".format(contract_addr)) assert_equal(client.get_collateral_for_storage(self.eth_hex_addr), int(0.625 * CFX)) assert_greater_than(GDrip, client.get_balance(self.eth_hex_addr)) storage_contract = get_contract_instance( abi_file=os.path.join(file_dir, "contracts/simple_storage.abi"), bytecode_file=os.path.join(file_dir, "contracts/simple_storage.dat"), ) # Should fail because of not enough balance for storage. self.log.info("Sending transaction without enough collateral") tx = self.call_contract_function( contract=storage_contract, contract_addr=contract_addr, name="setFresh", args=[], sender_key=self.eth_priv_key, eth_tx=True, ) receipt = self.wait_for_tx([tx])[0] assert_equal(int(receipt["outcomeStatus"], 0), 1) sponsor_whitelist_contract_addr = Web3.toChecksumAddress( "0888000000000000000000000000000000000001") file_dir = os.path.dirname(os.path.realpath(__file__)) control_contract_file_path = os.path.join( file_dir, "..", "internal_contract", "metadata", "SponsorWhitelistControl.json") control_contract_dict = json.loads( open(control_contract_file_path, "r").read()) control_contract = get_contract_instance( contract_dict=control_contract_dict) self.log.info("Setting sponsor for collateral") self.call_contract_function( contract=control_contract, name="setSponsorForCollateral", args=[Web3.toChecksumAddress(contract_addr)], value=1 * CFX, sender_key=self.genesis_priv_key, contract_addr=sponsor_whitelist_contract_addr, wait=True, check_status=True) self.log.info("Sending balance to eth_like tx") tx = client.new_tx(value=int(0.0625 * CFX), receiver=self.eth_hex_addr, nonce=self.get_nonce(genesis_addr)) client.send_tx(tx, True) self.log.info("Setting whitelist for all") self.call_contract_function( contract=control_contract, name="addPrivilegeByAdmin", args=[ Web3.toChecksumAddress(contract_addr), [Web3.toChecksumAddress("0x" + "0" * 40)] ], sender_key=self.eth_priv_key, contract_addr=sponsor_whitelist_contract_addr, eth_tx=True, wait=True, check_status=True) # Should not fail because of sponsored self.log.info("Sending transaction when sponsored") time.sleep(3) block_gen_thread.stop( ) # stop the block generation to test transaction relay in sponsorship tx = self.call_contract_function( contract=storage_contract, contract_addr=contract_addr, name="setFresh", args=[], sender_key=self.eth_priv_key, eth_tx=True, ) wait_until(lambda: self.nodes[1].txpool_txWithPoolInfo(tx.hash_hex())[ 'exist'], timeout=5) block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() receipt = self.wait_for_tx([tx])[0] assert_equal(receipt["storageCoveredBySponsor"], True) assert_equal(int(receipt["storageCollateralized"], 0), 64) wait_until(lambda: checktx(self.nodes[1], tx.hash_hex()), timeout=20) 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) 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): file_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(file_dir, "..", "internal_contract", "metadata", "Staking.json") staking_contract_dict = json.loads(open(os.path.join(file_path), "r").read()) staking_contract = get_contract_instance(contract_dict=staking_contract_dict) start_p2p_connection(self.nodes) self.log.info("Initializing contract") genesis_key = default_config["GENESIS_PRI_KEY"] genesis_addr = priv_to_addr(genesis_key) nonce = 0 gas_price = 1 gas = CONTRACT_DEFAULT_GAS block_gen_thread = BlockGenThread(self.nodes, self.log) block_gen_thread.start() self.tx_conf = {"from":Web3.toChecksumAddress(encode_hex_0x(genesis_addr)), "nonce":int_to_hex(nonce), "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0} total_num_blocks = 2 * 60 * 60 * 24 * 365 accumulate_interest_rate = [2 ** 80 * total_num_blocks] for _ in range(1000): accumulate_interest_rate.append(accumulate_interest_rate[-1] * ( 40000 + 1000000 * total_num_blocks) // (total_num_blocks * 1000000)) # Setup balance for node 0 node = self.nodes[0] client = RpcClient(node) (addr, priv_key) = client.rand_account() self.log.info("addr=%s priv_key=%s", addr, priv_key) tx = client.new_tx(value=5 * 10 ** 18, receiver=addr) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(client.get_balance(addr), 5 * 10 ** 18) assert_equal(client.get_staking_balance(addr), 0) self.tx_conf["to"] = Web3.toChecksumAddress("0888000000000000000000000000000000000002") # deposit 10**18 tx_data = decode_hex(staking_contract.functions.deposit(10 ** 18).buildTransaction(self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) deposit_time = self.get_block_number(client, tx.hash_hex()) assert_equal(client.get_staking_balance(addr), 10 ** 18) assert_equal(client.get_balance(addr), 4 * 10 ** 18 - charged_of_huge_gas(gas)) # withdraw 5 * 10**17 balance = client.get_balance(addr) capital = 5 * 10 ** 17 tx_data = decode_hex(staking_contract.functions.withdraw(capital).buildTransaction(self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) withdraw_time = self.get_block_number(client, tx.hash_hex()) interest = capital * accumulate_interest_rate[withdraw_time] // accumulate_interest_rate[deposit_time] - capital assert_equal(client.get_staking_balance(addr), 10 ** 18 - capital) assert_equal(client.get_balance(addr), balance + capital + interest - charged_of_huge_gas(gas)) # lock 4 * 10 ** 17 until block number 100000 balance = client.get_balance(addr) tx_data = decode_hex(staking_contract.functions.vote_lock(4 * 10 ** 17, 100000).buildTransaction(self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(client.get_balance(addr), balance - charged_of_huge_gas(gas)) assert_equal(client.get_staking_balance(addr), 5 * 10 ** 17) # withdraw 5 * 10**17 and it should fail balance = client.get_balance(addr) capital = 5 * 10 ** 17 tx_data = decode_hex(staking_contract.functions.withdraw(capital).buildTransaction(self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(client.get_balance(addr), balance - gas) assert_equal(client.get_staking_balance(addr), 5 * 10 ** 17) # withdraw 10**17 + 1 and it should fail balance = client.get_balance(addr) tx_data = decode_hex(staking_contract.functions.withdraw(10 ** 17 + 1).buildTransaction(self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) assert_equal(client.get_balance(addr), balance - gas) assert_equal(client.get_staking_balance(addr), 5 * 10 ** 17) # withdraw 10**17 and it should succeed balance = client.get_balance(addr) capital = 10 ** 17 tx_data = decode_hex(staking_contract.functions.withdraw(capital).buildTransaction(self.tx_conf)["data"]) tx = client.new_tx(value=0, sender=addr, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key) client.send_tx(tx) self.wait_for_tx([tx]) withdraw_time = self.get_block_number(client, tx.hash_hex()) interest = capital * accumulate_interest_rate[withdraw_time] // accumulate_interest_rate[deposit_time] - capital assert_equal(client.get_balance(addr), balance + capital + interest - charged_of_huge_gas(gas)) assert_equal(client.get_staking_balance(addr), 5 * 10 ** 17 - capital) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) self.log.info("Pass")
def run_test(self): start_p2p_connection(self.nodes) block_gen_thread = BlockGenThread(self.nodes, self.log, interval_base=0.2) block_gen_thread.start() genesis_key = default_config["GENESIS_PRI_KEY"] tx_n = 100 gas_price = 1 shard_size = int(self.num_nodes / self.n_shard) shard_balance = [] for s in range(self.n_shard): ''' Send random transactions to this shard s ''' shard_nodes = self.nodes[s * shard_size: (s + 1) * shard_size] receiver_sk, _ = ec_random_keys() value = default_config["TOTAL_COIN"] - 21000 balance_map = {receiver_sk: value} nonce_map = {receiver_sk: 0} tx = create_transaction(pri_key=genesis_key, receiver=privtoaddr(receiver_sk), value=value, nonce=0, gas_price=gas_price) shard_nodes[0].p2p.send_protocol_msg(Transactions(transactions=[tx])) for i in range(tx_n): sender_key = random.choice(list(balance_map)) nonce = nonce_map[sender_key] if random.random() < 0.2 and balance_map[sender_key] > 21000 * 4 * tx_n: value = int(balance_map[sender_key] * 0.5) receiver_sk, _ = ec_random_keys() nonce_map[receiver_sk] = 0 balance_map[receiver_sk] = value else: value = 1 receiver_sk = random.choice(list(balance_map)) balance_map[receiver_sk] += value tx = create_transaction(pri_key=sender_key, receiver=privtoaddr(receiver_sk), value=value, nonce=nonce, gas_price=gas_price) r = random.randint(0, shard_size - 1) shard_nodes[r].p2p.send_protocol_msg(Transactions(transactions=[tx])) nonce_map[sender_key] = nonce + 1 balance_map[sender_key] -= value + gas_price * 21000 self.log.info("New tx %s: %s send value %d to %s, sender balance:%d, receiver balance:%d", encode_hex(tx.hash), eth_utils.encode_hex(privtoaddr(sender_key))[-4:], value, eth_utils.encode_hex(privtoaddr(receiver_sk))[-4:], balance_map[sender_key], balance_map[receiver_sk]) self.log.debug("Send Transaction %s to node %d", encode_hex(tx.hash), r) time.sleep(random.random() / 10) for k in balance_map: self.log.info("Check account sk:%s addr:%s", bytes_to_int(k), eth_utils.encode_hex(privtoaddr(k))) wait_until(lambda: self.check_account(k, balance_map, shard_nodes[0])) shard_balance.append(balance_map) def epochCheck(node): r = node.cfx_epochNumber() return int(r, 0) > 110 wait_until(lambda: epochCheck(self.nodes[0])) wait_until(lambda: epochCheck(self.nodes[int(self.num_nodes / self.n_shard)])) for s in range(self.n_shard): connect_nodes(self.nodes, s * shard_size - 1, s * shard_size) block_gen_thread.stop() block_gen_thread.join() sync_blocks(self.nodes) ''' Check if the balance state of every node matches ''' success_shard = -1 # use the state of node 0 to find the winning shard for s in range(self.n_shard): balance_map = shard_balance[s] unmatch = False for k in balance_map: if not self.check_account(k, balance_map, self.nodes[0]): unmatch = True self.log.info("Final balance does not match shard %s, check next", s) break if unmatch: continue success_shard = s break assert success_shard != -1, "The final state of node 0 matches no shard state" self.log.info("Shard %s succeeds", success_shard) for i in range(1, self.num_nodes): balance_map = shard_balance[success_shard] for k in balance_map: if not self.check_account(k, balance_map, self.nodes[i]): raise AssertionError("Final balance of node {} does not match node 0, sender={}".format(i, k)) self.log.info("Pass")