Exemple #1
0
    def get_transactions_by_address(self, address, start=b"", limit=10):
        if not self.env.cluster_config.ENABLE_TRANSACTION_HISTORY:
            return [], b""

        serialized_address = address.serialize()
        end = b"addr_" + serialized_address
        original_start = (int.from_bytes(end, byteorder="big") + 1).to_bytes(
            len(end), byteorder="big")
        next = end
        # reset start to the latest if start is not valid
        if not start or start > original_start:
            start = original_start

        tx_list = []
        for k, v in self.db.reversed_range_iter(start, end):
            limit -= 1
            if limit < 0:
                break
            height = int.from_bytes(k[5 + 24:5 + 24 + 4], "big")
            cross_shard = int(k[5 + 24 + 4]) == 0
            index = int.from_bytes(k[5 + 24 + 4 + 1:], "big")
            if cross_shard:  # cross shard receive
                m_block = self.get_minor_block_by_height(height)
                x_shard_receive_tx_list = self.__get_confirmed_cross_shard_transaction_deposit_list(
                    m_block.header.get_hash())
                tx = x_shard_receive_tx_list[
                    index]  # tx is CrossShardTransactionDeposit
                tx_list.append(
                    TransactionDetail(
                        tx.tx_hash,
                        tx.from_address,
                        tx.to_address,
                        tx.value,
                        height,
                        m_block.header.create_time,
                        True,
                        tx.gas_token_id,
                        tx.transfer_token_id,
                    ))
            else:
                m_block = self.get_minor_block_by_height(height)
                receipt = m_block.get_receipt(self.db, index)
                tx = m_block.tx_list[index]  # tx is Transaction
                evm_tx = tx.tx.to_evm_tx()
                tx_list.append(
                    TransactionDetail(
                        tx.get_hash(),
                        Address(evm_tx.sender, evm_tx.from_full_shard_key),
                        Address(evm_tx.to, evm_tx.to_full_shard_key)
                        if evm_tx.to else None,
                        evm_tx.value,
                        height,
                        m_block.header.create_time,
                        receipt.success == b"\x01",
                        evm_tx.gas_token_id,
                        evm_tx.transfer_token_id,
                    ))
            next = (int.from_bytes(k, byteorder="big") - 1).to_bytes(
                len(k), byteorder="big")

        return tx_list, next
    def __get_transaction_details(
        self,
        start_key: bytes,
        end_key: bytes,
        limit: int,
        decoding_byte_offset: int,
        skip_coinbase_rewards: bool = False,
        transfer_token_id: Optional[int] = None,
    ) -> (List[TransactionDetail], bytes):
        next_key, tx_list = end_key, []
        tx_hashes = set()

        def skip_xshard(xshard_tx: CrossShardTransactionDeposit):
            if xshard_tx.is_from_root_chain:
                return (
                    skip_coinbase_rewards or xshard_tx.value == 0
                )  # value 0 if dummy deposit
            return (
                transfer_token_id is not None
                and xshard_tx.transfer_token_id != transfer_token_id
            )

        def skip_tx(normal_tx: EvmTransaction):
            return (
                transfer_token_id is not None
                and normal_tx.transfer_token_id != transfer_token_id
            )

        for k, v in self.db.reversed_range_iter(start_key, end_key):
            if limit <= 0:
                break
            height = int.from_bytes(
                k[decoding_byte_offset : decoding_byte_offset + 4], "big"
            )
            cross_shard = int(k[decoding_byte_offset + 4]) == 0
            index = int.from_bytes(k[decoding_byte_offset + 4 + 1 :], "big")
            m_block = self.get_minor_block_by_height(height)
            if cross_shard:  # cross shard receive
                x_shard_receive_tx_list = self.__get_confirmed_cross_shard_transaction_deposit_list(
                    m_block.header.get_hash()
                )
                tx = x_shard_receive_tx_list[
                    index
                ]  # type: CrossShardTransactionDeposit
                if tx.tx_hash not in tx_hashes and not skip_xshard(tx):
                    limit -= 1
                    tx_hashes.add(tx.tx_hash)
                    tx_list.append(
                        TransactionDetail(
                            tx.tx_hash,
                            tx.from_address,
                            tx.to_address,
                            tx.value,
                            height,
                            m_block.header.create_time,
                            True,
                            tx.gas_token_id,
                            tx.transfer_token_id,
                            is_from_root_chain=tx.is_from_root_chain,
                        )
                    )
            else:
                # no need to provide cross shard deposit list for in-shard tx receipt
                receipt = m_block.get_receipt(
                    self.db, index, x_shard_receive_tx_list=None
                )
                tx = m_block.tx_list[index]  # type: TypedTransaction
                evm_tx = tx.tx.to_evm_tx()
                tx_hash = tx.get_hash()
                if tx_hash not in tx_hashes and not skip_tx(evm_tx):
                    limit -= 1
                    tx_hashes.add(tx_hash)
                    tx_list.append(
                        TransactionDetail(
                            tx_hash,
                            Address(evm_tx.sender, evm_tx.from_full_shard_key),
                            Address(evm_tx.to, evm_tx.to_full_shard_key)
                            if evm_tx.to
                            else None,
                            evm_tx.value,
                            height,
                            m_block.header.create_time,
                            receipt.success == b"\x01",
                            evm_tx.gas_token_id,
                            evm_tx.transfer_token_id,
                            is_from_root_chain=False,
                        )
                    )
            next_key = (int.from_bytes(k, byteorder="big") - 1).to_bytes(
                len(k), byteorder="big"
            )

        return tx_list, next_key
