Sebagai seorang pengembang independen, saya menghabiskan waktu satu setengah bulan untuk membangun dari nol sebuah aplikasi desktop pemantauan dan analisis cerdas berbasis Web3 bernama "Siao Nan Web3 Sentinel". Aplikasi ini mendukung semua rantai yang kompatibel dengan EVM dan rantai Solana, mengintegrasikan interpretasi perdagangan AI, pengiriman multi-saluran, penggabungan data on-chain, dan fitur canggih lainnya, dan telah berjalan stabil selama beberapa bulan.

Sebelumnya saya telah menerbitkan sebuah ringkasan teknis, tetapi saya merasa analisis terhadap implementasi inti masih kurang "memuaskan". Oleh karena itu, saya memutuskan untuk menulis ulasan teknis mendalam ini, berbagi tanpa reservasi tentang keputusan desain dan detail implementasi yang tersembunyi di dalam kode dari berbagai dimensi seperti arsitektur proses, model I/O, konsistensi data, dan rekayasa AI. Saya berharap artikel ini dapat memberikan referensi yang berharga bagi pengembang yang juga menjelajahi bidang Web3.

Satu, Arsitektur Proses: Mengapa memilih "proses utama + beberapa proses anak"?

Banyak skrip pemantauan Python di pasaran menggunakan satu proses asyncio, tetapi saya dengan tegas memilih arsitektur mikro kernel "proses utama (GUI) + proses anak independen (EVM/SOL)" sejak awal desain.

1.1 Isolasi dan stabilitas mengalahkan segalanya

Koneksi WebSocket pada jaringan yang berfluktuasi sangat mudah memicu reconnect yang tidak normal, bahkan pustaka tingkat bawah dapat crash karena alasan yang tidak diketahui. Jika GUI dan log pemantauan dicampur dalam satu proses, setiap pengecualian yang tidak ditangkap atau pelanggaran akses memori dapat menyebabkan seluruh aplikasi desktop gagal. Dengan subprocess.Popen, saya memisahkan logika pemantauan EVM dan Solana menjadi proses anak, saya mewujudkan isolasi fisik: Evm.py crash atau dipaksa kill, jendela utama tetap berjalan normal, ikon baki tidak menghilang, pengguna dapat mengklik "Mulai" untuk menariknya kembali.

Transmisi log: Proses utama menangkap stdout proses anak melalui saluran, menggunakan thread forwardoutput untuk membaca baris demi baris, membersihkan kode warna ANSI, dan kemudian menyuntikkan JS ke DOM frontend melalui window.evaluate_js, mewujudkan penyegaran log waktu nyata sambil mempertahankan ringan thread UI.

1.2 Detail manajemen siklus hidup

Dalam core_process.py, menghentikan proses anak tidak sesederhana terminate(). Saya menerapkan satu set mekanisme pembunuhan yang kuat:

python

proc.terminate()

proc.wait(timeout=3)

if proc.poll() is None:

proc.kill()

proc.wait(timeout=2)

if proc.poll() is None:

os.system(f'taskkill /F /PID {proc.pid}')

Serangkaian kombinasi ini memastikan bahwa bahkan jika interpreter Python macet, lapisan bawah Windows dapat sepenuhnya membersihkan pohon proses, menghindari proses yang tersisa menghabiskan port atau mengunci database, yang dapat menyebabkan kegagalan saat memulai berikutnya.

Dua, Model I/O dan koneksi yang sangat tersedia: bukan hanya asyncio

2.1 Mode pemantauan campuran: WSS real-time + kompensasi RPC

Untuk koin asli dari rantai EVM, karena tidak ada log event Transfer standar, tidak mungkin untuk berlangganan melalui WSS. Saya merancang kompensator polling: setiap 60 detik mendapatkan eth_getBalance melalui RPC, dan membandingkannya dengan snapshot memori, jika selisihnya lebih dari 1e-18, pemicu pengiriman. Mekanisme yang tampaknya sederhana ini sebenarnya adalah garis pertahanan terakhir saat berlangganan WSS tidak aktif.

Untuk token dan NFT, sistem berlangganan logs, dan memproses dengan cermat event TransferSingle dan TransferBatch dari ERC1155. Khususnya TransferBatch, bidang data-nya berisi array dinamis, saya menerapkan parsing offset manual berdasarkan spesifikasi ABI, bukan mengandalkan pustaka berat, yang secara signifikan mengurangi beban parsing.

2.2 Penundaan eksponensial WSS dan pengalihan panas node

Dalam lingkungan produksi, node RPC/WSS publik dapat dibatasi atau gagal kapan saja. Saya menerapkan rotasi node dan strategi reconnect dalam chain_wss_monitor_direction:

Kolam node: Dalam file konfigurasi, beberapa WSS_NODES dikonfigurasi untuk setiap rantai, memilih satu secara acak atau berurutan saat mulai.

Algoritma penundaan: Setelah koneksi terputus, interval percobaan dimulai dari 5 detik, setiap kali menggandakan hingga 60 detik, untuk menghindari badai penghubungan DDoS sebelum node pulih.

Adaptasi lingkungan jaringan domestik: sistem mendukung pengaturan alamat HTTP perangkat lunak proxy lokal, meneruskan lalu lintas WSS ke proxy melalui pustaka websockets_proxy, memulihkan komunikasi stabil dengan node luar negeri.

2.3 Jalur analisis asinkron Solana

Kecepatan blok Solana sangat cepat, dan struktur transaksi sangat kompleks. Untuk menghindari pemanggilan API Helius yang menghalangi penerimaan pesan WSS, saya merancang model decoupling produsen-konsumen:

Produsen: Setelah WSS logsSubscribe menerima tanda tangan, segera memasukkannya ke dalam asyncio.Queue atau langsung memicu tugas latar belakang asyncio.create_task.

Konsumen: Tugas asinkron independen bertanggung jawab untuk memanggil antarmuka Helius /v0/transactions, menganalisis nativeTransfers, tokenTransfers, events.nft, dan bidang lainnya.

Ini menjamin bahwa loop recv() koneksi WSS tidak akan pernah terjebak oleh permintaan HTTP lambat, memastikan real-time pesan dalam lingkungan TPS yang sangat tinggi.

Tiga, Konsistensi data: dari penghapusan memori ke batas SQLite

3.1 Sisi EVM: Indeks unik database

Dalam pemantauan EVM, transaksi yang sama mungkin diproses berkali-kali karena reconnect WSS, kompensasi polling, dll. Bergantung hanya pada set memori tidak dapat menangani restart proses. Oleh karena itu, saya merancang batas unik komposit untuk tabel tx_history:

sql

UNIQUE(tx_hash, log_index, address)

Setiap penyisipan ulang akan dibuang secara diam-diam oleh SQLite dengan ON CONFLICT IGNORE, menjamin idempotensi dari sisi inti database. Untuk transfer koin asli yang tidak memiliki log_index, akan diturunkan menggunakan tx_hash + address sebagai kunci gabungan.

3.2 Sisi Solana: Penghapusan tanda tangan dalam jendela waktu

Transaksi Solana tidak memiliki konsep log_index, dan analisis Helius dapat menghasilkan beberapa catatan. Saya menggunakan set memori untuk menyimpan tanda tangan yang baru diproses, dan menggunakan pemikiran varian LimitedSizeDict, ketika jumlah tanda tangan melebihi 1000, secara otomatis menghapus setengahnya (atau menggunakan OrderedDict untuk mengeluarkan entri tertua). Penghapusan jendela geser ini mencapai keseimbangan yang baik antara kinerja dan akurasi.

Empat, Rekayasa AI: Toleransi kesalahan multi-penyedia dan seni parsing JSON

4.1 Penjadwalan dinamis berbasis fitur

MultiAIClient adalah inti dari modul AI. Ini bukan hanya percabangan if-else sederhana, tetapi merupakan pengatur jadwal berbasis fitur. File konfigurasi mendefinisikan fungsi yang didukung oleh setiap penyedia (seperti transaction_insight, daily_report, dll.). Saat permintaan dilakukan, sistem akan menyaring daftar penyedia yang mendukung fitur tersebut, mengajukan permintaan berdasarkan prioritas, dan jika waktu habis atau gagal, secara otomatis menurunkan ke yang berikutnya.

4.2 Parsing defensif output LLM

Output model besar JSON yang tidak stabil adalah hal yang biasa. Proses penanganan saya jauh lebih kompleks daripada json.loads:

Pembersihan: Menghapus penanda blok kode Markdown json` dan.

Ekstraksi reguler: Jika parsing gagal, langsung gunakan ekspresi reguler r'"insight"\s*:\s*"([^"]*)"' untuk mengekstrak bidang secara brutal, ini adalah garis pertahanan terakhir.

Pemetaan bidang: kompatibel dengan berbagai penamaan kunci seperti insight / Insight / interpretasi.

Mekanisme ini memastikan bahwa bahkan jika Moonshot atau DeepSeek mengembalikan "setengah JSON", frontend tetap dapat menampilkan interpretasi yang valid, tanpa memunculkan JSONDecodeError yang menyebabkan layar putih.

Lima, Memori dan kinerja: LimitedSizeDict dan antrean asinkron

5.1 Kamus kapasitas terbatas kustom

Pustaka standar Python tidak memiliki kamus LRU bawaan dan terbatas ukuran. Saya telah mengimplementasikan LimitedSizeDict berdasarkan collections.OrderedDict:

python

def setitem(self, key, value):

if len(self) >= self.max_size:

self.popitem(last=False) # Menghapus item yang paling awal dimasukkan

super().__setitem__(key, value)

Struktur data sederhana ini digunakan untuk caching informasi Token, caching harga, dan caching metadata NFT. Ini memastikan bahwa selama waktu berjalan yang lama, penggunaan memori tidak akan meningkat secara linier seiring bertambahnya alamat yang dipantau, tetapi tetap stabil pada level yang sangat rendah.

5.2 Penulisan asinkron log Solana secara serial

Catatan transaksi Solana yang rinci perlu ditulis ke file JSON. Jika beberapa coroutine melakukan json.dump secara bersamaan, sangat mudah menyebabkan kerusakan format file. Saya memperkenalkan asyncio.Queue:

Semua permintaan penulisan log akan memasukkan data ke dalam antrean.

Satu-satunya coroutine latar belakang filewriter yang menghalangi menunggu antrean, mengambil data dan kemudian melakukan I/O file.

Ini tidak hanya menghindari kunci thread yang rumit, tetapi juga memanfaatkan fitur asinkron untuk menjamin keamanan data di bawah beban tinggi.

Enam, Komunikasi dua arah antara frontend dan backend: integrasi mendalam pywebview

6.1 Penyuntikan API JS

pywebview memungkinkan metode objek Python untuk diekspos langsung ke JavaScript frontend. Kelas Api saya mewarisi dari beberapa Mixin, semua metode publik yang diawali dengan def secara otomatis menjadi anggota window.pywebview.api. Ini memungkinkan saya untuk mewujudkan pemisahan frontend dan backend dengan biaya yang sangat rendah, di mana frontend hanya perlu fokus pada interaksi UI.

6.2 Instance dan komunikasi terpisah dari jendela mengambang

Jendela mengambang bukanlah DIV anak dari jendela utama, tetapi adalah jendela independen kedua yang dibuat oleh pywebview. Saya mengelola siklus hidupnya melalui FloatingWindowManager dan menggunakan instance js_api dari proses utama untuk menyuntikkan kode JS ke jendela mengambang (evaluate_js), mewujudkan pengiriman log dari jendela utama ke jendela mengambang secara waktu nyata. Desain ini memastikan bahwa jendela mengambang meskipun ditutup, tidak akan mempengaruhi jalannya tugas pemantauan utama.

Tujuh, Peng打包 aplikasi desktop: Lubang dalam PyInstaller dan praktik rekayasa

Menyerahkan proyek Python kepada pengguna akhir yang tidak memiliki latar belakang teknis, meng打包 menjadi EXE independen adalah jalan yang harus dilalui. PyInstaller tampaknya dapat diselesaikan dengan satu perintah, tetapi dalam proyek yang kompleks, ada banyak detail yang dapat membuat pengembang frustrasi. Bagian ini berbagi beberapa lubang dalam proses peng打包 "Xiao Nan Web3 Sentinel" dan solusi yang saya temui.

7.1 Impor implisit dan --hidden-import

PyInstaller membangun pohon dependensi dengan menganalisis statis pernyataan import dari file entri. Namun, banyak pustaka (seperti pystray, websockets) menggunakan importlib.import_module atau import untuk memuat submodul secara dinamis, yang menyebabkan EXE yang dikemas melempar ModuleNotFoundError saat dijalankan.

Kunci untuk menyelesaikan masalah ini adalah secara terbalik melokalisasi modul yang hilang berdasarkan informasi kesalahan, dan secara eksplisit menyatakan --hidden-import dalam perintah peng打包. Misalnya, dalam proyek ini, fungsi ikon baki harus ditambahkan:

bash

--hidden-import pystray._win32

--hidden-import pystray._util

--hidden-import win32event

--hidden-import win32api

Ini mengharuskan pengembang untuk memiliki pemahaman tertentu tentang struktur internal pustaka yang bergantung, biasanya perlu menggabungkan membaca kode sumber dan percobaan berulang untuk sepenuhnya mencantumkan semua ketergantungan implisit.

7.2 --collect-all dan perangkap file sumber daya

Koleksi pywebview tidak hanya berisi kode Python, tetapi juga bergantung pada HTML/JS frontend dan file runtime Edge WebView2. Analisis default PyInstaller tidak dapat mendeteksi sumber daya non-kode ini. Jika tidak ditangani, program yang dikemas akan mengalami layar putih karena tidak dapat menemukan index.html atau webview.js.

Cara penanganan yang benar adalah menggunakan --collect-all pywebview, parameter ini memaksa PyInstaller untuk menyalin semua file di direktori paket pywebview (termasuk biner dan sumber daya statis) secara lengkap ke direktori peng打包. Ini adalah praktik standar untuk menangani pustaka GUI "berat" semacam ini.

7.3 Ketergantungan biner dan kompresi UPX

Pustaka yang menjadi ketergantungan proyek seperti pywin32, Pillow, dll. mengandung file biner .pyd dan .dll. File-file ini cukup besar, dan setelah peng打包 oleh PyInstaller, tidak akan dikompresi secara otomatis. Dengan mengintegrasikan alat UPX dan menentukan --upx-dir dalam perintah peng打包, file biner dalam EXE akhir dapat dikompresi dengan rasio tinggi (biasanya dapat mengurangi ukuran sebesar 30%-50%). Perlu dicatat bahwa sangat sedikit perangkat lunak antivirus lama yang mungkin menghasilkan false positive terhadap program yang dibungkus UPX, tetapi untuk kelompok pengguna teknis, probabilitas ini sangat rendah dan dapat diselesaikan dengan mengirimkan sampel.

7.4 "Pembekuan" jalur dan sys._MEIPASS

Ini adalah konsep paling inti dalam peng打包an PyInstaller. Pada tahap pengembangan, program mengakses file konfigurasi dan sumber daya gambar melalui jalur file atau relatif. Setelah dikemas menjadi file EXE tunggal, semua sumber daya diekstrak ke direktori sementara, dan jalur direktori tersebut disimpan dalam variabel sys._MEIPASS.

Pengembang harus mengganti semua logika akses file secara global dalam kode, pola tipikalnya adalah sebagai berikut:

python

def get_resource_path(relative_path):

if getattr(sys, 'frozen', False):

base = sys._MEIPASS

else:

base = os.path.abspath(".")

return os.path.join(base, relative_path)

Mengabaikan penyesuaian ini akan menyebabkan program tidak dapat menemukan file eksternal saat dijalankan, ini adalah "neraka jalur" yang paling sering dihadapi oleh pemula saat meng打包. Cara saya adalah membungkus fungsi ini dalam utils.py, memanggil secara konsisten di seluruh proyek, memastikan konsistensi perilaku jalur sebelum dan sesudah peng打包.

7.5 Penanganan khusus untuk proses anak

Sistem ini mengadopsi arsitektur proses utama yang memulai proses anak. Setelah peng打包, skrip proses anak Evm.py dan Sol.py juga dikemas di dalam EXE. Jika proses utama masih mencoba memulai Evm.py dengan python.exe, itu akan gagal karena file tidak ditemukan. Solusi saya adalah mendeteksi secara dinamis apakah dalam mode peng打包 saat proses utama memulai proses anak, dan menyampaikan parameter --main-exe-dir yang benar agar proses anak dapat menemukan direktori luar tempat file konfigurasi berada. Detail logika ini telah dijelaskan dalam bab arsitektur proses, dan tidak akan dibahas lebih lanjut di sini.

Delapan, Kesimpulan

Mereview seluruh proses pengembangan, dari skrip tunggal ke arsitektur multiproses, dari WebSocket telanjang ke kolam node yang sangat tersedia, dari log print sederhana ke penyimpanan SQLite terstruktur, setiap langkah adalah pendalaman pemahaman rekayasa. Eksplorasi dalam tahap peng打包 membuat saya merasakan dengan mendalam: dapat membuat perangkat lunak berjalan stabil hanyalah langkah pertama, dapat membuat pengguna menggunakannya dengan mudah adalah pengiriman yang sebenarnya.

Ini bukan hanya alat pemantauan, tetapi juga merupakan kumpulan pengalaman praktik saya di bidang pemrograman asinkron, manajemen proses, integrasi AI, dan pengembangan perangkat lunak desktop.

Jika Anda tertarik dengan rincian teknis apa pun dalam teks, silakan kunjungi GITHUB saya:

https://github.com/pingdj/Web3

Dapatkan perangkat lunak dan lebih banyak dokumentasi teknis. Saya juga berharap dapat berdiskusi dan bertukar ide dengan semua orang di Binance Square.

Profil penulis: Xiao Nan, pengembang mandiri & Web3, fokus pada aplikasi desktop Python, analisis data blockchain, dan penerapan rekayasa AI.

$BNB

BNB
BNB
791.78
+0.19%