def generate_transactions(self, _):
     self.call_contract_function(
         self.contract,
         "transfer",
         [Web3.toChecksumAddress(priv_to_addr(self.accounts[0])), 1000],
         self.default_account_key,
         self.contract_address,
         True,
         True,
         storage_limit=512)
     self.call_contract_function(
         self.contract,
         "approve",
         [Web3.toChecksumAddress(priv_to_addr(self.accounts[1])), 500],
         self.accounts[0],
         self.contract_address,
         True,
         True,
         storage_limit=512)
     self.call_contract_function(
         self.contract,
         "transferFrom", [
             Web3.toChecksumAddress(priv_to_addr(self.accounts[0])),
             Web3.toChecksumAddress(priv_to_addr(self.default_account_key)),
             300
         ],
         self.accounts[1],
         self.contract_address,
         True,
         True,
         storage_limit=512)
Exemple #2
0
    def __init__(self):
        super().__init__()

        self.nonce_map = {}
        self.genesis_priv_key = default_config['GENESIS_PRI_KEY']
        self.genesis_addr = priv_to_addr(self.genesis_priv_key)
        self.eth_priv_key = EthTransactionTest.ETH_KEY
        self.eth_addr = priv_to_addr(self.eth_priv_key)
        self.eth_hex_addr = encode_hex_0x(self.eth_addr)
    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_empty_blocks(1)
            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_empty_blocks(1)
        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()
        client = RpcClient(self.nodes[0])
        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=priv_to_addr(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(priv_to_addr(sender_key))[-4:],
                       value, eth_utils.encode_hex(priv_to_addr(receiver_sk))[-4:])
        def check_packed():
            client.generate_block(1)
            return checktx(self.nodes[0], tx.hash_hex())
        wait_until(lambda: check_packed())
        sender_addr = eth_utils.encode_hex(priv_to_addr(sender_key))
        receiver_addr = eth_utils.encode_hex(priv_to_addr(receiver_sk))
        sender_balance = default_config["TOTAL_COIN"] - value - gas_price * 21000
        # Generate 2 * CACHE_INDEX_STRIDE to start evicting anticone cache
        self.nodes[0].generate_empty_blocks(2000)
        assert_equal(client.get_balance(sender_addr), sender_balance)
        assert_equal(client.get_balance(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: client.get_balance(sender_addr) == sender_balance)
        wait_until(lambda: client.get_balance(receiver_addr) == value)
        self.log.info("Pass 2")
Exemple #4
0
    def run_test(self):
        file_path = os.path.dirname(os.path.realpath(__file__)).split("/")
        file_path.pop(-1)
        file_path.extend(["internal_contract", "metadata", "Staking.json"])
        file_path = "/".join(file_path)
        staking_contract_dict = json.loads(open(os.path.join(file_path), "r").read())
        staking_contract = get_contract_instance(contract_dict=staking_contract_dict)
        staking_contract_addr = Web3.toChecksumAddress("843c409373ffd5c0bec1dddb7bec830856757b65")

        self.problem = "0x2bc79b7514884ab00da924607d71542cc4fed3beb8518e747726ae30ab6c7944"
        self.solution = "0xc4d2751c52311d0d7efe44e5c4195e058ad5ef4bb89b3e1761b24dc277b132c2"
        self.priv_key = default_config["GENESIS_PRI_KEY"]
        self.sender = encode_hex_0x(priv_to_addr(self.priv_key))
        self.sender_checksum = Web3.toChecksumAddress(self.sender)
        self.pub = []
        self.pri = []
        self.rpc = RpcClient(self.nodes[0])
        gas = CONTRACT_DEFAULT_GAS
        gas_price = 10

        # lock token for genesis account
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.tx_conf['to'] = staking_contract_addr
        tx_data = decode_hex(staking_contract.functions.deposit(1000000 * 10 ** 18).buildTransaction(self.tx_conf)["data"])
        tx = self.rpc.new_tx(value=0, receiver=staking_contract_addr, data=tx_data, gas=gas, gas_price=gas_price)
        self.rpc.send_tx(tx, True)

        for i in range(10):
            priv_key = random.randint(0, 2 ** 256).to_bytes(32, "big")
            pub_key = encode_hex_0x(priv_to_addr(priv_key))
            self.pub.append(pub_key)
            self.pri.append(priv_key)
            transaction = self.rpc.new_tx(sender=self.sender, receiver=pub_key, value=1000000 * 10 ** 18, priv_key=self.priv_key)
            self.rpc.send_tx(transaction, True)
            # deposit 10000 tokens
            tx_data = decode_hex(staking_contract.functions.deposit(10000 * 10 ** 18).buildTransaction(self.tx_conf)["data"])
            tx = self.rpc.new_tx(value=0, sender=pub_key, receiver=self.tx_conf["to"], gas=gas, data=tx_data, priv_key=priv_key)
            self.rpc.send_tx(tx)
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.filter = Filter(from_epoch="earliest", to_epoch="latest_state")
        self.testEventContract()
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.testBallotContract()
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.testPayContract()
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.testHTLCContract()
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.testDaiContract()
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.testMappingContract()
        self.tx_conf = {"from":self.sender, "gas":int_to_hex(gas), "gasPrice":int_to_hex(gas_price), "chainId":0}
        self.testDaiJoinContract()
        self.log.info("Pass")
Exemple #5
0
    def __init__(self):
        super().__init__()

        self.nonce_map = {}
        self.genesis_priv_key = default_config['GENESIS_PRI_KEY']
        self.genesis_addr = priv_to_addr(self.genesis_priv_key)
        self.balance_map = {self.genesis_priv_key: default_config['TOTAL_COIN']}
Exemple #6
0
 def generate_transactions(self, i):
     self.call_contract_function(
         self.vote_contract,
         "createIssue", [
             i,
             Web3.toChecksumAddress(self.token_address),
             [j for j in range(self.num_of_options)],
             [
                 Web3.toChecksumAddress(priv_to_addr(acc))
                 for acc in self.accounts
             ], "v"
         ],
         self.default_account_key,
         self.vote_address,
         True,
         True,
         storage_limit=64)
     for i in range(self.num_of_options):
         self.call_contract_function(
             self.vote_contract,
             "vote", [i, random.randint(0, self.num_of_options - 1)],
             self.default_account_key,
             self.vote_address,
             True,
             True,
             storage_limit=64)
 def call_contract_function(self, contract, name, args, sender_key, contract_addr=None, wait=False,
                            check_status=False, storage_limit=0):
     # If contract address is empty, call the constructor.
     if contract_addr:
         func = getattr(contract.functions, name)
     else:
         func = getattr(contract, name)
     attributes = {
         'nonce': self.get_nonce(priv_to_addr(sender_key)),
         ** SmartContractBenchBase.REQUEST_BASE
     }
     if contract_addr:
         attributes['receiver'] = decode_hex(contract_addr)
         attributes['to'] = contract_addr
     else:
         attributes['receiver'] = b''
     tx_data = func(*args).buildTransaction(attributes)
     tx_data['data'] = decode_hex(tx_data['data'])
     tx_data['pri_key'] = sender_key
     tx_data['gas_price'] = tx_data['gasPrice']
     tx_data['storage_limit'] = storage_limit
     tx_data.pop('gasPrice', None)
     tx_data.pop('chainId', None)
     tx_data.pop('to', None)
     transaction = create_transaction(**tx_data)
     self._send_transaction(transaction, wait, check_status)
     return transaction
 def new_address_and_transfer(self, count=1, amount=100000000000000, wait=False, check_status=False):
     results = []
     for _ in range(count):
         pri_key, pub_key = ec_random_keys()
         transaction = self.transfer(self.default_account_key, priv_to_addr(pri_key), amount, wait, check_status)
         results.append([pri_key, transaction])
     return results
Exemple #9
0
 def call_contract_function(self,
                            contract,
                            name,
                            args,
                            sender_key,
                            value=None,
                            contract_addr=None,
                            wait=False,
                            check_status=False):
     if contract_addr:
         func = getattr(contract.functions, name)
     else:
         func = getattr(contract, name)
     attrs = {
         'nonce': self.get_nonce(priv_to_addr(sender_key)),
         **Issue988Test.REQUEST_BASE
     }
     if contract_addr:
         attrs['receiver'] = decode_hex(contract_addr)
         attrs['to'] = contract_addr
     else:
         attrs['receiver'] = b''
     tx_data = func(*args).buildTransaction(attrs)
     tx_data['data'] = decode_hex(tx_data['data'])
     tx_data['pri_key'] = sender_key
     tx_data['gas_price'] = tx_data['gasPrice']
     if value:
         tx_data['value'] = value
     tx_data.pop('gasPrice', None)
     tx_data.pop('chainId', None)
     tx_data.pop('to', None)
     transaction = create_transaction(**tx_data)
     self.send_transaction(transaction, wait, check_status)
     return transaction
Exemple #10
0
 def run_test(self):
     client = RpcClient(self.nodes[0])
     genesis_address = "0x" + encode_hex(
         priv_to_addr(default_config['GENESIS_PRI_KEY']))
     genesis_balance = default_config["TOTAL_COIN"]
     client.generate_empty_blocks(ERA_EPOCH_COUNT * 10)
     print(client.epoch_number("latest_checkpoint"))
     assert client.epoch_number("latest_checkpoint") > 0
     # Just assert we can still get the balance
     assert_equal(client.get_balance(genesis_address, client.EPOCH_NUM(1)),
                  genesis_balance)
    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        # deploy contract
        bytecode_file = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), CONTRACT_PATH)
        assert (os.path.isfile(bytecode_file))
        bytecode = open(bytecode_file).read()
        _, contractAddr = self.deploy_contract(sender, priv_key, bytecode)
        self.log.info(f"contract deployed at address {contractAddr}")

        # emit events throughout a few eras
        num_events = 0

        while self.rpc[ARCHIVE_NODE].epoch_number(
        ) < NUM_ERAS * ERA_EPOCH_COUNT:
            self.call_contract(sender, priv_key, contractAddr,
                               encode_hex_0x(keccak(b"foo()")))
            num_events += 1

        self.log.info(f"num_events = {num_events}")
        self.log.info(
            f"epoch_number = {self.rpc[ARCHIVE_NODE].epoch_number()}")

        # sync blocks and wait for gc
        sync_blocks(self.nodes)
        time.sleep(1)

        latest_checkpoint = self.rpc[FULL_NODE].epoch_number(
            "latest_checkpoint")
        assert_greater_than(latest_checkpoint, 0)

        # filtering the whole epoch range should fail on full nodes
        filter = Filter(from_epoch="earliest",
                        to_epoch="latest_state",
                        topics=[CALLED_TOPIC])
        logs_archive = self.rpc[ARCHIVE_NODE].get_logs(filter)
        assert_equal(len(logs_archive), num_events)

        assert_raises_rpc_error(None, None, self.rpc[FULL_NODE].get_logs,
                                filter)

        # filtering since the latest checkpoint should yield the same result
        filter = Filter(from_epoch="latest_checkpoint",
                        to_epoch="latest_state",
                        topics=[CALLED_TOPIC])
        logs_archive = self.rpc[ARCHIVE_NODE].get_logs(filter)
        assert_greater_than(len(logs_archive), 0)

        logs_full = self.rpc[FULL_NODE].get_logs(filter)
        assert_equal(logs_archive, logs_full)

        self.log.info("Pass")
 def check_account(self, k, balance_map):
     addr = eth_utils.encode_hex(priv_to_addr(k))
     try:
         balance = self.rpc_client.get_balance(addr)
     except Exception as e:
         self.log.info("Fail to get balance, error=%s", str(e))
         return False
     if balance == balance_map[k]:
         return True
     else:
         self.log.info("Remote balance:%d, local balance:%d", balance, balance_map[k])
         time.sleep(1)
         return False
