Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classifier update #108

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
e4d1e99
WIP: event classifier
verdigos Jan 30, 2024
e07d650
WIP: event classifier 2
verdigos Mar 13, 2024
e2b43b1
Fix magic numbers
verdigos May 23, 2024
bf8b5f7
Minor fixes. Add failed property to block. Add subscriptions and wton…
verdigos Jun 3, 2024
4e8b248
WIP: event classifier 3
verdigos Jun 25, 2024
cb17e05
WIP: Event classifier 4
verdigos Jul 13, 2024
e545964
WIP: Event classifier 5
verdigos Jul 19, 2024
eac4fa7
WIP: Event classifier 6
verdigos Aug 3, 2024
fcc1afb
WIP: Event classifier 7. Multiprocessing
verdigos Aug 11, 2024
7da0614
WIP: Event classifier 8
verdigos Aug 26, 2024
9fb5201
WIP: Event classifier 9
verdigos Sep 2, 2024
7b7d33d
Fix requirements
verdigos Sep 2, 2024
b777778
Fix auction bid action
verdigos Sep 3, 2024
1de29d8
Add missing NftAuction class
verdigos Sep 10, 2024
1f949b6
Fix run_event_classifier.sh
verdigos Sep 10, 2024
12de7c7
Fix run_event_classifier.sh
verdigos Sep 10, 2024
00f7bc5
Fix run_event_classifier.sh
verdigos Sep 10, 2024
49e2eb9
Fix jetton transfer's forward payload decoding
verdigos Sep 11, 2024
821f53d
Added docker file, fixed redis and added separate thread for fetching…
kdimentionaltree Sep 14, 2024
19b0057
Change action id calculation
verdigos Sep 15, 2024
7503147
Remove deprecated module
verdigos Sep 15, 2024
0863425
Revert db engine changes after rebase
verdigos Sep 15, 2024
62d66df
Add trace classifier (#82)
verdigos Sep 16, 2024
b895199
Added golang API
kdimentionaltree Sep 16, 2024
250ad77
Fixed dialect problem
kdimentionaltree Sep 17, 2024
30fc4f5
Docker standalone setup update
kdimentionaltree Sep 17, 2024
53fc0a5
Updated docker setup
kdimentionaltree Sep 17, 2024
df4e503
Updated submodule
kdimentionaltree Sep 17, 2024
f8c1715
Updated readme
kdimentionaltree Sep 17, 2024
8f39d94
Add jetton_mint action. Fixes, WIP
1IxI1 Sep 28, 2024
514ed2b
Add stonfi v2 swaps, provide and withdraw liquidity actions support
verdigos Oct 8, 2024
f8a3654
Fix stonfi swap v2 serialization error
verdigos Oct 8, 2024
5ec9ce9
Update deposit and withdraw liquidity actions and matchers
verdigos Oct 23, 2024
fa09781
Fix naming. Add missing field to withdraw liquidity action
verdigos Oct 23, 2024
40fb0b0
Dedust liquidity deposit, refactor
1IxI1 Oct 28, 2024
f84fb77
Liq.: add user jwallets
1IxI1 Nov 7, 2024
7eaccba
Change db, fixes
1IxI1 Nov 9, 2024
5139ce1
Clean comments
1IxI1 Nov 9, 2024
05743ee
Add temporary fields to actions to save accounts and tx hashes includ…
verdigos Nov 14, 2024
cde76cf
Additional logging
verdigos Nov 14, 2024
3e6732c
Save action accounts into separate table
verdigos Nov 14, 2024
e0378a3
Fix error while saving actions
verdigos Nov 14, 2024
52d8b63
Fix failed nft transfers
verdigos Nov 15, 2024
504d10b
Fix missing prev owner
verdigos Nov 15, 2024
f5a30dc
Liquid staking withdraw/deposit
1IxI1 Nov 21, 2024
d3c3d8f
Add dns renew action
verdigos Nov 21, 2024
28179c4
Reorder db type
1IxI1 Nov 21, 2024
05448da
Merge branch 'events-fixes' into events-fixes-extended-actions
verdigos Nov 21, 2024
730524a
Merge branch 'classifier-mint-liq' into events-fixes-extended-actions
verdigos Nov 21, 2024
4438df4
Optimize imports
verdigos Nov 21, 2024
d409850
Combine dedust liquidity deposit blocks
verdigos Nov 21, 2024
6e42b77
Merge branch 'feature/stonfi-v2' into events-fixes-extended-actions
verdigos Nov 22, 2024
6078f10
Ton stakers actions improvements
verdigos Nov 22, 2024
ba02bb3
Liquidity provisioning actions improvements
verdigos Nov 22, 2024
8a4b7b8
Save nft mint opcode
verdigos Nov 22, 2024
932ee53
Fix staking details db field
verdigos Nov 22, 2024
1f9a34e
Fix serializing empty blocks
verdigos Nov 22, 2024
3f587cc
Fix opcode error
verdigos Nov 22, 2024
fd11d8f
Add warning when serializing unexpected action type
verdigos Nov 22, 2024
c3fe0f9
Remove debug prints
verdigos Nov 22, 2024
a31acf5
Fix action type
verdigos Nov 22, 2024
1a4692b
Fix failed stake deposit
verdigos Nov 22, 2024
95cbd54
Fix swaps
verdigos Nov 22, 2024
3c92f71
Fix min lt utime block calculation
verdigos Nov 22, 2024
df99fc1
Fix swaps
verdigos Nov 22, 2024
c0ba3b7
Add nominator pool deposit/withdraw request
1IxI1 Nov 23, 2024
4183aec
Add missing jetton mint matcher
verdigos Nov 24, 2024
37baf56
Change renew dns action name
verdigos Nov 24, 2024
1f8a4ca
Fix failed jetton mints support
verdigos Nov 24, 2024
842c364
Fix failed jetton burns support
verdigos Nov 24, 2024
14de16f
Add proper handling for failed jetton mints. Save ton_amount for mints
verdigos Nov 24, 2024
ca2718a
Fix tonstakers withdraw
verdigos Nov 24, 2024
5704556
Fix false positive elector recover/deposit state detection
verdigos Nov 24, 2024
dfd86b0
Fix pool address for ton stakers withdraw liquidity
verdigos Nov 25, 2024
7d5f41b
Fix import error
verdigos Nov 25, 2024
472ad2f
Fix dedust deposit liquidity
verdigos Nov 25, 2024
16832d2
Merge branch 'classifier-mint-liq' into events-fixes-extended-actions
verdigos Nov 25, 2024
8186956
Nominator pool staking improvements
verdigos Nov 26, 2024
1089906
Fix nominator pool amount field
verdigos Nov 26, 2024
4244795
Add contract deployments
verdigos Nov 26, 2024
aeb2552
Better auction bid actions support
verdigos Nov 26, 2024
ac9e358
Dedust withdraw liquidity
1IxI1 Dec 2, 2024
0e659a0
Temporary add try excepts in unclassified events reader
verdigos Dec 4, 2024
73b0d45
Merge remote-tracking branch 'refs/remotes/vimlover/events-fixes-exte…
verdigos Dec 5, 2024
295fd39
Dedust liquidity withdrawal fixes
verdigos Dec 5, 2024
a5aa470
Fix earliest block calculation
verdigos Dec 11, 2024
b092cb3
Fix pton transfers
verdigos Dec 11, 2024
1ab2e2c
Revert "Temporary add try excepts in unclassified events reader"
verdigos Dec 12, 2024
5ed8352
Fix contract deployment duplication
verdigos Dec 12, 2024
5edbea2
Improved failed ton transfers detection
verdigos Dec 15, 2024
4d769a7
Improved failed ton transfers detection 2
verdigos Dec 16, 2024
b5b2450
Use tx_hashes instead of extended_tx_hashes. Remove extended_tx_hashes
verdigos Dec 16, 2024
c2d1334
try catch fix
kdimentionaltree Dec 17, 2024
07f4e2d
Merge remote-tracking branch 'upstream/events-fixes' into events-fixe…
verdigos Jan 13, 2025
460a1ee
Add trace_end_lt to actions. Add trace_end_lt, action_end_lt to actio…
verdigos Jan 13, 2025
907f396
Add trace_end_utime, trace_external_hash to actions. Add trace_end_ut…
verdigos Jan 15, 2025
a863919
Revert changes to default params values in event_classifier.py
verdigos Jan 15, 2025
ee68312
Add mc_seqno_end and trace_mc_seqno_end to actions
verdigos Jan 16, 2025
afff641
Add extra currencies support
verdigos Jan 20, 2025
b0a93e8
Fix extra currencies
verdigos Jan 20, 2025
c7a1811
Fix extra currencies 2
verdigos Jan 20, 2025
d23acc1
Exclude referral payouts from swap actions
verdigos Jan 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,8 @@ venv.bak/

/sandbox
.env*
env
sandbox.ipynb
Session.vim
indexer/indexer/core/t_est.py
some.txt
21 changes: 13 additions & 8 deletions indexer/event_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,21 @@
import sys
import time
import traceback

from typing import Optional
from datetime import timedelta
from typing import Optional

from sqlalchemy import update, select, and_, or_
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import sessionmaker, contains_eager

from indexer.core import redis
from indexer.core.database import engine, Trace, Transaction, Message, Action, TraceEdge, SyncSessionMaker
from indexer.core.database import engine, Trace, Transaction, Message, Action, SyncSessionMaker
from indexer.core.settings import Settings
from indexer.events import context
from indexer.events.blocks.utils.address_selectors import extract_additional_addresses
from indexer.events.blocks.utils.block_tree_serializer import block_to_action
from indexer.events.blocks.utils.event_deserializer import deserialize_event
from indexer.events.event_processing import process_event_async
from indexer.events.event_processing import process_event_async, process_event_async_with_postprocessing
from indexer.events.interface_repository import EmulatedTransactionsInterfaceRepository, gather_interfaces, \
RedisInterfaceRepository

Expand Down Expand Up @@ -284,6 +282,9 @@ async def process_trace_batch_async(ids: list[str]):
# logger.error(f"query: {insert(Action).values(actions).on_conflict_do_nothing()}")
# session.execute(insert(Action).values(actions).on_conflict_do_nothing())
session.add_all(actions)
for action in actions:
session.add_all(action.get_action_accounts())

if state == 'ok':
ok_traces.append(trace_id)
else:
Expand All @@ -308,16 +309,20 @@ async def process_trace(trace: Trace) -> tuple[str, str, list[Action]]:
if len(trace.transactions) == 1 and trace.transactions[0].descr == 'tick_tock':
return trace.trace_id, 'ok', []
try:
result = await process_event_async(trace)
result = await process_event_async_with_postprocessing(trace)
actions = []
state = 'ok'
for block in result.bfs_iter():
for block in result:
if block.btype != 'root':
if block.btype == 'call_contract' and block.event_nodes[0].message.destination is None:
continue
if block.btype == 'empty':
continue
if block.btype == 'call_contract' and block.event_nodes[0].message.source is None:
continue
if block.broken:
state = 'broken'
action = block_to_action(block, trace.trace_id)
action = block_to_action(block, trace.trace_id, trace)
actions.append(action)
return trace.trace_id, state, actions
except Exception as e:
Expand Down
57 changes: 57 additions & 0 deletions indexer/indexer/core/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def get_engine(settings: Settings):
pool_timeout=128,
echo=False)
return engine