Exemple #3
0
    def test_two_tx_in_one_block(self):
        id1 = Identity.create_random_identity()
        id2 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_from_identity(id2, full_shard_id=0)
        acc3 = Address.create_random_account(full_shard_id=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_quarkash=2000000 + opcodes.GTXCOST)
        state = create_default_shard_state(env=env)

        state.add_tx(
            create_transfer_transaction(
                shard_state=state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc2,
                value=1000000,
            ))

        b0 = state.create_block_to_mine(address=acc3)
        state.finalize_and_add_block(b0)
        self.assertEqual(state.get_balance(id1.recipient, 0), 1000000)
        self.assertEqual(state.get_balance(acc2.recipient, 0), 1000000)
        self.assertEqual(state.get_balance(acc3.recipient, 0),
                         opcodes.GTXCOST // 2)

        # Check Account has full_shard_id
        self.assertEqual(state.evm_state.get_full_shard_id(acc2.recipient),
                         acc2.full_shard_id)

        state.add_tx(
            create_transfer_transaction(
                shard_state=state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=Address(acc2.recipient, acc2.full_shard_id +
                                   2),  # set a different full shard id
                value=12345,
                gas=50000,
            ))
        state.add_tx(
            create_transfer_transaction(
                shard_state=state,
                key=id2.get_key(),
                from_address=acc2,
                to_address=acc1,
                value=54321,
                gas=40000,
            ))
        b1 = state.create_block_to_mine(address=acc3, gas_limit=40000)
        self.assertEqual(len(b1.tx_list), 1)
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 2)

        # Should succeed
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(state.get_balance(id1.recipient, 0),
                         1000000 - opcodes.GTXCOST - 12345 + 54321)
        self.assertEqual(state.get_balance(acc2.recipient, 0),
                         1000000 - opcodes.GTXCOST + 12345 - 54321)
        self.assertEqual(state.get_balance(acc3.recipient, 0),
                         opcodes.GTXCOST * 1.5)

        # Check receipts
        self.assertEqual(len(state.evm_state.receipts), 2)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, 21000)
        self.assertEqual(state.evm_state.receipts[1].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[1].gas_used, 42000)

        block, i = state.get_transaction_by_hash(b1.tx_list[0].get_hash())
        self.assertEqual(block, b1)
        self.assertEqual(i, 0)

        block, i = state.get_transaction_by_hash(b1.tx_list[1].get_hash())
        self.assertEqual(block, b1)
        self.assertEqual(i, 1)

        # Check acc2 full_shard_id doesn't change
        self.assertEqual(state.evm_state.get_full_shard_id(acc2.recipient),
                         acc2.full_shard_id)
    def test_contract_suicide(self):
        """
        Kill Call Data: 0x41c0e1b5
        """
        QETH = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        id2 = Identity.create_random_identity()
        acc2 = Address.create_from_identity(id2, full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 200 * 10**18,
                "QETH": 99999
            },
        )
        state = create_default_shard_state(env=env)

        # 1. create contract
        BYTECODE = "6080604052348015600f57600080fd5b5060948061001e6000396000f3fe6080604052600436106039576000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514603b575b005b348015604657600080fd5b50604d604f565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea165627a7a7230582034cc4e996685dcadcc12db798751d2913034a3e963356819f2293c3baea4a18c0029"
        """
        pragma solidity ^0.5.1;
        contract Sample {
          function () payable external{}
          function kill() external {selfdestruct(msg.sender);}
        }
        """
        CREATION_GAS = 92417
        tx = contract_creation_tx(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_full_shard_key=acc1.full_shard_key,
            bytecode=BYTECODE,
            gas_token_id=self.genesis_token,
            transfer_token_id=self.genesis_token,
        )
        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, CREATION_GAS)
        contract_address = mk_contract_address(acc1.recipient,
                                               acc1.full_shard_key, 0)
        self.assertEqual(contract_address,
                         state.evm_state.receipts[0].contract_address)
        self.assertEqual(acc1.full_shard_key,
                         state.evm_state.receipts[0].contract_full_shard_key)
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            200 * 10**18 - CREATION_GAS,
        )
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.getAfterTaxReward(CREATION_GAS + self.shard_coinbase),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 0)
        self.assertEqual(tx_list[0].gas_token_id, self.genesis_token)
        self.assertEqual(tx_list[0].transfer_token_id, self.genesis_token)

        # 2. send some default token
        tx_send = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=Address(contract_address, acc1.full_shard_key),
            value=10 * 10**18,
            gas=opcodes.GTXCOST + 40,
            gas_price=1,
            nonce=None,
            data=b"",
            gas_token_id=self.genesis_token,
            transfer_token_id=self.genesis_token,
        )
        self.assertTrue(state.add_tx(tx_send))
        b2 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b2.tx_list), 1)
        state.finalize_and_add_block(b2)
        self.assertEqual(state.header_tip, b2.header)
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used,
                         opcodes.GTXCOST + 40)
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            200 * 10**18 - CREATION_GAS - (opcodes.GTXCOST + 40) - 10 * 10**18,
        )
        self.assertEqual(
            state.get_token_balance(contract_address, self.genesis_token),
            10 * 10**18)

        # 3. suicide
        SUICIDE_GAS = 13199
        tx_kill = create_transfer_transaction(
            shard_state=state,
            key=id2.get_key(),
            from_address=acc2,
            to_address=Address(contract_address, acc1.full_shard_key),
            value=0,
            gas=1000000,
            gas_price=0,  # !!! acc2 has no token yet...
            nonce=None,
            data=bytes.fromhex("41c0e1b5"),
            gas_token_id=self.genesis_token,
            transfer_token_id=self.genesis_token,
        )
        self.assertTrue(state.add_tx(tx_kill))
        b3 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b3.tx_list), 1)
        state.finalize_and_add_block(b3)
        self.assertEqual(state.header_tip, b3.header)
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, SUICIDE_GAS)
        self.assertEqual(
            state.get_token_balance(id2.recipient, self.genesis_token),
            10 * 10**18)
        self.assertEqual(
            state.get_token_balance(contract_address, self.genesis_token), 0)
Exemple #5
0
 async def eth_getStorageAt(self, address, key, shard=None):
     addr = Address.deserialize(address)
     if shard is not None:
         addr = Address(addr.recipient, shard)
     res = await self.master.get_storage_at(addr, key, None)
     return data_encoder(res) if res is not None else None
Exemple #6
0
 async def eth_getTransactionCount(self, address, shard=None):
     address = Address.deserialize(address)
     if shard is not None:
         address = Address(address.recipient, shard)
     account_branch_data = await self.master.get_primary_account_data(address)
     return account_branch_data.transaction_count