Exemple #13
0
 def check_account(self, k, balance_map, node):
     addr = eth_utils.encode_hex(priv_to_addr(k))
     try:
         balance = parse_as_int(node.cfx_getBalance(addr))
     except Exception as e:
         self.log.debug("Fail to get balance, error=%s", str(e))
         return False
     if balance == balance_map[k]:
         return True
     else:
         self.log.info("Remote balance:%d, local balance:%d", balance, balance_map[k])
         time.sleep(1)
         return False
Exemple #14
0
    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        # deploy storage test contract
        bytecode_file = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), CONTRACT_PATH)
        assert (os.path.isfile(bytecode_file))
        bytecode = open(bytecode_file).read()
        _, contractAddr = self.deploy_contract(sender, priv_key, bytecode)

        # call contract throughout a few eras
        self.call_contract(sender, priv_key, contractAddr,
                           encode_hex_0x(keccak(b"increment()")))
        self.rpc[FULLNODE0].generate_blocks(SNAPSHOT_EPOCH_COUNT)
        self.call_contract(sender, priv_key, contractAddr,
                           encode_hex_0x(keccak(b"increment()")))
        self.rpc[FULLNODE0].generate_blocks(SNAPSHOT_EPOCH_COUNT)
        self.call_contract(sender, priv_key, contractAddr,
                           encode_hex_0x(keccak(b"destroy()")))
        self.rpc[FULLNODE0].generate_blocks(SNAPSHOT_EPOCH_COUNT)

        # check storage root of non-existent contract
        root_full = self.rpc[FULLNODE0].get_storage_root(
            "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", epoch=hex(1))
        root_light = self.rpc[LIGHTNODE].get_storage_root(
            "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", epoch=hex(1))
        assert_equal(root_full, root_light)

        # make sure the storage roots are verifiable on the light node
        latest_epoch = self.rpc[FULLNODE0].epoch_number()
        self.rpc[FULLNODE0].generate_blocks(SNAPSHOT_EPOCH_COUNT)
        sync_blocks(self.nodes)

        # check storage roots
        first_available_epoch = (latest_epoch - 1) // SNAPSHOT_EPOCH_COUNT \
                                * SNAPSHOT_EPOCH_COUNT - SNAPSHOT_EPOCH_COUNT * 2 + 1
        # After latest_epoch is obtained the test generated SNAPSHOT_EPOCH_COUNT more blocks.
        first_available_epoch += SNAPSHOT_EPOCH_COUNT
        # The proof is only available since the second available snapshot.
        first_available_epoch += SNAPSHOT_EPOCH_COUNT
        for epoch in range(first_available_epoch, latest_epoch):
            root_full = self.rpc[FULLNODE0].get_storage_root(contractAddr,
                                                             epoch=hex(epoch))
            root_light = self.rpc[LIGHTNODE].get_storage_root(contractAddr,
                                                              epoch=hex(epoch))
            assert_equal(root_full, root_light)
            self.log.info(f"Pass (epoch {epoch})")

        self.log.info("Pass")