engine = get_engine(settings)
SessionMaker = sessionmaker(bind=engine, class_=AsyncSession)

Expand Down Expand Up @@ -185,6 +186,15 @@ class TraceEdge(Base):

trace: "Trace" = relationship("Trace", back_populates="edges", viewonly=True)

class ActionAccount(Base):
__tablename__ = 'action_accounts'
action_id: str = Column(String, primary_key=True)
trace_id: str = Column(String, primary_key=True)
account: str = Column(String(70), primary_key=True)
trace_end_lt: int = Column(Numeric)
action_end_lt: int = Column(Numeric)
trace_end_utime: int = Column(Numeric)
action_end_utime: int = Column(Numeric)

class Action(Base):
__tablename__ = 'actions'
Expand Down Expand Up @@ -265,6 +275,40 @@ class Action(Base):
]))
nft_mint_data = Column(CompositeType("nft_mint_details", [
Column("nft_item_index", Numeric)]))
dex_deposit_liquidity_data = Column(CompositeType("dex_deposit_liquidity_details", [
Column("dex", String),
Column("amount1", Numeric),
Column("amount2", Numeric),
Column("asset1", String),
Column("asset2", String),
Column('user_jetton_wallet_1', String),
Column('user_jetton_wallet_2', String),
Column("lp_tokens_minted", Numeric),
]))
dex_withdraw_liquidity_data = Column(CompositeType("dex_withdraw_liquidity_details", [
Column("dex", String),
Column("amount1", Numeric),
Column("amount2", Numeric),
Column('asset1_out', String),
Column('asset2_out', String),
Column('user_jetton_wallet_1', String),
Column('user_jetton_wallet_2', String),
Column('dex_jetton_wallet_1', String),
Column('dex_jetton_wallet_2', String),
Column("lp_tokens_burnt", Numeric),
]))
staking_data = Column(CompositeType("staking_details", [
Column("provider", String),
Column("ts_nft", String),
]))
trace_end_lt: int = Column(Numeric)
trace_end_utime: int = Column(Numeric)
trace_external_hash: str = Column(String)
mc_seqno_end: int = Column(Numeric)
trace_mc_seqno_end: int = Column(Numeric)
accounts: list[str]
value_extra_currencies: dict = Column(JSONB)


