예제 #1
0
async def do_main(args: argparse.Namespace) -> None:
    # Establish database connections
    engine = _get_engine(args)
    Session.configure(bind=engine)  # type: ignore
    session = Session()

    # Ensure database schema is present
    if args.database_url == MEMORY_DB:
        Base.metadata.create_all(engine)

    start_block = args.start_block
    end_block = args.end_block

    from web3.auto.ipc import w3

    if args.disable_jsonrpc:
        ipc_path = None
    elif args.ipc_path:
        ipc_path = args.ipc_path
    else:
        ipc_path = get_xdg_cthaeh_root() / "jsonrpc.ipc"

    app = Application(
        w3,
        session,
        start_block=start_block,
        end_block=end_block,
        concurrency=args.concurrency,
        ipc_path=ipc_path,
    )

    logger.info("Started main process (pid=%d)", os.getpid())
    async with background_trio_service(app) as manager:
        await manager.wait_finished()
예제 #2
0
def session(_Session, _schema):
    session = Session()
    transaction = session.begin_nested()

    try:
        yield session
    finally:
        transaction.rollback()
        session.close()
예제 #3
0
class LogTopic(Base):
    query = Session.query_property()

    __tablename__ = "logtopic"
    __table_args__ = (
        UniqueConstraint("idx",
                         "log_receipt_hash",
                         "log_idx",
                         name="ix_idx_log_receipt_hash_log_idx"),
        Index(
            "ix_idx_topic_topic_log_receipt_hash_log_idx",
            "idx",
            "topic_topic",
            "log_receipt_hash",
            "log_idx",
        ),
        ForeignKeyConstraint(("log_idx", "log_receipt_hash"),
                             ("log.idx", "log.receipt_hash")),
    )
    __mapper_args__ = {"confirm_deleted_rows": False}

    id = Column(Integer, primary_key=True)

    idx = Column(Integer, nullable=False)

    topic_topic = Column(LargeBinary(32),
                         ForeignKey("topic.topic"),
                         index=True,
                         nullable=False)
    log_idx = Column(Integer, nullable=False)
    log_receipt_hash = Column(LargeBinary(32), nullable=False)

    topic = relationship("Topic")
    log = relationship("Log", foreign_keys=[log_idx, log_receipt_hash])
예제 #4
0
class BlockUncle(Base):
    query = Session.query_property()

    __tablename__ = "blockuncle"
    __table_args__ = (
        Index(
            "ix_blockuncle_idx_block_header_hash",
            "idx",
            "block_header_hash",
            unique=True,
        ),
        Index(
            "ix_block_header_hash_uncle_hash",
            "block_header_hash",
            "uncle_hash",
            unique=True,
        ),
    )

    idx = Column(Integer, nullable=False)

    block_header_hash = Column(LargeBinary(32),
                               ForeignKey("block.header_hash"),
                               primary_key=True)
    uncle_hash = Column(LargeBinary(32),
                        ForeignKey("header.hash"),
                        primary_key=True)

    block = relationship("Block")
    uncle = relationship("Header")
예제 #5
0
class BlockTransaction(Base):
    query = Session.query_property()

    __tablename__ = "blocktransaction"
    __table_args__ = (
        Index(
            "ix_blocktransaction_idx_block_header_hash",
            "idx",
            "block_header_hash",
            unique=True,
        ),
        Index(
            "ix_block_header_hash_transaction_hash",
            "block_header_hash",
            "transaction_hash",
            unique=True,
        ),
    )
    idx = Column(Integer, nullable=False)

    block_header_hash = Column(LargeBinary(32),
                               ForeignKey("block.header_hash"),
                               primary_key=True)
    transaction_hash = Column(LargeBinary(32),
                              ForeignKey("transaction.hash"),
                              primary_key=True)

    block = relationship("Block")
    transaction = relationship("Transaction")