Exemple #15
0
 def check_account(self, k, balance_map):
     addr = eth_utils.encode_hex(priv_to_addr(k))
     try:
         balance = parse_as_int(self.nodes[0].cfx_getBalance(addr))
         staking_balance = parse_as_int(self.nodes[0].cfx_getStakingBalance(addr))
         collateral_for_storage = parse_as_int(self.nodes[0].cfx_getCollateralForStorage(addr))
     except Exception as e:
         self.log.info("Fail to get balance, error=%s", str(e))
         return False
     if balance + staking_balance + collateral_for_storage == balance_map[k]:
         return True
     else:
         self.log.info("Remote balance:%d, local balance:%d", balance + staking_balance + collateral_for_storage, balance_map[k])
         time.sleep(1)
         return False
Exemple #16
0
 def check_account(self, k, balance_map):
     addr = eth_utils.encode_hex(priv_to_addr(k))
     client = RpcClient(self.nodes[0])
     try:
         balance = client.get_balance(addr)
         staking_balance = client.get_staking_balance(addr)
         collateral_for_storage = client.get_collateral_for_storage(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 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 __init__(self):
     super().__init__()
     self.nonce_map = {}
     self.default_account_key = default_config["GENESIS_PRI_KEY"]
     self.default_account_address = priv_to_addr(self.default_account_key)
 def transfer(self, sender_key, receiver, amount, wait=False, check_status=False):
     nonce = self.get_nonce(priv_to_addr(sender_key))
     transaction = create_transaction(nonce, 1, 21000, amount, receiver, pri_key=sender_key)
     self._send_transaction(transaction, wait, check_status)
     return transaction
Exemple #20
0
    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}
        block_gen_thread = BlockGenThread(self.nodes, self.log, interval_base=0.2)
        block_gen_thread.start()

        '''Check if transaction from uncommitted new address can be accepted'''
        tx_n = 5
        new_keys = set()
        gas_price = 1
        for i in range(tx_n):
            sender_key = genesis_key
            receiver_sk, _ = ec_random_keys()
            new_keys.add(receiver_sk)
            value = int((balance_map[sender_key] - ((tx_n - i) * 21000 * gas_price)) * random.random())
            balance_map[receiver_sk] = value
            nonce = nonce_map[sender_key]
            receiver_addr = priv_to_addr(receiver_sk)
            tx = create_transaction(pri_key=sender_key, receiver=receiver_addr, value=value, nonce=nonce,
                                    gas_price=gas_price)
            r = random.randint(0, self.num_nodes - 1)
            r = 0
            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(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)
        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))
        self.log.info("Pass 1")

        '''Test Random Transactions'''
        wait_for_account_stable()
        for key in new_keys:
            nonce_map[key] = wait_for_initial_nonce_for_privkey(self.nodes[0], key)
        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
            storage_limit = 0
            if 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 = CONTRACT_DEFAULT_GAS
                is_payment = False
                storage_limit = 200000
            else:
                value = 1
                receiver_sk = random.choice(list(balance_map))
                receiver = priv_to_addr(receiver_sk)
                balance_map[receiver_sk] += value
                is_payment = True
            # 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, storage_limit=storage_limit)
            r = random.randint(0, self.num_nodes - 1)
            r = 0
            self.nodes[r].p2p.send_protocol_msg(Transactions(transactions=[tx]))
            all_txs.append(tx)
            nonce_map[sender_key] = nonce + 1
            if is_payment:
                balance_map[sender_key] -= value + gas_price * gas
            else:
                balance_map[sender_key] -= value + gas_price * charged_of_huge_gas(gas)
            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(priv_to_addr(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")
Exemple #21
0
    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):
        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):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

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

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

        # deploy contract
        bytecode_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), CONTRACT_PATH)
        assert(os.path.isfile(bytecode_file))
        bytecode = open(bytecode_file).read()
        _, contractAddr = self.deploy_contract(sender, priv_key, bytecode)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        txs = txs1
        txs.extend(txs2)

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

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

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

        log_index = 0
        transaction_index = 0
        transaction_log_index = 0

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

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

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

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

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

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

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

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

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

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

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

        # test paging use case
        BATCH_SIZE = 7

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

        collected_logs = []
        offset = 0

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

        assert_equal(collected_logs, all_logs)

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

        self.log.info("Pass")
    def 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)