def __repr__(self):
full_repr = ""
Expand All @@ -274,6 +318,18 @@ def __repr__(self):
full_repr += f"{key}={value}, "
return full_repr

def get_action_accounts(self):
accounts = []
for account in self.accounts:
accounts.append(ActionAccount(action_id=self.action_id,
trace_id=self.trace_id,
account=account,
action_end_lt=self.end_lt,
trace_end_lt=self.trace_end_lt,
trace_end_utime=self.trace_end_utime,
action_end_utime=self.end_utime))
return accounts

class Transaction(Base):
__tablename__ = 'transactions'
__table_args__ = (
Expand Down Expand Up @@ -409,6 +465,7 @@ class Message(Base):
import_fee: int = Column(BigInteger)
body_hash: str = Column(String(44))
init_state_hash: Optional[str] = Column(String(44), nullable=True)
value_extra_currencies: dict = Column(JSONB, nullable=True)

transaction = relationship("Transaction",
viewonly=True,
Expand Down
15 changes: 13 additions & 2 deletions indexer/indexer/events/blocks/auction.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,29 @@ async def build_block(self, block: Block, other_blocks: list[Block]) -> list[Blo
bid_block = AuctionBid({})

if 'NftAuction' in interfaces:
bid_block.data = {
nft_address = interfaces['NftAuction']['nft_addr']
nft_item = await context.interface_repository.get().get_nft_item(nft_address)
data = {
'amount': Amount(block.event_nodes[0].message.value),
'bidder': AccountId(block.event_nodes[0].message.source),
'auction': AccountId(block.event_nodes[0].message.destination),
'nft_address': AccountId(interfaces['NftAuction']['nft_addr']),
'nft_address': AccountId(nft_address),
'nft_item_index': None,
'nft_collection': None
}
if nft_item:
data['nft_item_index'] = nft_item.index
data['nft_collection'] = AccountId(nft_item.collection_address)
bid_block.data = data
elif 'NFTItem' in interfaces and _is_teleitem(interfaces['NFTItem']):
nft_data = interfaces['NFTItem']
bid_block.data = {
'amount': Amount(block.event_nodes[0].message.value),
'bidder': AccountId(block.event_nodes[0].message.source),
'auction': AccountId(block.event_nodes[0].message.destination),
'nft_address': AccountId(block.event_nodes[0].message.destination),
'nft_collection': AccountId(nft_data['collection_address']) if nft_data['collection_address'] is not None else None,
'nft_item_index': nft_data['index'] if nft_data['index'] is not None else None
}
else:
return []
Expand Down
36 changes: 28 additions & 8 deletions indexer/indexer/events/blocks/basic_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,34 @@ def __init__(self, node: EventNode):
self.comment = None

super().__init__('ton_transfer', [node], {
'extra_currencies': node.message.value_extra_currencies,
'source': AccountId(node.message.source) if node.message.source is not None else None,
'destination': AccountId(
node.message.destination) if node.message.destination is not None else None,
'value': Amount(node.message.value),
'comment': self.comment,
'encrypted': self.encrypted,
})
self.failed = node.failed
if node.failed:
if node.message is not None and node.message.bounce == True:
self.failed = True
elif node.get_tx() is not None and node.get_tx().end_status == 'uninit':
self.failed = False
else:
self.failed = True
self.value = node.message.value

_fill_flow_from_node(self.value_flow, node)


class ContractDeploy(Block):
def __init__(self, node: EventNode):
super().__init__('contract_deploy', [], node.message.transaction.account)
self.failed = node.failed

tx = node.get_tx()
if tx is not None and tx.end_status == 'active' and tx.orig_status not in ('active', 'frozen'):
self.children_blocks.append(ContractDeploy(node))

class CallContractBlock(Block):
opcode: int

def __init__(self, node: EventNode):
super().__init__('call_contract', [node], {
'extra_currencies': node.message.value_extra_currencies,
'opcode': node.get_opcode(),
'source': AccountId(node.message.source) if node.message.source is not None else None,
'destination': AccountId(
Expand All @@ -82,6 +86,9 @@ def __init__(self, node: EventNode):
self.is_external = node.message.source is None
self.opcode = node.get_opcode()
_fill_flow_from_node(self.value_flow, node)
tx = node.get_tx()
if tx is not None and tx.end_status == 'active' and tx.orig_status not in ('active', 'frozen'):
self.children_blocks.append(ContractDeploy(node))

def get_body(self) -> Slice:
return Slice.one_from_boc(self.event_nodes[0].message.message_content.body)
Expand All @@ -91,3 +98,16 @@ def get_message(self) -> Message:

def __repr__(self):
return f"!{self.btype}:={hex(self.opcode)}"

class ContractDeploy(Block):
def __init__(self, node: EventNode):
super().__init__('contract_deploy', [node], {
'opcode': node.get_opcode(),
'source': AccountId(node.message.source) if node.message.source is not None else None,
'destination': AccountId(
node.message.destination) if node.message.destination is not None else None,
'value': Amount(node.message.value),
})
self.failed = node.failed
self.is_external = node.message.source is None
self.opcode = node.get_opcode()
28 changes: 24 additions & 4 deletions indexer/indexer/events/blocks/basic_matchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ def __init__(self, child_matcher: BlockMatcher | None = None,
parent_matcher: BlockMatcher | None = None,
optional=False,
children_matchers=None,
include_excess=True):
include_excess=True,
include_bounces=True,
pre_build_auto_append=False):
self.child_matcher = child_matcher
self.children_matchers = children_matchers
self.parent_matcher = parent_matcher
self.optional = optional
self.include_excess = include_excess
self.include_bounces = include_bounces
self.pre_build_auto_append = pre_build_auto_append

def test_self(self, block: Block):
def test_self(self, block: Block) -> bool:
return True

async def try_build(self, block: Block) -> list[Block] | None:
Expand All @@ -36,10 +40,19 @@ async def try_build(self, block: Block) -> list[Block] | None:
parent_matched = await self.process_parent_matcher(block, blocks, parent_matched)
if self_matched and parent_matched and child_matched:
try:
r = await self.build_block(block, blocks)
auto_append_opcodes = []
if self.include_excess:
auto_append_opcodes.append(ExcessMessage.opcode)
if self.include_bounces:
auto_append_opcodes.append(0xffffffff)
if len(auto_append_opcodes) > 0 and self.pre_build_auto_append:
for next_block in block.next_blocks:
if isinstance(next_block, CallContractBlock) and next_block.opcode in auto_append_opcodes:
blocks.append(next_block)
r = await self.build_block(block, blocks)
if len(auto_append_opcodes) > 0 and not self.pre_build_auto_append:
for next_block in block.next_blocks:
if isinstance(next_block, CallContractBlock) and next_block.opcode == ExcessMessage.opcode:
if isinstance(next_block, CallContractBlock) and next_block.opcode in auto_append_opcodes:
r.append(next_block)
return r
except Exception as e:
Expand Down Expand Up @@ -153,6 +166,13 @@ def __init__(self, block_type, child_matcher=None, parent_matcher=None, optional
def test_self(self, block: Block):
return block.btype == self.block_type

class GenericMatcher(BlockMatcher):
def __init__(self, test_self_func, child_matcher=None, parent_matcher=None, optional=False):
super().__init__(child_matcher, parent_matcher, optional)
self.test_self_func = test_self_func

def test_self(self, block: Block):
return self.test_self_func(block)

def child_sequence_matcher(matchers: list[BlockMatcher]) -> BlockMatcher | None:
if len(matchers) == 0:
Expand Down
Loading