예제 #6
0
class Receipt(Base):
    query = Session.query_property()

    __tablename__ = "receipt"

    transaction_hash = Column(LargeBinary(32),
                              ForeignKey("transaction.hash"),
                              primary_key=True)
    transaction = relationship("Transaction", back_populates="receipt")

    state_root = Column(LargeBinary(32), nullable=False)
    gas_used = Column(BigInteger, nullable=False)
    _bloom = Column(LargeBinary(1024), nullable=False)
    logs = relationship("Log", back_populates="receipt", order_by="Log.idx")

    @property
    def bloom(self) -> int:
        return big_endian_to_int(self._bloom)

    @bloom.setter
    def bloom(self, value: int) -> None:
        self._bloom = int_to_big_endian(value)

    @classmethod
    def from_ir(cls, receipt_ir: ReceiptIR,
                transaction_hash: Hash32) -> "Receipt":
        return cls(
            transaction_hash=transaction_hash,
            state_root=receipt_ir.state_root,
            gas_used=receipt_ir.gas_used,
            _bloom=receipt_ir.bloom,
        )
예제 #7
0
class Log(Base):
    query = Session.query_property()

    __tablename__ = "log"
    __table_args__ = (UniqueConstraint("idx",
                                       "receipt_hash",
                                       name="ix_idx_receipt_hash"), )

    id = Column(Integer, primary_key=True)
    idx = Column(Integer, nullable=False)

    receipt_hash = Column(
        LargeBinary(32),
        ForeignKey("receipt.transaction_hash"),
        index=True,
        nullable=False,
    )
    receipt = relationship("Receipt", back_populates="logs")

    address = Column(LargeBinary(20), index=True, nullable=False)
    topics = relationship("Topic", secondary="logtopic", order_by=LogTopic.idx)
    data = Column(LargeBinary, nullable=False)

    def __repr__(self) -> str:
        return (f"Log("
                f"idx={self.idx!r}, "
                f"receipt_hash={self.receipt_hash!r}, "
                f"address={self.address!r}, "
                f"data={self.data!r}, "
                f"topics={self.topics!r}"
                f")")

    def __str__(self) -> str:
        # TODO: use eth_utils.humanize_bytes once it is released
        if len(self.data) > 4:
            pretty_data = humanize_hash(Hash32(self.data))
        else:
            pretty_data = self.data.hex()

        if len(self.topics) == 0:  # type: ignore
            pretty_topics = "(anonymous)"
        else:
            pretty_topics = "|".join((
                humanize_hash(Hash32(topic.topic))
                for topic in self.topics  # type: ignore
            ))

        return f"Log[#{self.idx} A={humanize_hash(self.address)} D={pretty_data}/T={pretty_topics}]"  # type: ignore  # noqa: E501

    @classmethod
    def from_ir(cls, log_ir: LogIR, idx: int, receipt_hash: Hash32) -> "Log":
        return cls(idx=idx,
                   receipt_hash=receipt_hash,
                   address=log_ir.address,
                   data=log_ir.data)
예제 #8
0
class Transaction(Base):
    query = Session.query_property()

    __tablename__ = "transaction"

    hash = Column(LargeBinary(32), primary_key=True)

    block_header_hash = Column(LargeBinary(32),
                               ForeignKey("block.header_hash"),
                               nullable=True,
                               index=True)
    block = relationship("Block")

    blocks = relationship("Block",
                          secondary="blocktransaction",
                          order_by=BlockTransaction.idx)
    receipt = relationship("Receipt",
                           uselist=False,
                           back_populates="transaction",
                           cascade="all")

    nonce = Column(BigInteger, nullable=False)
    gas_price = Column(BigInteger, nullable=False)
    gas = Column(BigInteger, nullable=False)
    to = Column(LargeBinary(20), nullable=True)
    value = Column(LargeBinary(32), nullable=False)
    data = Column(LargeBinary, nullable=False)
    v = Column(LargeBinary(32), nullable=False)
    r = Column(LargeBinary(32), nullable=False)
    s = Column(LargeBinary(32), nullable=False)

    sender = Column(LargeBinary(20), nullable=False)

    @classmethod
    def from_ir(cls, transaction_ir: TransactionIR,
                block_header_hash: Optional[Hash32]) -> "Transaction":
        return cls(
            hash=transaction_ir.hash,
            block_header_hash=block_header_hash,
            nonce=transaction_ir.nonce,
            gas_price=transaction_ir.gas_price,
            gas=transaction_ir.gas,
            to=transaction_ir.to,
            value=transaction_ir.value,
            data=transaction_ir.data,
            v=transaction_ir.v,
            r=transaction_ir.r,
            s=transaction_ir.s,
            sender=transaction_ir.sender,
        )