Exemple #25
0
    def run_test(self):
        priv_key = default_config["GENESIS_PRI_KEY"]
        sender = eth_utils.encode_hex(priv_to_addr(priv_key))

        # check storage root of non-existent contract
        root = self.rpc[FULLNODE0].get_storage_root(
            "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")

        assert_equal(root["delta"], None)
        assert_equal(root["delta"], None)
        assert_equal(root["delta"], None)

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

        # get storage root; expect: (D0, I0, S0) = (?, NULL, NULL)
        root0 = self.rpc[FULLNODE0].get_storage_root(contractAddr)

        assert_is_hash_string(root0["delta"])
        assert_equal(root0["intermediate"], None)
        assert_equal(root0["snapshot"], None)

        # update storage; expect: (D1, I1, S1) == (?, I0, S0)
        # NOTE: call_contract will generate some blocks but it should be < SNAPSHOT_EPOCH_COUNT
        self.call_contract(sender, priv_key, contractAddr,
                           encode_hex_0x(keccak(b"increment()")))
        root1 = self.rpc[FULLNODE0].get_storage_root(contractAddr)

        assert_is_hash_string(root1["delta"])
        assert_ne(root1["delta"], root0["delta"])
        assert_equal(root1["intermediate"], None)
        assert_equal(root1["snapshot"], None)

        # go to next era
        self.rpc[FULLNODE0].generate_blocks(SNAPSHOT_EPOCH_COUNT)

        # get storage root; expect: (D2, I2, S2) == (NULL, D1, NULL)
        # (the previous delta trie became the current intermediate trie)
        root2 = self.rpc[FULLNODE0].get_storage_root(contractAddr)

        assert_equal(root2["delta"], None)
        assert_equal(root2["intermediate"], root1["delta"])
        assert_equal(root2["snapshot"], None)

        # update storage; expect: (D3, I3, S3) == (?, I2, S2)
        # NOTE: call_contract will generate some blocks but it should be < SNAPSHOT_EPOCH_COUNT
        self.call_contract(sender, priv_key, contractAddr,
                           encode_hex_0x(keccak(b"increment()")))
        root3 = self.rpc[FULLNODE0].get_storage_root(contractAddr)

        assert_is_hash_string(root3["delta"])
        assert_ne(root3["delta"], root2["delta"])
        assert_equal(root3["intermediate"], root2["intermediate"])
        assert_equal(root3["snapshot"], root2["snapshot"])

        # go to next era
        self.rpc[FULLNODE0].generate_blocks(SNAPSHOT_EPOCH_COUNT)

        # get storage root; expect: (D4, I4, S4) == (NULL, D3, ?)
        # (the previous delta trie became the current intermediate trie)
        # (note that storage root in the snapshot will not match due to differences in padding)
        root4 = self.rpc[FULLNODE0].get_storage_root(contractAddr)

        assert_equal(root4["delta"], None)
        assert_equal(root4["intermediate"], root3["delta"])
        assert_is_hash_string(root4["snapshot"])

        # check if other node's storage root matches
        sync_blocks(self.nodes[:])
        root = self.rpc[FULLNODE1].get_storage_root(contractAddr)
        assert (root == root4)

        # destroy account
        # NOTE: call_contract will generate some blocks but it should be < SNAPSHOT_EPOCH_COUNTs
        self.call_contract(sender, priv_key, contractAddr,
                           encode_hex_0x(keccak(b"destroy()")))
        root5 = self.rpc[FULLNODE0].get_storage_root(contractAddr)

        assert_equal(root5["delta"], "TOMBSTONE")
        assert_equal(root5["intermediate"], root4["intermediate"])
        assert_equal(root5["snapshot"], root4["snapshot"])

        self.log.info("Pass")