예제 #9
0
class Topic(Base):
    query = Session.query_property()

    __tablename__ = "topic"

    topic = Column(LargeBinary(32), primary_key=True)

    logs = relationship("Log", secondary="logtopic", order_by=LogTopic.idx)

    def __repr__(self) -> str:
        return f"Topic(topic={self.topic!r})"

    def __str__(self) -> str:
        return f"Topic[{humanize_hash(self.topic)}]"  # type: ignore
예제 #10
0
class Block(Base):
    query = Session.query_property()

    __tablename__ = "block"

    header_hash = Column(LargeBinary(32),
                         ForeignKey("header.hash"),
                         primary_key=True)
    header = relationship("Header", back_populates="block")

    uncles = relationship("Header",
                          secondary="blockuncle",
                          order_by=BlockUncle.idx)
    transactions = relationship("Transaction",
                                secondary="blocktransaction",
                                order_by=BlockTransaction.idx)
예제 #11
0
class LogTopic(Base):
    query = Session.query_property()

    __tablename__ = "logtopic"
    __table_args__ = (
        UniqueConstraint("idx", "log_id", name="ix_idx_log_id"),
        Index("ix_idx_topic_topic_log_id", "idx", "topic_topic", "log_id"),
    )
    id = Column(Integer, primary_key=True)

    idx = Column(Integer, nullable=False)

    topic_topic = Column(LargeBinary(32),
                         ForeignKey("topic.topic"),
                         index=True,
                         nullable=False)
    log_id = Column(Integer, ForeignKey("log.id"), index=True, nullable=False)

    topic = relationship("Topic")
    log = relationship("Log")
예제 #12
0
class Header(Base):
    query = Session.query_property()

    __tablename__ = "header"
    __table_args__ = (
        CheckConstraint(
            "_parent_hash is null or _detatched_parent_hash is null",
            name="_no_double_parent_hash",
        ),
        Index("ix_hash_is_canonical", "hash", "is_canonical"),
    )

    hash = Column(LargeBinary(32), primary_key=True)

    block = relationship("Block", uselist=False, back_populates="header")
    uncle_blocks = relationship("Block",
                                secondary="blockuncle",
                                order_by=BlockUncle.idx)

    is_canonical = Column(Boolean, nullable=False, index=True)

    _detatched_parent_hash = Column(LargeBinary(32), nullable=True, index=True)
    _parent_hash = Column(LargeBinary(32),
                          ForeignKey("header.hash"),
                          nullable=True,
                          index=True)
    uncles_hash = Column(LargeBinary(32), nullable=False)
    coinbase = Column(LargeBinary(20), nullable=False)
    state_root = Column(LargeBinary(32), nullable=False)
    transaction_root = Column(LargeBinary(32), nullable=False)
    receipt_root = Column(LargeBinary(32), nullable=False)
    _bloom = Column(LargeBinary(1024), nullable=False)
    difficulty = Column(LargeBinary(32), nullable=False)
    block_number = Column(BigInteger, index=True, nullable=False)
    gas_limit = Column(BigInteger, nullable=False)
    gas_used = Column(BigInteger, nullable=False)
    timestamp = Column(Integer, nullable=False)
    extra_data = Column(LargeBinary, nullable=False)
    # mix_hash = Column(LargeBinary(32), nullable=False)
    nonce = Column(LargeBinary(8), nullable=False)

    children = relationship(
        "Header",
        backref=backref("parent", remote_side=[hash])  # type: ignore
    )

    @property
    def is_genesis(self) -> bool:
        return (self.block_number == 0 and self.is_canonical  # noqa: W503
                and self.parent_hash == GENESIS_PARENT_HASH  # noqa: W503
                )

    @property
    def is_detatched(self) -> bool:
        return self._parent_hash is None and self._detatched_parent_hash is not None

    @property
    def parent_hash(self) -> Optional[Hash32]:
        if self._parent_hash is not None and self._detatched_parent_hash is not None:
            raise TypeError("Invalid: header has two parent hashes")
        elif self._detatched_parent_hash is not None:
            return Hash32(self._detatched_parent_hash)
        elif self._parent_hash is None:
            if self.block_number == 0:
                return GENESIS_PARENT_HASH
            else:
                return None
        else:
            return Hash32(self._parent_hash)

    @parent_hash.setter
    def parent_hash(self, value: Optional[Hash32]) -> None:
        if value == GENESIS_PARENT_HASH and self.block_number == 0:
            self._parent_hash = None
        else:
            self._parent_hash = value

    @classmethod
    def from_ir(cls, header: HeaderIR, is_detatched: bool = False) -> "Header":
        parent_hash: Optional[Hash32]
        if is_detatched or header.is_genesis:
            parent_hash = None
        else:
            parent_hash = header.parent_hash

        detatched_parent_hash: Optional[Hash32]
        if is_detatched:
            detatched_parent_hash = header.parent_hash
        else:
            detatched_parent_hash = None

        return cls(
            hash=header.hash,
            is_canonical=header.is_canonical,
            _parent_hash=parent_hash,
            _detatched_parent_hash=detatched_parent_hash,
            uncles_hash=header.uncles_hash,
            coinbase=header.coinbase,
            state_root=header.state_root,
            transaction_root=header.transaction_root,
            receipt_root=header.receipt_root,
            _bloom=header.bloom,
            difficulty=header.difficulty,
            block_number=header.block_number,
            gas_limit=header.gas_limit,
            gas_used=header.gas_used,
            timestamp=header.timestamp,
            extra_data=header.extra_data,
            # mix_hash=header.mix_hash,
            nonce=header.nonce,
        )