Exemple #26
0
    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")
Exemple #27
0
    for sender in all_senders:
        try:
            print("Check {} with addr {}".format(sender.client.node.url, sender.addr))
            sender.wait_for_balance()
            senders.append(sender)
        except Exception as e:
            print(sender.client.node.url, "is not available for Exception", e)
            break

    # start threads to send txs to different nodes
    print("begin to send txs ...")
    workers = []
    for s in senders:
        t = TpsWorker(s, num_receivers)
        workers.append(t)
        t.start()
    for w in workers:
        w.join()

# main
if len(sys.argv) == 1:
    print("faucet private key not specified.")
    sys.exit(1)

faucet_priv_key = sys.argv[1]
faucet_addr = eth_utils.encode_hex(priv_to_addr(faucet_priv_key))
bootnodes = load_boot_nodes()
num_threads = 1 if len(sys.argv) < 3 else int(sys.argv[2])
num_receivers = 20 if len(sys.argv) < 4 else int(sys.argv[3])
work(faucet_addr, faucet_priv_key, bootnodes, num_threads, num_receivers)
    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):
        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")
Exemple #30
0
    def run_test(self):
        genesis_key = default_config["GENESIS_PRI_KEY"]
        receiver_sk, _ = ec_random_keys()
        receiver_addr = priv_to_addr(receiver_sk)
        client = RpcClient(self.nodes[0])

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

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

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