예제 #13
0
def _Session(engine, _schema):
    Session.configure(bind=engine)
    return Session
예제 #14
0
class Header(Base):
    query = Session.query_property()

    __tablename__ = "header"

    hash = Column(LargeBinary(32), primary_key=True)

    block = relationship("Block", uselist=False, back_populates="header")
    uncle_blocks = relationship("Block",
                                secondary="blockuncle",
                                order_by=BlockUncle.idx)

    is_canonical = Column(Boolean, nullable=False)

    _parent_hash = Column(LargeBinary(32),
                          ForeignKey("header.hash"),
                          nullable=True,
                          index=True)
    uncles_hash = Column(LargeBinary(32), nullable=False)
    coinbase = Column(LargeBinary(20), nullable=False)
    state_root = Column(LargeBinary(32), nullable=False)
    transaction_root = Column(LargeBinary(32), nullable=False)
    receipt_root = Column(LargeBinary(32), nullable=False)
    _bloom = Column(LargeBinary(1024), nullable=False)
    difficulty = Column(LargeBinary(32), nullable=False)
    block_number = Column(BigInteger, index=True, nullable=False)
    gas_limit = Column(BigInteger, nullable=False)
    gas_used = Column(BigInteger, nullable=False)
    timestamp = Column(Integer, nullable=False)
    extra_data = Column(LargeBinary, nullable=False)
    # mix_hash = Column(LargeBinary(32), nullable=False)
    nonce = Column(LargeBinary(8), nullable=False)

    children = relationship(
        "Header",
        backref=backref("parent", remote_side=[hash])  # type: ignore
    )

    @property
    def parent_hash(self) -> Optional[Hash32]:
        if self._parent_hash is None:
            if self.block_number == 0:
                return GENESIS_PARENT_HASH
            else:
                return None
        else:
            return Hash32(self._parent_hash)

    @parent_hash.setter
    def parent_hash(self, value: Optional[Hash32]) -> None:
        if value == GENESIS_PARENT_HASH and self.block_number == 0:
            self._parent_hash = None
        else:
            self._parent_hash = value

    @classmethod
    def from_ir(cls, header: HeaderIR) -> "Header":
        return cls(
            hash=header.hash,
            is_canonical=header.is_canonical,
            _parent_hash=None if header.is_genesis else header.parent_hash,
            uncles_hash=header.uncles_hash,
            coinbase=header.coinbase,
            state_root=header.state_root,
            transaction_root=header.transaction_root,
            receipt_root=header.receipt_root,
            _bloom=header.bloom,
            difficulty=header.difficulty,
            block_number=header.block_number,
            gas_limit=header.gas_limit,
            gas_used=header.gas_used,
            timestamp=header.timestamp,
            extra_data=header.extra_data,
            # mix_hash=header.mix_hash,
            nonce=header.nonce,
        )