Ver3.0
์ ์ฒด ์ด๋
Ver3.0 ๐ ํ์ด์ฌ์ผ๋ก ๋ธ๋ก์ฒด์ธ ๊ฑฐ๋๋ด์ญ ์๋ ๋ถ์ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ

๐ ํ์ด์ฌ์ผ๋ก ๋ธ๋ก์ฒด์ธ ๊ฑฐ๋๋ด์ญ ์๋ ๋ถ์ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ
๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ๋ฅผ ํ์ด์ฌ์ผ๋ก ๋๋ํ๊ฒ ๋ถ์ํ๋ ์๋ฒฝ ๊ฐ์ด๋ ๐
๐ฏ ๋ธ๋ก์ฒด์ธ ๊ฑฐ๋๋ด์ญ ๋ถ์, ์ ํ์ํ ๊น?
์์ฆ ๋ธ๋ก์ฒด์ธ ๊ธฐ์ ์ด ๋์ธ์์? ๋นํธ์ฝ์ธ, ์ด๋๋ฆฌ์๋ถํฐ ์์ํด์ ์๋ง์ ์ํธํํ์ NFT, DeFi ํ๋ก์ ํธ๋ค์ด ์์์ง๊ณ ์์ด. ๊ทธ๋ฐ๋ฐ ์ด ๋ชจ๋ ๊ฑฐ๋๋ค์ด ๋ธ๋ก์ฒด์ธ์ ํฌ๋ช ํ๊ฒ ๊ธฐ๋ก๋๋ ๊ฑด ์์ง? ๐๋ฌธ์ ๋ ์ด ๋ฐ์ดํฐ๊ฐ ์์ฒญ๋๊ฒ ๋ฐฉ๋ํ๋ค๋ ๊ฑฐ์ผ. ๋งค์ผ ์๋ฐฑ๋ง ๊ฑด์ ๊ฑฐ๋๊ฐ ๋ฐ์ํ๊ณ , ๊ฐ ๊ฑฐ๋๋ง๋ค ๋ณด๋ด๋ ์ฌ๋, ๋ฐ๋ ์ฌ๋, ๊ธ์ก, ์์๋ฃ, ํ์์คํฌํ ๋ฑ ๋ค์ํ ์ ๋ณด๊ฐ ๋ด๊ฒจ์์ด. ์ด๊ฑธ ์ฌ๋์ด ์ผ์ผ์ด ํ์ธํ๋ค? ๋ถ๊ฐ๋ฅ์ ๊ฐ๊น์ง! ๐คฏ
๊ทธ๋์ ๋ฑ์ฅํ ๊ฒ ๋ฐ๋ก ์๋ ๋ถ์ ํ๋ก๊ทธ๋จ์ด์ผ. ํ์ด์ฌ์ ํ์ฉํ๋ฉด ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ์์งํ๊ณ , ํจํด์ ๋ถ์ํ๊ณ , ์๋ฏธ์๋ ์ธ์ฌ์ดํธ๋ฅผ ๋ฝ์๋ผ ์ ์์ด. ํฌ์ ์ ๋ต ์๋ฆฝ, ์ด์๊ฑฐ๋ ํ์ง, ์์ฅ ํธ๋ ๋ ๋ถ์ ๋ฑ ํ์ฉ ๋ฒ์๊ฐ ๋ฌด๊ถ๋ฌด์งํ์ง!
๐ก ์ค์ ํ์ฉ ์ฌ๋ก
โข ์ํธํํ ๊ฑฐ๋์: ์ด์๊ฑฐ๋ ํจํด ๊ฐ์ง ๋ฐ ๋ณด์ ๊ฐํ
โข ํฌ์์: ๊ณ ๋(๋๋ ๋ณด์ ์) ์์ง์ ์ถ์ ๋ฐ ํฌ์ ์ ๋ต ์๋ฆฝ
โข ์ธ๋ฌด ๋น๊ตญ: ์ํธํํ ๊ฑฐ๋ ์ถ์ ๋ฐ ๊ณผ์ธ ์๋ฃ ํ๋ณด
โข ์ฐ๊ตฌ๊ธฐ๊ด: ๋ธ๋ก์ฒด์ธ ๋คํธ์ํฌ ๋ถ์ ๋ฐ ํ์ ์ฐ๊ตฌ
โข DeFi ํ๋ก์ ํธ: ํ๋กํ ์ฝ ์ฌ์ฉ ํจํด ๋ถ์ ๋ฐ ์ต์ ํ
โข ์ํธํํ ๊ฑฐ๋์: ์ด์๊ฑฐ๋ ํจํด ๊ฐ์ง ๋ฐ ๋ณด์ ๊ฐํ
โข ํฌ์์: ๊ณ ๋(๋๋ ๋ณด์ ์) ์์ง์ ์ถ์ ๋ฐ ํฌ์ ์ ๋ต ์๋ฆฝ
โข ์ธ๋ฌด ๋น๊ตญ: ์ํธํํ ๊ฑฐ๋ ์ถ์ ๋ฐ ๊ณผ์ธ ์๋ฃ ํ๋ณด
โข ์ฐ๊ตฌ๊ธฐ๊ด: ๋ธ๋ก์ฒด์ธ ๋คํธ์ํฌ ๋ถ์ ๋ฐ ํ์ ์ฐ๊ตฌ
โข DeFi ํ๋ก์ ํธ: ํ๋กํ ์ฝ ์ฌ์ฉ ํจํด ๋ถ์ ๋ฐ ์ต์ ํ
๐ ๏ธ ๊ฐ๋ฐ ํ๊ฒฝ ์ค๋นํ๊ธฐ
๋ณธ๊ฒฉ์ ์ผ๋ก ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฐํ๊ธฐ ์ ์ ํ์ํ ๋๊ตฌ๋ค์ ์ค๋นํด๋ณด์! ํ์ด์ฌ ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ์ ์๊ฐ๋ณด๋ค ๊ฐ๋จํด. ๐๐ฆ ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ค๋ฉด ๋ช ๊ฐ์ง ํต์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํด. ๊ฐ๊ฐ์ ์ญํ ์ ์์๋ณด์!
Web3.py - ๋ธ๋ก์ฒด์ธ๊ณผ์ ์ํต ์ฐฝ๊ตฌ
์ด๋๋ฆฌ์ ๋ธ๋ก์ฒด์ธ๊ณผ ์ํธ์์ฉํ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ํ์ด์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ. ๋ธ๋ก ์ ๋ณด ์กฐํ, ํธ๋์ญ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ, ์ค๋งํธ ์ปจํธ๋ํธ ํธ์ถ ๋ฑ ๊ฑฐ์ ๋ชจ๋ ์์ ์ด ๊ฐ๋ฅํด!
์ด๋๋ฆฌ์ ๋ธ๋ก์ฒด์ธ๊ณผ ์ํธ์์ฉํ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ํ์ด์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ. ๋ธ๋ก ์ ๋ณด ์กฐํ, ํธ๋์ญ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ, ์ค๋งํธ ์ปจํธ๋ํธ ํธ์ถ ๋ฑ ๊ฑฐ์ ๋ชจ๋ ์์ ์ด ๊ฐ๋ฅํด!
๐ป ์ค์น ๋ช
๋ น์ด
pip install web3
Pandas - ๋ฐ์ดํฐ ๋ถ์์ ํต์ฌ
์์งํ ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ๋ฅผ ํ ํํ๋ก ์ ๋ฆฌํ๊ณ ๋ถ์ํ๋ ๋ฐ ์ต๊ณ ์ ๋๊ตฌ์ผ. ์์ ์ฒ๋ผ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์์ด์ ์ ๋ง ํธ๋ฆฌํด! ๐
์์งํ ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ๋ฅผ ํ ํํ๋ก ์ ๋ฆฌํ๊ณ ๋ถ์ํ๋ ๋ฐ ์ต๊ณ ์ ๋๊ตฌ์ผ. ์์ ์ฒ๋ผ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์์ด์ ์ ๋ง ํธ๋ฆฌํด! ๐
๐ป ์ค์น ๋ช
๋ น์ด
pip install pandas numpy
Requests - API ํต์ ์ ๊ธฐ๋ณธ
Etherscan, Infura ๊ฐ์ ๋ธ๋ก์ฒด์ธ API ์๋น์ค์ ํต์ ํ ๋ ํ์์ ์ด์ผ. HTTP ์์ฒญ์ ๊ฐ๋จํ๊ฒ ๋ณด๋ผ ์ ์์ด!
Etherscan, Infura ๊ฐ์ ๋ธ๋ก์ฒด์ธ API ์๋น์ค์ ํต์ ํ ๋ ํ์์ ์ด์ผ. HTTP ์์ฒญ์ ๊ฐ๋จํ๊ฒ ๋ณด๋ผ ์ ์์ด!
๐ป ์ค์น ๋ช
๋ น์ด
pip install requests
๐ API ํค ๋ฐ๊ธ๋ฐ๊ธฐ
๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ค๋ฉด API ํค๊ฐ ํ์ํด. ๋ฌด๋ฃ๋ก ๋ฐ๊ธ๋ฐ์ ์ ์์ผ๋ ๊ฑฑ์ ๋ง! ๐
Step 1: Infura ๊ฐ์
Infura(infura.io)์ ์ ์ํด์ ๋ฌด๋ฃ ๊ณ์ ์ ๋ง๋ค์ด. ์ด๋๋ฆฌ์ ๋ ธ๋์ ์ง์ ์ฐ๊ฒฐํ์ง ์๊ณ ๋ ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ์๋น์ค์ผ!
Infura(infura.io)์ ์ ์ํด์ ๋ฌด๋ฃ ๊ณ์ ์ ๋ง๋ค์ด. ์ด๋๋ฆฌ์ ๋ ธ๋์ ์ง์ ์ฐ๊ฒฐํ์ง ์๊ณ ๋ ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ์๋น์ค์ผ!
Step 2: ํ๋ก์ ํธ ์์ฑ
๋์๋ณด๋์์ ์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๋ฉด ๊ณ ์ ํ Project ID๋ฅผ ๋ฐ๊ฒ ๋ผ. ์ด๊ฒ ๋ฐ๋ก ๋์ API ํค์ผ! ๐
๋์๋ณด๋์์ ์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๋ฉด ๊ณ ์ ํ Project ID๋ฅผ ๋ฐ๊ฒ ๋ผ. ์ด๊ฒ ๋ฐ๋ก ๋์ API ํค์ผ! ๐
Step 3: Etherscan API ํค ๋ฐ๊ธ
Etherscan(etherscan.io)์์๋ ๋ฌด๋ฃ API ํค๋ฅผ ๋ฐ๊ธ๋ฐ์. ๋ ์์ธํ ๊ฑฐ๋ ์ ๋ณด์ ์ค๋งํธ ์ปจํธ๋ํธ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ด!
Etherscan(etherscan.io)์์๋ ๋ฌด๋ฃ API ํค๋ฅผ ๋ฐ๊ธ๋ฐ์. ๋ ์์ธํ ๊ฑฐ๋ ์ ๋ณด์ ์ค๋งํธ ์ปจํธ๋ํธ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ด!
โ ๏ธ ๋ณด์ ์ฃผ์์ฌํญ
API ํค๋ ์ ๋ ์ฝ๋์ ์ง์ ํ๋์ฝ๋ฉํ์ง ๋ง! ํ๊ฒฝ๋ณ์๋ ๋ณ๋์ ์ค์ ํ์ผ์ ์ ์ฅํ๊ณ .gitignore์ ์ถ๊ฐํด์ GitHub์ ์ฌ๋ผ๊ฐ์ง ์๋๋ก ํด์ผ ํด. ํค๊ฐ ๋ ธ์ถ๋๋ฉด ์ ์ฉ๋ ์ ์๊ฑฐ๋ ! ๐
API ํค๋ ์ ๋ ์ฝ๋์ ์ง์ ํ๋์ฝ๋ฉํ์ง ๋ง! ํ๊ฒฝ๋ณ์๋ ๋ณ๋์ ์ค์ ํ์ผ์ ์ ์ฅํ๊ณ .gitignore์ ์ถ๊ฐํด์ GitHub์ ์ฌ๋ผ๊ฐ์ง ์๋๋ก ํด์ผ ํด. ํค๊ฐ ๋ ธ์ถ๋๋ฉด ์ ์ฉ๋ ์ ์๊ฑฐ๋ ! ๐
๐ ๊ธฐ๋ณธ ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ ์์ง ํ๋ก๊ทธ๋จ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ฝ๋ฉ์ ์์ํด๋ณผ๊น? ๋จผ์ ๊ฐ๋จํ ๋ธ๋ก ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํ๋ก๊ทธ๋จ๋ถํฐ ๋ง๋ค์ด๋ณด์! ๐จ๐ก Web3 ์ฐ๊ฒฐ ์ค์
๊ฐ์ฅ ๋จผ์ ํด์ผ ํ ์ผ์ ์ด๋๋ฆฌ์ ๋คํธ์ํฌ์ ์ฐ๊ฒฐํ๋ ๊ฑฐ์ผ. Infura๋ฅผ ํตํด ์ฐ๊ฒฐํ๋ฉด ๋ณ๋์ ๋ ธ๋ ์ด์ ์์ด๋ ๋ธ๋ก์ฒด์ธ์ ์ ๊ทผํ ์ ์์ด!๐ Python ์ฝ๋ - Web3 ์ด๊ธฐํ
from web3 import Web3
import json
# Infura ์๋ํฌ์ธํธ ์ค์
INFURA_URL = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
# Web3 ์ธ์คํด์ค ์์ฑ
w3 = Web3(Web3.HTTPProvider(INFURA_URL))
# ์ฐ๊ฒฐ ํ์ธ
if w3.is_connected():
print("โ
์ด๋๋ฆฌ์ ๋ฉ์ธ๋ท์ ์ฑ๊ณต์ ์ผ๋ก ์ฐ๊ฒฐ๋์์ต๋๋ค!")
print(f"ํ์ฌ ๋ธ๋ก ๋์ด: {w3.eth.block_number}")
else:
print("โ ์ฐ๊ฒฐ ์คํจ! API ํค๋ฅผ ํ์ธํด์ฃผ์ธ์.")
๐ก Pro Tip
is_connected() ๋ฉ์๋๋ก ์ฐ๊ฒฐ ์ํ๋ฅผ ํญ์ ํ์ธํ๋ ์ต๊ด์ ๋ค์ด์! ๋คํธ์ํฌ ๋ฌธ์ ๋ API ํค ์ค๋ฅ๋ฅผ ๋ฏธ๋ฆฌ ์ก์ ์ ์์ด. ์ค์ ์๋น์ค์์๋ ์ฌ์ฐ๊ฒฐ ๋ก์ง๋ ๊ตฌํํ๋ ๊ฒ ์ข์! ๐
is_connected() ๋ฉ์๋๋ก ์ฐ๊ฒฐ ์ํ๋ฅผ ํญ์ ํ์ธํ๋ ์ต๊ด์ ๋ค์ด์! ๋คํธ์ํฌ ๋ฌธ์ ๋ API ํค ์ค๋ฅ๋ฅผ ๋ฏธ๋ฆฌ ์ก์ ์ ์์ด. ์ค์ ์๋น์ค์์๋ ์ฌ์ฐ๊ฒฐ ๋ก์ง๋ ๊ตฌํํ๋ ๊ฒ ์ข์! ๐
๐ ๋ธ๋ก ์ ๋ณด ์กฐํํ๊ธฐ
์ด์ ์ค์ ๋ธ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์๋ณด์! ๊ฐ ๋ธ๋ก์๋ ์์ฒญ๋๊ฒ ๋ง์ ์ ๋ณด๊ฐ ๋ด๊ฒจ์์ด. ๋ธ๋ก ํด์, ํ์์คํฌํ, ๊ฑฐ๋ ๊ฐ์, ์ฑ๊ตด์ ์ฃผ์ ๋ฑ๋ฑ... ๐ฏ๐ Python ์ฝ๋ - ๋ธ๋ก ๋ฐ์ดํฐ ์์ง
def get_block_info(block_number):
"""
ํน์ ๋ธ๋ก์ ์์ธ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
"""
try:
# ๋ธ๋ก ์ ๋ณด ์กฐํ
block = w3.eth.get_block(block_number, full_transactions=True)
block_info = {
'block_number': block['number'],
'timestamp': block['timestamp'],
'hash': block['hash'].hex(),
'parent_hash': block['parentHash'].hex(),
'miner': block['miner'],
'difficulty': block['difficulty'],
'total_difficulty': block['totalDifficulty'],
'size': block['size'],
'gas_used': block['gasUsed'],
'gas_limit': block['gasLimit'],
'transaction_count': len(block['transactions'])
}
return block_info
except Exception as e:
print(f"โ ๋ธ๋ก ์ ๋ณด ์กฐํ ์คํจ: {e}")
return None
# ์ต์ ๋ธ๋ก ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
latest_block = w3.eth.block_number
block_data = get_block_info(latest_block)
if block_data:
print(f"\n๐ฆ ๋ธ๋ก #{block_data['block_number']} ์ ๋ณด")
print(f"โฐ ์์ฑ ์๊ฐ: {block_data['timestamp']}")
print(f"๐ท ์ฑ๊ตด์: {block_data['miner']}")
print(f"๐ผ ๊ฑฐ๋ ๊ฐ์: {block_data['transaction_count']}")
print(f"โฝ ์ฌ์ฉ๋ ๊ฐ์ค: {block_data['gas_used']:,}")
๐ ์ฝ๋ ํด์ค
full_transactions=True ํ๋ผ๋ฏธํฐ๊ฐ ํต์ฌ์ด์ผ! ์ด๊ฑธ True๋ก ์ค์ ํ๋ฉด ๋ธ๋ก ์์ ๋ชจ๋ ๊ฑฐ๋ ์ ๋ณด๋ฅผ ์์ธํ๊ฒ ๊ฐ์ ธ์ฌ ์ ์์ด. False๋ก ํ๋ฉด ๊ฑฐ๋ ํด์๋ง ๋ฐ๊ฒ ๋ผ. ๋ฐ์ดํฐ ์์ด ๋ง์ผ๋๊น ํ์์ ๋ฐ๋ผ ์ ํํ๋ฉด ๋ผ! ๐
full_transactions=True ํ๋ผ๋ฏธํฐ๊ฐ ํต์ฌ์ด์ผ! ์ด๊ฑธ True๋ก ์ค์ ํ๋ฉด ๋ธ๋ก ์์ ๋ชจ๋ ๊ฑฐ๋ ์ ๋ณด๋ฅผ ์์ธํ๊ฒ ๊ฐ์ ธ์ฌ ์ ์์ด. False๋ก ํ๋ฉด ๊ฑฐ๋ ํด์๋ง ๋ฐ๊ฒ ๋ผ. ๋ฐ์ดํฐ ์์ด ๋ง์ผ๋๊น ํ์์ ๋ฐ๋ผ ์ ํํ๋ฉด ๋ผ! ๐
๐ธ ๊ฑฐ๋ ๋ด์ญ ์์ธ ๋ถ์
๋ธ๋ก ์ ๋ณด๋ ์ข์ง๋ง, ์ง์ง ์ค์ํ ๊ฑด ๊ฑฐ๋ ๋ด์ญ์ด์ง! ๋๊ฐ ๋๊ตฌ์๊ฒ ์ผ๋ง๋ฅผ ๋ณด๋๋์ง, ์์๋ฃ๋ ์ผ๋ง๋ ๋๋์ง ๋ฑ์ ๋ถ์ํด๋ณด์. ๐ฐ๐ Python ์ฝ๋ - ๊ฑฐ๋ ๋ด์ญ ๋ถ์
def analyze_transactions(block_number):
"""
๋ธ๋ก ๋ด ๋ชจ๋ ๊ฑฐ๋๋ฅผ ๋ถ์ํ๋ ํจ์
"""
block = w3.eth.get_block(block_number, full_transactions=True)
transactions = []
for tx in block['transactions']:
# Wei๋ฅผ Ether๋ก ๋ณํ
value_in_ether = w3.from_wei(tx['value'], 'ether')
# ๊ฐ์ค๋น ๊ณ์ฐ
gas_price = w3.from_wei(tx['gasPrice'], 'gwei')
tx_data = {
'hash': tx['hash'].hex(),
'from': tx['from'],
'to': tx['to'] if tx['to'] else 'Contract Creation',
'value': float(value_in_ether),
'gas': tx['gas'],
'gas_price': float(gas_price),
'nonce': tx['nonce'],
'transaction_index': tx['transactionIndex']
}
transactions.append(tx_data)
return transactions
# ๊ฑฐ๋ ๋ถ์ ์คํ
latest_block = w3.eth.block_number
transactions = analyze_transactions(latest_block)
print(f"\n๐ผ ๋ธ๋ก #{latest_block}์ ๊ฑฐ๋ ๋ถ์")
print(f"์ด ๊ฑฐ๋ ์: {len(transactions)}")
# ๊ฑฐ๋๋ ํต๊ณ
total_value = sum(tx['value'] for tx in transactions)
avg_gas_price = sum(tx['gas_price'] for tx in transactions) / len(transactions) if transactions else 0
print(f"๐ฐ ์ด ๊ฑฐ๋๋: {total_value:.4f} ETH")
print(f"โฝ ํ๊ท ๊ฐ์ค ๊ฐ๊ฒฉ: {avg_gas_price:.2f} Gwei")
# ์์ 5๊ฐ ๊ฑฐ๋ ์ถ๋ ฅ
print("\n๐ ์์ 5๊ฐ ๊ฑฐ๋:")
sorted_txs = sorted(transactions, key=lambda x: x['value'], reverse=True)[:5]
for i, tx in enumerate(sorted_txs, 1):
print(f"{i}. {tx['value']:.4f} ETH - {tx['hash'][:10]}...")
๐ก ๋จ์ ๋ณํ ๊ฟํ
์ด๋๋ฆฌ์์์๋ Wei๋ผ๋ ๊ฐ์ฅ ์์ ๋จ์๋ฅผ ์ฌ์ฉํด. 1 ETH = 10^18 Wei์ผ! ๊ทธ๋์ w3.from_wei() ํจ์๋ก ๋ณํํด์ค์ผ ์ฌ๋์ด ์ฝ๊ธฐ ํธํ ์ซ์๊ฐ ๋ผ. ๊ฐ์ค ๊ฐ๊ฒฉ์ ๋ณดํต Gwei(10^9 Wei) ๋จ์๋ก ํ์ํ๊ณ ! ๐ข
์ด๋๋ฆฌ์์์๋ Wei๋ผ๋ ๊ฐ์ฅ ์์ ๋จ์๋ฅผ ์ฌ์ฉํด. 1 ETH = 10^18 Wei์ผ! ๊ทธ๋์ w3.from_wei() ํจ์๋ก ๋ณํํด์ค์ผ ์ฌ๋์ด ์ฝ๊ธฐ ํธํ ์ซ์๊ฐ ๋ผ. ๊ฐ์ค ๊ฐ๊ฒฉ์ ๋ณดํต Gwei(10^9 Wei) ๋จ์๋ก ํ์ํ๊ณ ! ๐ข
๐ Pandas๋ฅผ ํ์ฉํ ๋ฐ์ดํฐ ๋ถ์
์ด์ ์์งํ ๋ฐ์ดํฐ๋ฅผ Pandas๋ก ์ ๋ฆฌํ๊ณ ๋ถ์ํด๋ณด์! ํ ํํ๋ก ์ ๋ฆฌํ๋ฉด ํจ์ฌ ๋ณด๊ธฐ ์ข๊ณ ๋ถ์ํ๊ธฐ๋ ์ฌ์์ ธ. ๐ฏ๐ DataFrame์ผ๋ก ๋ฐ์ดํฐ ์ ๋ฆฌ
๐ Python ์ฝ๋ - Pandas ๋ฐ์ดํฐ ๋ถ์
import pandas as pd
from datetime import datetime
def create_transaction_dataframe(start_block, end_block):
"""
์ฌ๋ฌ ๋ธ๋ก์ ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ DataFrame์ผ๋ก ์์ฑ
"""
all_transactions = []
print(f"๐ฅ ๋ธ๋ก {start_block}๋ถํฐ {end_block}๊น์ง ๋ฐ์ดํฐ ์์ง ์ค...")
for block_num in range(start_block, end_block + 1):
try:
block = w3.eth.get_block(block_num, full_transactions=True)
block_timestamp = datetime.fromtimestamp(block['timestamp'])
for tx in block['transactions']:
tx_data = {
'block_number': block_num,
'timestamp': block_timestamp,
'tx_hash': tx['hash'].hex(),
'from_address': tx['from'],
'to_address': tx['to'] if tx['to'] else 'Contract',
'value_eth': float(w3.from_wei(tx['value'], 'ether')),
'gas_price_gwei': float(w3.from_wei(tx['gasPrice'], 'gwei')),
'gas_used': tx['gas'],
'tx_fee_eth': float(w3.from_wei(tx['gas'] * tx['gasPrice'], 'ether'))
}
all_transactions.append(tx_data)
if block_num % 10 == 0:
print(f"โ
๋ธ๋ก {block_num} ์ฒ๋ฆฌ ์๋ฃ")
except Exception as e:
print(f"โ ๋ธ๋ก {block_num} ์ฒ๋ฆฌ ์คํจ: {e}")
continue
df = pd.DataFrame(all_transactions)
return df
# ์ต๊ทผ 50๊ฐ ๋ธ๋ก ๋ถ์
latest = w3.eth.block_number
df_transactions = create_transaction_dataframe(latest - 50, latest)
print(f"\n๐ ์์ง๋ ๋ฐ์ดํฐ: {len(df_transactions)} ๊ฑด")
print("\n๋ฐ์ดํฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ:")
print(df_transactions.head())
๐ฌ ํต๊ณ ๋ถ์ ๋ฐ ์ธ์ฌ์ดํธ ๋์ถ
DataFrame์ด ์ค๋น๋์ผ๋ฉด ์ด์ ๋ณธ๊ฒฉ์ ์ธ ๋ถ์ ์๊ฐ! ๋ค์ํ ํต๊ณ๋ฅผ ๋ฝ์๋ด๊ณ ์๋ฏธ์๋ ํจํด์ ์ฐพ์๋ณด์. ๐๐ Python ์ฝ๋ - ํต๊ณ ๋ถ์
# ๊ธฐ๋ณธ ํต๊ณ ์ ๋ณด
print("\n๐ ๊ฑฐ๋ ๊ธ์ก ํต๊ณ")
print(df_transactions['value_eth'].describe())
print("\nโฝ ๊ฐ์ค ๊ฐ๊ฒฉ ํต๊ณ")
print(df_transactions['gas_price_gwei'].describe())
# ์๊ฐ๋๋ณ ๊ฑฐ๋๋ ๋ถ์
df_transactions['hour'] = df_transactions['timestamp'].dt.hour
hourly_stats = df_transactions.groupby('hour').agg({
'value_eth': ['sum', 'mean', 'count'],
'gas_price_gwei': 'mean'
}).round(4)
print("\nโฐ ์๊ฐ๋๋ณ ๊ฑฐ๋ ํจํด")
print(hourly_stats)
# ๊ณ ์ก ๊ฑฐ๋ ํํฐ๋ง
high_value_txs = df_transactions[df_transactions['value_eth'] > 10]
print(f"\n๐ 10 ETH ์ด์ ๊ณ ์ก ๊ฑฐ๋: {len(high_value_txs)}๊ฑด")
print(high_value_txs[['tx_hash', 'value_eth', 'from_address', 'to_address']].head())
# ๊ฐ์ฅ ํ๋ฐํ ์ฃผ์ ์ฐพ๊ธฐ
top_senders = df_transactions['from_address'].value_counts().head(10)
print("\n๐ฅ ๊ฐ์ฅ ํ๋ฐํ ์ก์ ์ฃผ์ TOP 10")
for i, (address, count) in enumerate(top_senders.items(), 1):
print(f"{i}. {address}: {count}๊ฑด")
# ์ปจํธ๋ํธ ์์ฑ ๊ฑฐ๋ ๋ถ์
contract_creations = df_transactions[df_transactions['to_address'] == 'Contract']
print(f"\n๐๏ธ ์ค๋งํธ ์ปจํธ๋ํธ ์์ฑ: {len(contract_creations)}๊ฑด")
๐ฏ ๋ถ์ ํฌ์ธํธ
โข ์๊ฐ๋๋ณ ํจํด: ํน์ ์๊ฐ๋์ ๊ฑฐ๋๊ฐ ๋ชฐ๋ฆฌ๋์ง ํ์ธ
โข ๊ณ ์ก ๊ฑฐ๋: ๊ณ ๋(๋๋ ๋ณด์ ์)์ ์์ง์ ์ถ์
โข ํ๋ฐํ ์ฃผ์: ๊ฑฐ๋์๋ ์ฃผ์ ์๋น์ค ์ฃผ์ ํ์
โข ๊ฐ์ค ๊ฐ๊ฒฉ ๋ณ๋: ๋คํธ์ํฌ ํผ์ก๋ ์ธก์
โข ์ปจํธ๋ํธ ์์ฑ: ์๋ก์ด ํ๋ก์ ํธ ๋ฐ์นญ ๋ชจ๋ํฐ๋ง
โข ์๊ฐ๋๋ณ ํจํด: ํน์ ์๊ฐ๋์ ๊ฑฐ๋๊ฐ ๋ชฐ๋ฆฌ๋์ง ํ์ธ
โข ๊ณ ์ก ๊ฑฐ๋: ๊ณ ๋(๋๋ ๋ณด์ ์)์ ์์ง์ ์ถ์
โข ํ๋ฐํ ์ฃผ์: ๊ฑฐ๋์๋ ์ฃผ์ ์๋น์ค ์ฃผ์ ํ์
โข ๊ฐ์ค ๊ฐ๊ฒฉ ๋ณ๋: ๋คํธ์ํฌ ํผ์ก๋ ์ธก์
โข ์ปจํธ๋ํธ ์์ฑ: ์๋ก์ด ํ๋ก์ ํธ ๋ฐ์นญ ๋ชจ๋ํฐ๋ง
๐จ ๋ฐ์ดํฐ ์๊ฐํ
์ซ์๋ง ๋ณด๋ฉด ์ง๋ฃจํ์์? ๊ทธ๋ํ๋ก ์๊ฐํํ๋ฉด ํจํด์ด ํ๋์ ๋ณด์ฌ! Matplotlib๊ณผ Seaborn์ ํ์ฉํด๋ณด์. ๐๐ Python ์ฝ๋ - ๋ฐ์ดํฐ ์๊ฐํ
import matplotlib.pyplot as plt
import seaborn as sns
# ํ๊ธ ํฐํธ ์ค์ (์ ํ์ฌํญ)
plt.rcParams['font.family'] = 'DejaVu Sans'
plt.rcParams['axes.unicode_minus'] = False
# ์คํ์ผ ์ค์
sns.set_style("whitegrid")
plt.figure(figsize=(15, 10))
# 1. ์๊ฐ๋๋ณ ๊ฑฐ๋๋ ์ถ์ด
plt.subplot(2, 2, 1)
hourly_volume = df_transactions.groupby('hour')['value_eth'].sum()
plt.plot(hourly_volume.index, hourly_volume.values, marker='o', linewidth=2, color='#667eea')
plt.title('์๊ฐ๋๋ณ ์ด ๊ฑฐ๋๋', fontsize=14, fontweight='bold')
plt.xlabel('์๊ฐ (Hour)')
plt.ylabel('๊ฑฐ๋๋ (ETH)')
plt.grid(True, alpha=0.3)
# 2. ๊ฐ์ค ๊ฐ๊ฒฉ ๋ถํฌ
plt.subplot(2, 2, 2)
plt.hist(df_transactions['gas_price_gwei'], bins=50, color='#764ba2', alpha=0.7, edgecolor='black')
plt.title('๊ฐ์ค ๊ฐ๊ฒฉ ๋ถํฌ', fontsize=14, fontweight='bold')
plt.xlabel('๊ฐ์ค ๊ฐ๊ฒฉ (Gwei)')
plt.ylabel('๋น๋')
plt.grid(True, alpha=0.3)
# 3. ๊ฑฐ๋ ๊ธ์ก ๋ถํฌ (๋ก๊ทธ ์ค์ผ์ผ)
plt.subplot(2, 2, 3)
value_data = df_transactions[df_transactions['value_eth'] > 0]['value_eth']
plt.hist(value_data, bins=50, color='#22c55e', alpha=0.7, edgecolor='black')
plt.yscale('log')
plt.title('๊ฑฐ๋ ๊ธ์ก ๋ถํฌ (๋ก๊ทธ ์ค์ผ์ผ)', fontsize=14, fontweight='bold')
plt.xlabel('๊ฑฐ๋ ๊ธ์ก (ETH)')
plt.ylabel('๋น๋ (๋ก๊ทธ)')
plt.grid(True, alpha=0.3)
# 4. ๋ธ๋ก๋ณ ๊ฑฐ๋ ์
plt.subplot(2, 2, 4)
block_tx_count = df_transactions.groupby('block_number').size()
plt.bar(block_tx_count.index, block_tx_count.values, color='#f59e0b', alpha=0.7)
plt.title('๋ธ๋ก๋ณ ๊ฑฐ๋ ์', fontsize=14, fontweight='bold')
plt.xlabel('๋ธ๋ก ๋ฒํธ')
plt.ylabel('๊ฑฐ๋ ์')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('blockchain_analysis.png', dpi=300, bbox_inches='tight')
print("\n๐ ๊ทธ๋ํ๊ฐ 'blockchain_analysis.png'๋ก ์ ์ฅ๋์์ต๋๋ค!")
๐ก ์๊ฐํ ํ
๊ฑฐ๋ ๊ธ์ก์ ํธ์ฐจ๊ฐ ํฌ๊ธฐ ๋๋ฌธ์ ๋ก๊ทธ ์ค์ผ์ผ์ ์ฌ์ฉํ๋ ๊ฒ ์ข์! 0.001 ETH๋ถํฐ 1000 ETH๊น์ง ๋ค์ํ ๊ฑฐ๋๊ฐ ์์ฌ์๊ฑฐ๋ . ๋ก๊ทธ ์ค์ผ์ผ์ ์ฐ๋ฉด ์ ์ฒด ๋ถํฌ๋ฅผ ํ๋์ ๋ณผ ์ ์์ด! ๐
๊ฑฐ๋ ๊ธ์ก์ ํธ์ฐจ๊ฐ ํฌ๊ธฐ ๋๋ฌธ์ ๋ก๊ทธ ์ค์ผ์ผ์ ์ฌ์ฉํ๋ ๊ฒ ์ข์! 0.001 ETH๋ถํฐ 1000 ETH๊น์ง ๋ค์ํ ๊ฑฐ๋๊ฐ ์์ฌ์๊ฑฐ๋ . ๋ก๊ทธ ์ค์ผ์ผ์ ์ฐ๋ฉด ์ ์ฒด ๋ถํฌ๋ฅผ ํ๋์ ๋ณผ ์ ์์ด! ๐
๐ค ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ์์คํ ๊ตฌ์ถ
์ง๊ธ๊น์ง๋ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๋ค๋ฉด, ์ด์ ๋ ์ค์๊ฐ์ผ๋ก ์๋ก์ด ๋ธ๋ก๊ณผ ๊ฑฐ๋๋ฅผ ๋ชจ๋ํฐ๋งํ๋ ์์คํ ์ ๋ง๋ค์ด๋ณด์! ๐จโก ์ค์๊ฐ ๋ธ๋ก ๊ฐ์
๐ Python ์ฝ๋ - ์ค์๊ฐ ๋ชจ๋ํฐ๋ง
import time
from datetime import datetime
class BlockchainMonitor:
def __init__(self, w3_instance):
self.w3 = w3_instance
self.last_block = self.w3.eth.block_number
self.alert_threshold = 100 # ETH ๋จ์
def check_new_blocks(self):
"""
์๋ก์ด ๋ธ๋ก์ ํ์ธํ๊ณ ๋ถ์
"""
current_block = self.w3.eth.block_number
if current_block > self.last_block:
print(f"\n๐ ์๋ก์ด ๋ธ๋ก ๋ฐ๊ฒฌ: #{current_block}")
# ์๋ก์ด ๋ธ๋ก๋ค ์ฒ๋ฆฌ
for block_num in range(self.last_block + 1, current_block + 1):
self.analyze_block(block_num)
self.last_block = current_block
def analyze_block(self, block_number):
"""
๋ธ๋ก ๋ถ์ ๋ฐ ์๋ฆผ
"""
try:
block = self.w3.eth.get_block(block_number, full_transactions=True)
timestamp = datetime.fromtimestamp(block['timestamp'])
print(f"\n๐ฆ ๋ธ๋ก #{block_number}")
print(f"โฐ ์๊ฐ: {timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"๐ผ ๊ฑฐ๋ ์: {len(block['transactions'])}")
# ๊ณ ์ก ๊ฑฐ๋ ๊ฐ์ง
for tx in block['transactions']:
value_eth = float(self.w3.from_wei(tx['value'], 'ether'))
if value_eth >= self.alert_threshold:
print(f"\n๐จ ๊ณ ์ก ๊ฑฐ๋ ๊ฐ์ง!")
print(f" ๊ธ์ก: {value_eth:.2f} ETH")
print(f" From: {tx['from']}")
print(f" To: {tx['to'] if tx['to'] else 'Contract Creation'}")
print(f" Hash: {tx['hash'].hex()}")
# ์ฌ๊ธฐ์ ์๋ฆผ ๋ก์ง ์ถ๊ฐ (์ด๋ฉ์ผ, ํ
๋ ๊ทธ๋จ ๋ฑ)
self.send_alert(tx, value_eth)
except Exception as e:
print(f"โ ๋ธ๋ก ๋ถ์ ์คํจ: {e}")
def send_alert(self, transaction, value):
"""
์๋ฆผ ์ ์ก (์์)
"""
# ์ค์ ๋ก๋ ์ด๋ฉ์ผ, SMS, ํ
๋ ๊ทธ๋จ ๋ฑ์ผ๋ก ์๋ฆผ ์ ์ก
alert_message = f"๊ณ ์ก ๊ฑฐ๋ ๊ฐ์ง: {value:.2f} ETH"
print(f"๐ง ์๋ฆผ ์ ์ก: {alert_message}")
def run(self, interval=12):
"""
๋ชจ๋ํฐ๋ง ์คํ (interval: ํ์ธ ์ฃผ๊ธฐ, ์ด ๋จ์)
"""
print("๐ ๋ธ๋ก์ฒด์ธ ๋ชจ๋ํฐ๋ง ์์...")
print(f"ํ์ฌ ๋ธ๋ก: #{self.last_block}")
print(f"์๋ฆผ ์๊ณ๊ฐ: {self.alert_threshold} ETH")
try:
while True:
self.check_new_blocks()
time.sleep(interval)
except KeyboardInterrupt:
print("\nโน๏ธ ๋ชจ๋ํฐ๋ง ์ข
๋ฃ")
# ๋ชจ๋ํฐ๋ง ์์
monitor = BlockchainMonitor(w3)
monitor.alert_threshold = 50 # 50 ETH ์ด์ ๊ฑฐ๋ ์๋ฆผ
# ์คํ (Ctrl+C๋ก ์ข
๋ฃ)
# monitor.run(interval=15) # 15์ด๋ง๋ค ํ์ธ
โ ๏ธ ์คํ ์ ์ฃผ์์ฌํญ
์ค์๊ฐ ๋ชจ๋ํฐ๋ง์ API ํธ์ถ์ ๊ณ์ํ๊ธฐ ๋๋ฌธ์ ๋ฌด๋ฃ ํ๋์ ์์ฒญ ์ ํ์ ๊ฑธ๋ฆด ์ ์์ด! Infura ๋ฌด๋ฃ ํ๋์ ํ๋ฃจ 100,000 ์์ฒญ๊น์ง ๊ฐ๋ฅํด. interval์ ๋๋ฌด ์งง๊ฒ ์ค์ ํ์ง ๋ง๊ณ , ํ์ํ ๊ฒฝ์ฐ ์ ๋ฃ ํ๋์ ๊ณ ๋ คํด๋ด! ๐ธ
์ค์๊ฐ ๋ชจ๋ํฐ๋ง์ API ํธ์ถ์ ๊ณ์ํ๊ธฐ ๋๋ฌธ์ ๋ฌด๋ฃ ํ๋์ ์์ฒญ ์ ํ์ ๊ฑธ๋ฆด ์ ์์ด! Infura ๋ฌด๋ฃ ํ๋์ ํ๋ฃจ 100,000 ์์ฒญ๊น์ง ๊ฐ๋ฅํด. interval์ ๋๋ฌด ์งง๊ฒ ์ค์ ํ์ง ๋ง๊ณ , ํ์ํ ๊ฒฝ์ฐ ์ ๋ฃ ํ๋์ ๊ณ ๋ คํด๋ด! ๐ธ
๐ฏ ํน์ ์ฃผ์ ์ถ์ ์์คํ
ํน์ ์ง๊ฐ ์ฃผ์์ ๋ชจ๋ ๊ฑฐ๋๋ฅผ ์ถ์ ํ๊ณ ์ถ์ ๋๊ฐ ์์ง? ๊ณ ๋ ์ง๊ฐ์ด๋ ๊ฑฐ๋์ ์ง๊ฐ์ ๋ชจ๋ํฐ๋งํ๋ฉด ์์ฅ ์์ง์์ ์์ธกํ ์ ์์ด! ๐๐ Python ์ฝ๋ - ์ฃผ์ ์ถ์
class AddressTracker:
def __init__(self, w3_instance, target_address):
self.w3 = w3_instance
self.target_address = w3_instance.to_checksum_address(target_address)
self.transaction_history = []
def get_balance(self):
"""
ํ์ฌ ์์ก ์กฐํ
"""
balance_wei = self.w3.eth.get_balance(self.target_address)
balance_eth = self.w3.from_wei(balance_wei, 'ether')
return float(balance_eth)
def scan_blocks(self, start_block, end_block):
"""
ํน์ ๋ธ๋ก ๋ฒ์์์ ํด๋น ์ฃผ์์ ๊ฑฐ๋ ์ฐพ๊ธฐ
"""
print(f"๐ ์ฃผ์ {self.target_address} ์ค์บ ์ค...")
found_transactions = []
for block_num in range(start_block, end_block + 1):
try:
block = self.w3.eth.get_block(block_num, full_transactions=True)
for tx in block['transactions']:
# ์ก์ ์ ๋๋ ์์ ์๊ฐ ํ๊ฒ ์ฃผ์์ธ ๊ฒฝ์ฐ
if tx['from'] == self.target_address or tx['to'] == self.target_address:
tx_data = {
'block': block_num,
'timestamp': datetime.fromtimestamp(block['timestamp']),
'hash': tx['hash'].hex(),
'from': tx['from'],
'to': tx['to'] if tx['to'] else 'Contract',
'value': float(self.w3.from_wei(tx['value'], 'ether')),
'type': 'OUT' if tx['from'] == self.target_address else 'IN'
}
found_transactions.append(tx_data)
print(f"โ
๊ฑฐ๋ ๋ฐ๊ฒฌ: ๋ธ๋ก #{block_num}")
if block_num % 100 == 0:
print(f"์งํ๋ฅ : ๋ธ๋ก {block_num}/{end_block}")
except Exception as e:
print(f"โ ๋ธ๋ก {block_num} ์ค์บ ์คํจ: {e}")
continue
self.transaction_history.extend(found_transactions)
return found_transactions
def analyze_activity(self):
"""
๊ฑฐ๋ ํ๋ ๋ถ์
"""
if not self.transaction_history:
print("๊ฑฐ๋ ๋ด์ญ์ด ์์ต๋๋ค.")
return
df = pd.DataFrame(self.transaction_history)
print(f"\n๐ {self.target_address} ํ๋ ๋ถ์")
print(f"์ด ๊ฑฐ๋ ์: {len(df)}")
# ์
์ถ๊ธ ํต๊ณ
incoming = df[df['type'] == 'IN']
outgoing = df[df['type'] == 'OUT']
print(f"\n๐ฐ ์
๊ธ ๊ฑฐ๋: {len(incoming)}๊ฑด")
print(f" ์ด ์
๊ธ์ก: {incoming['value'].sum():.4f} ETH")
print(f" ํ๊ท ์
๊ธ์ก: {incoming['value'].mean():.4f} ETH")
print(f"\n๐ธ ์ถ๊ธ ๊ฑฐ๋: {len(outgoing)}๊ฑด")
print(f" ์ด ์ถ๊ธ์ก: {outgoing['value'].sum():.4f} ETH")
print(f" ํ๊ท ์ถ๊ธ์ก: {outgoing['value'].mean():.4f} ETH")
print(f"\n๐ผ ํ์ฌ ์์ก: {self.get_balance():.4f} ETH")
# ๊ฑฐ๋ ์๋๋ฐฉ ๋ถ์
print(f"\n๐ค ์ฃผ์ ๊ฑฐ๋ ์๋๋ฐฉ TOP 5")
counterparties = []
for _, tx in df.iterrows():
if tx['type'] == 'IN':
counterparties.append(tx['from'])
else:
counterparties.append(tx['to'])
from collections import Counter
top_counterparties = Counter(counterparties).most_common(5)
for i, (address, count) in enumerate(top_counterparties, 1):
print(f"{i}. {address}: {count}๊ฑด")
return df
# ์ฌ์ฉ ์์
target_wallet = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" # ์์ ์ฃผ์
tracker = AddressTracker(w3, target_wallet)
# ์ต๊ทผ 1000๋ธ๋ก ์ค์บ
latest = w3.eth.block_number
transactions = tracker.scan_blocks(latest - 1000, latest)
# ๋ถ์ ๊ฒฐ๊ณผ ์ถ๋ ฅ
analysis_df = tracker.analyze_activity()
๐ฏ ํ์ฉ ์๋๋ฆฌ์ค
โข ๊ณ ๋ ์ถ์ : ๋๋ ๋ณด์ ์์ ๋งค์/๋งค๋ ํจํด ๋ถ์
โข ๊ฑฐ๋์ ๋ชจ๋ํฐ๋ง: ๊ฑฐ๋์ ์ ์ถ๊ธ ํ๋ฆ ํ์
โข ์ค๋งํธ ์ปจํธ๋ํธ ๋ถ์: DeFi ํ๋กํ ์ฝ ์ฌ์ฉ ํจํด ์ฐ๊ตฌ
โข ํฌํธํด๋ฆฌ์ค ๊ด๋ฆฌ: ์์ ์ ์ง๊ฐ ๊ฑฐ๋ ๋ด์ญ ์๋ ๊ธฐ๋ก
โข ์ธ๋ฌด ์๋ฃ: ์ํธํํ ๊ฑฐ๋ ๋ด์ญ ์ ๋ฆฌ
โข ๊ณ ๋ ์ถ์ : ๋๋ ๋ณด์ ์์ ๋งค์/๋งค๋ ํจํด ๋ถ์
โข ๊ฑฐ๋์ ๋ชจ๋ํฐ๋ง: ๊ฑฐ๋์ ์ ์ถ๊ธ ํ๋ฆ ํ์
โข ์ค๋งํธ ์ปจํธ๋ํธ ๋ถ์: DeFi ํ๋กํ ์ฝ ์ฌ์ฉ ํจํด ์ฐ๊ตฌ
โข ํฌํธํด๋ฆฌ์ค ๊ด๋ฆฌ: ์์ ์ ์ง๊ฐ ๊ฑฐ๋ ๋ด์ญ ์๋ ๊ธฐ๋ก
โข ์ธ๋ฌด ์๋ฃ: ์ํธํํ ๊ฑฐ๋ ๋ด์ญ ์ ๋ฆฌ
๐ ์ค๋งํธ ์ปจํธ๋ํธ ์ํธ์์ฉ ๋ถ์
์ด๋๋ฆฌ์์ ์ง์ง ๋งค๋ ฅ์ ์ค๋งํธ ์ปจํธ๋ํธ์์? ERC-20 ํ ํฐ, NFT, DeFi ํ๋กํ ์ฝ ๋ฑ ๋ชจ๋ ๊ฒ ์ค๋งํธ ์ปจํธ๋ํธ๋ก ๋์ํด. ์ด๊ฒ๋ค๊ณผ์ ์ํธ์์ฉ์ ๋ถ์ํด๋ณด์! ๐จ๐ช ERC-20 ํ ํฐ ์ ์ก ์ถ์
๐ Python ์ฝ๋ - ERC-20 ํ ํฐ ๋ถ์
from web3 import Web3
# ERC-20 ํ์ค ABI (Transfer ์ด๋ฒคํธ)
ERC20_ABI = [
{
"anonymous": False,
"inputs": [
{"indexed": True, "name": "from", "type": "address"},
{"indexed": True, "name": "to", "type": "address"},
{"indexed": False, "name": "value", "type": "uint256"}
],
"name": "Transfer",
"type": "event"
},
{
"constant": True,
"inputs": [],
"name": "name",
"outputs": [{"name": "", "type": "string"}],
"type": "function"
},
{
"constant": True,
"inputs": [],
"name": "symbol",
"outputs": [{"name": "", "type": "string"}],
"type": "function"
},
{
"constant": True,
"inputs": [],
"name": "decimals",
"outputs": [{"name": "", "type": "uint8"}],
"type": "function"
},
{
"constant": True,
"inputs": [{"name": "_owner", "type": "address"}],
"name": "balanceOf",
"outputs": [{"name": "balance", "type": "uint256"}],
"type": "function"
}
]
class TokenAnalyzer:
def __init__(self, w3_instance, token_address):
self.w3 = w3_instance
self.token_address = w3_instance.to_checksum_address(token_address)
self.contract = w3_instance.eth.contract(
address=self.token_address,
abi=ERC20_ABI
)
def get_token_info(self):
"""
ํ ํฐ ๊ธฐ๋ณธ ์ ๋ณด ์กฐํ
"""
try:
name = self.contract.functions.name().call()
symbol = self.contract.functions.symbol().call()
decimals = self.contract.functions.decimals().call()
return {
'name': name,
'symbol': symbol,
'decimals': decimals,
'address': self.token_address
}
except Exception as e:
print(f"โ ํ ํฐ ์ ๋ณด ์กฐํ ์คํจ: {e}")
return None
def get_balance(self, address):
"""
ํน์ ์ฃผ์์ ํ ํฐ ์์ก ์กฐํ
"""
try:
address = self.w3.to_checksum_address(address)
balance = self.contract.functions.balanceOf(address).call()
decimals = self.contract.functions.decimals().call()
# ์ค์ ์์ก์ผ๋ก ๋ณํ
actual_balance = balance / (10 ** decimals)
return actual_balance
except Exception as e:
print(f"โ ์์ก ์กฐํ ์คํจ: {e}")
return 0
def get_transfer_events(self, from_block, to_block):
"""
Transfer ์ด๋ฒคํธ ์กฐํ
"""
try:
# Transfer ์ด๋ฒคํธ ํํฐ ์์ฑ
event_filter = self.contract.events.Transfer.create_filter(
fromBlock=from_block,
toBlock=to_block
)
events = event_filter.get_all_entries()
transfers = []
decimals = self.contract.functions.decimals().call()
for event in events:
transfer_data = {
'block': event['blockNumber'],
'tx_hash': event['transactionHash'].hex(),
'from': event['args']['from'],
'to': event['args']['to'],
'value': event['args']['value'] / (10 ** decimals)
}
transfers.append(transfer_data)
return transfers
except Exception as e:
print(f"โ ์ด๋ฒคํธ ์กฐํ ์คํจ: {e}")
return []
def analyze_transfers(self, from_block, to_block):
"""
ํ ํฐ ์ ์ก ๋ถ์
"""
token_info = self.get_token_info()
if not token_info:
return
print(f"\n๐ช ํ ํฐ ๋ถ์: {token_info['name']} ({token_info['symbol']})")
print(f"๐ ์ปจํธ๋ํธ ์ฃผ์: {token_info['address']}")
transfers = self.get_transfer_events(from_block, to_block)
if not transfers:
print("์ ์ก ๋ด์ญ์ด ์์ต๋๋ค.")
return
df = pd.DataFrame(transfers)
print(f"\n๐ ์ ์ก ํต๊ณ (๋ธ๋ก {from_block} ~ {to_block})")
print(f"์ด ์ ์ก ํ์: {len(df)}")
print(f"์ด ์ ์ก๋: {df['value'].sum():,.2f} {token_info['symbol']}")
print(f"ํ๊ท ์ ์ก๋: {df['value'].mean():,.2f} {token_info['symbol']}")
print(f"์ต๋ ์ ์ก๋: {df['value'].max():,.2f} {token_info['symbol']}")
# ์์ ์ก์ ์
print(f"\n๐ค ์์ ์ก์ ์ TOP 5")
top_senders = df['from'].value_counts().head(5)
for i, (address, count) in enumerate(top_senders.items(), 1):
total_sent = df[df['from'] == address]['value'].sum()
print(f"{i}. {address[:10]}...: {count}๊ฑด, {total_sent:,.2f} {token_info['symbol']}")
# ์์ ์์ ์
print(f"\n๐ฅ ์์ ์์ ์ TOP 5")
top_receivers = df['to'].value_counts().head(5)
for i, (address, count) in enumerate(top_receivers.items(), 1):
total_received = df[df['to'] == address]['value'].sum()
print(f"{i}. {address[:10]}...: {count}๊ฑด, {total_received:,.2f} {token_info['symbol']}")
return df
# USDT ํ ํฐ ๋ถ์ ์์
usdt_address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"
token_analyzer = TokenAnalyzer(w3, usdt_address)
# ํ ํฐ ์ ๋ณด ์กฐํ
token_info = token_analyzer.get_token_info()
print(token_info)
# ์ต๊ทผ 100๋ธ๋ก์ ์ ์ก ๋ด์ญ ๋ถ์
latest = w3.eth.block_number
transfer_df = token_analyzer.analyze_transfers(latest - 100, latest)
๐ก ABI๋?
ABI(Application Binary Interface)๋ ์ค๋งํธ ์ปจํธ๋ํธ์ ํต์ ํ๊ธฐ ์ํ ์ธํฐํ์ด์ค์ผ. ์ด๋ค ํจ์๊ฐ ์๊ณ , ์ด๋ค ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋์ง ์ ์๋์ด ์์ด. ERC-20 ๊ฐ์ ํ์ค์ ABI๊ฐ ์ ํด์ ธ ์์ด์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ง! ๐ฏ
ABI(Application Binary Interface)๋ ์ค๋งํธ ์ปจํธ๋ํธ์ ํต์ ํ๊ธฐ ์ํ ์ธํฐํ์ด์ค์ผ. ์ด๋ค ํจ์๊ฐ ์๊ณ , ์ด๋ค ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋์ง ์ ์๋์ด ์์ด. ERC-20 ๊ฐ์ ํ์ค์ ABI๊ฐ ์ ํด์ ธ ์์ด์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ง! ๐ฏ
๐ก Etherscan API ํ์ฉํ๊ธฐ
Web3.py๋ง์ผ๋ก๋ ํ๊ณ๊ฐ ์์ ๋๊ฐ ์์ด. Etherscan API๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ ๋ค์ํ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ๊ฐ์ ธ์ฌ ์ ์์ด! ๐๐ Python ์ฝ๋ - Etherscan API ํ์ฉ
import requests
import time
class EtherscanAPI:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.etherscan.io/api"
def get_normal_transactions(self, address, startblock=0, endblock=99999999):
"""
์ผ๋ฐ ์ด๋๋ฆฌ์ ๊ฑฐ๋ ๋ด์ญ ์กฐํ
"""
params = {
'module': 'account',
'action': 'txlist',
'address': address,
'startblock': startblock,
'endblock': endblock,
'sort': 'desc',
'apikey': self.api_key
}
response = requests.get(self.base_url, params=params)
data = response.json()
if data['status'] == '1':
return data['result']
else:
print(f"โ API ์ค๋ฅ: {data['message']}")
return []
def get_token_transactions(self, address, contractaddress=None):
"""
ERC-20 ํ ํฐ ๊ฑฐ๋ ๋ด์ญ ์กฐํ
"""
params = {
'module': 'account',
'action': 'tokentx',
'address': address,
'sort': 'desc',
'apikey': self.api_key
}
if contractaddress:
params['contractaddress'] = contractaddress
response = requests.get(self.base_url, params=params)
data = response.json()
if data['status'] == '1':
return data['result']
else:
print(f"โ API ์ค๋ฅ: {data['message']}")
return []
def get_internal_transactions(self, address):
"""
๋ด๋ถ ๊ฑฐ๋ ๋ด์ญ ์กฐํ (์ค๋งํธ ์ปจํธ๋ํธ ์คํ)
"""
params = {
'module': 'account',
'action': 'txlistinternal',
'address': address,
'sort': 'desc',
'apikey': self.api_key
}
response = requests.get(self.base_url, params=params)
data = response.json()
if data['status'] == '1':
return data['result']
else:
return []
def get_contract_abi(self, contract_address):
"""
์ค๋งํธ ์ปจํธ๋ํธ ABI ์กฐํ
"""
params = {
'module': 'contract',
'action': 'getabi',
'address': contract_address,
'apikey': self.api_key
}
response = requests.get(self.base_url, params=params)
data = response.json()
if data['status'] == '1':
return data['result']
else:
print(f"โ ABI ์กฐํ ์คํจ: {data['message']}")
return None
def get_eth_price(self):
"""
ํ์ฌ ์ด๋๋ฆฌ์ ๊ฐ๊ฒฉ ์กฐํ
"""
params = {
'module': 'stats',
'action': 'ethprice',
'apikey': self.api_key
}
response = requests.get(self.base_url, params=params)
data = response.json()
if data['status'] == '1':
return {
'usd': float(data['result']['ethusd']),
'btc': float(data['result']['ethbtc'])
}
return None
def analyze_address_complete(self, address):
"""
์ฃผ์ ์ข
ํฉ ๋ถ์
"""
print(f"\n๐ ์ฃผ์ ์ข
ํฉ ๋ถ์: {address}\n")
# 1. ์ผ๋ฐ ๊ฑฐ๋
print("๐ ์ผ๋ฐ ETH ๊ฑฐ๋ ์กฐํ ์ค...")
normal_txs = self.get_normal_transactions(address)
print(f"โ
{len(normal_txs)}๊ฑด ๋ฐ๊ฒฌ")
time.sleep(0.2) # API ์ ํ ๊ณ ๋ ค
# 2. ํ ํฐ ๊ฑฐ๋
print("\n๐ช ํ ํฐ ๊ฑฐ๋ ์กฐํ ์ค...")
token_txs = self.get_token_transactions(address)
print(f"โ
{len(token_txs)}๊ฑด ๋ฐ๊ฒฌ")
time.sleep(0.2)
# 3. ๋ด๋ถ ๊ฑฐ๋
print("\n๐ ๋ด๋ถ ๊ฑฐ๋ ์กฐํ ์ค...")
internal_txs = self.get_internal_transactions(address)
print(f"โ
{len(internal_txs)}๊ฑด ๋ฐ๊ฒฌ")
# ํต๊ณ ๋ถ์
if normal_txs:
df_normal = pd.DataFrame(normal_txs)
df_normal['value'] = df_normal['value'].astype(float) / 1e18
print(f"\n๐ฐ ETH ๊ฑฐ๋ ํต๊ณ")
print(f"์ด ๊ฑฐ๋ ์: {len(df_normal)}")
print(f"์ด ๊ฑฐ๋๋: {df_normal['value'].sum():.4f} ETH")
# ์
์ถ๊ธ ๊ตฌ๋ถ
incoming = df_normal[df_normal['to'].str.lower() == address.lower()]
outgoing = df_normal[df_normal['from'].str.lower() == address.lower()]
print(f"์
๊ธ: {len(incoming)}๊ฑด, {incoming['value'].sum():.4f} ETH")
print(f"์ถ๊ธ: {len(outgoing)}๊ฑด, {outgoing['value'].sum():.4f} ETH")
if token_txs:
df_tokens = pd.DataFrame(token_txs)
print(f"\n๐ช ํ ํฐ ๊ฑฐ๋ ํต๊ณ")
print(f"์ด ํ ํฐ ๊ฑฐ๋: {len(df_tokens)}๊ฑด")
# ๊ฑฐ๋๋ ํ ํฐ ์ข
๋ฅ
unique_tokens = df_tokens['tokenSymbol'].value_counts()
print(f"\n๊ฑฐ๋๋ ํ ํฐ ์ข
๋ฅ ({len(unique_tokens)}๊ฐ):")
for token, count in unique_tokens.head(10).items():
print(f" โข {token}: {count}๊ฑด")
return {
'normal': normal_txs,
'token': token_txs,
'internal': internal_txs
}
# Etherscan API ์ฌ์ฉ ์์
etherscan = EtherscanAPI("YOUR_ETHERSCAN_API_KEY")
# ์ด๋๋ฆฌ์ ๊ฐ๊ฒฉ ์กฐํ
eth_price = etherscan.get_eth_price()
print(f"๐ต ํ์ฌ ETH ๊ฐ๊ฒฉ: ${eth_price['usd']:,.2f}")
# ์ฃผ์ ์ข
ํฉ ๋ถ์
target_address = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
analysis_result = etherscan.analyze_address_complete(target_address)
๐ฏ Etherscan API์ ์ฅ์
โข ๋น ๋ฅธ ์กฐํ: ์ธ๋ฑ์ฑ๋ ๋ฐ์ดํฐ๋ก ๋น ๋ฅธ ๊ฒ์
โข ๋ค์ํ ์ ๋ณด: ์ผ๋ฐ ๊ฑฐ๋, ํ ํฐ ๊ฑฐ๋, ๋ด๋ถ ๊ฑฐ๋ ๋ชจ๋ ์กฐํ
โข ๊ฒ์ฆ๋ ๋ฐ์ดํฐ: Etherscan์ด ๊ฒ์ฆํ ์ ํํ ์ ๋ณด
โข ๋ฌด๋ฃ ์ฌ์ฉ: ํ๋ฃจ 100,000 ์์ฒญ๊น์ง ๋ฌด๋ฃ
โข ABI ์ ๊ณต: ๊ฒ์ฆ๋ ์ปจํธ๋ํธ์ ABI ์๋ ์กฐํ
โข ๋น ๋ฅธ ์กฐํ: ์ธ๋ฑ์ฑ๋ ๋ฐ์ดํฐ๋ก ๋น ๋ฅธ ๊ฒ์
โข ๋ค์ํ ์ ๋ณด: ์ผ๋ฐ ๊ฑฐ๋, ํ ํฐ ๊ฑฐ๋, ๋ด๋ถ ๊ฑฐ๋ ๋ชจ๋ ์กฐํ
โข ๊ฒ์ฆ๋ ๋ฐ์ดํฐ: Etherscan์ด ๊ฒ์ฆํ ์ ํํ ์ ๋ณด
โข ๋ฌด๋ฃ ์ฌ์ฉ: ํ๋ฃจ 100,000 ์์ฒญ๊น์ง ๋ฌด๋ฃ
โข ABI ์ ๊ณต: ๊ฒ์ฆ๋ ์ปจํธ๋ํธ์ ABI ์๋ ์กฐํ
๐พ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ๊ด๋ฆฌ
์์งํ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ๊ฒ๋ ์ค์ํด! ๋งค๋ฒ ๋ธ๋ก์ฒด์ธ์์ ๋ค์ ๊ฐ์ ธ์ค๋ฉด ์๊ฐ๋ ์ค๋ ๊ฑธ๋ฆฌ๊ณ API ์ ํ์๋ ๊ฑธ๋ฆฌ๊ฑฐ๋ . ๐๏ธ๐ CSV ํ์ผ๋ก ์ ์ฅ
๐ Python ์ฝ๋ - ๋ฐ์ดํฐ ์ ์ฅ
import os
from datetime import datetime
class DataManager:
def __init__(self, data_dir='blockchain_data'):
self.data_dir = data_dir
# ๋ฐ์ดํฐ ๋๋ ํ ๋ฆฌ ์์ฑ
if not os.path.exists(data_dir):
os.makedirs(data_dir)
print(f"๐ ๋ฐ์ดํฐ ๋๋ ํ ๋ฆฌ ์์ฑ: {data_dir}")
def save_transactions(self, df, filename=None):
"""
๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ CSV๋ก ์ ์ฅ
"""
if filename is None:
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filename = f"transactions_{timestamp}.csv"
filepath = os.path.join(self.data_dir, filename)
df.to_csv(filepath, index=False, encoding='utf-8-sig')
print(f"๐พ ๋ฐ์ดํฐ ์ ์ฅ ์๋ฃ: {filepath}")
print(f" ์ด {len(df)}๊ฑด์ ๊ฑฐ๋ ์ ์ฅ")
return filepath
def load_transactions(self, filename):
"""
์ ์ฅ๋ ๊ฑฐ๋ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ
"""
filepath = os.path.join(self.data_dir, filename)
if not os.path.exists(filepath):
print(f"โ ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค: {filepath}")
return None
df = pd.read_csv(filepath)
print(f"๐ ๋ฐ์ดํฐ ๋ก๋ ์๋ฃ: {len(df)}๊ฑด")
return df
def list_saved_files(self):
"""
์ ์ฅ๋ ํ์ผ ๋ชฉ๋ก ์กฐํ
"""
files = [f for f in os.listdir(self.data_dir) if f.endswith('.csv')]
if not files:
print("์ ์ฅ๋ ํ์ผ์ด ์์ต๋๋ค.")
return []
print(f"\n๐ ์ ์ฅ๋ ํ์ผ ๋ชฉ๋ก ({len(files)}๊ฐ)")
for i, file in enumerate(sorted(files), 1):
filepath = os.path.join(self.data_dir, file)
size = os.path.getsize(filepath) / 1024 # KB
print(f"{i}. {file} ({size:.2f} KB)")
return files
def merge_data(self, filenames):
"""
์ฌ๋ฌ ํ์ผ์ ๋ฐ์ดํฐ ๋ณํฉ
"""
dfs = []
for filename in filenames:
df = self.load_transactions(filename)
if df is not None:
dfs.append(df)
if not dfs:
print("๋ณํฉํ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.")
return None
merged_df = pd.concat(dfs, ignore_index=True)
# ์ค๋ณต ์ ๊ฑฐ (tx_hash ๊ธฐ์ค)
if 'tx_hash' in merged_df.columns:
before = len(merged_df)
merged_df = merged_df.drop_duplicates(subset=['tx_hash'])
after = len(merged_df)
print(f"๐ ์ค๋ณต ์ ๊ฑฐ: {before - after}๊ฑด")
print(f"โ
๋ณํฉ ์๋ฃ: ์ด {len(merged_df)}๊ฑด")
return merged_df
def export_to_excel(self, df, filename):
"""
Excel ํ์ผ๋ก ๋ด๋ณด๋ด๊ธฐ
"""
filepath = os.path.join(self.data_dir, filename)
try:
df.to_excel(filepath, index=False, engine='openpyxl')
print(f"๐ Excel ํ์ผ ์์ฑ: {filepath}")
except ImportError:
print("โ openpyxl ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค: pip install openpyxl")
# ๋ฐ์ดํฐ ๊ด๋ฆฌ์ ์์ฑ
data_manager = DataManager()
# ๊ฑฐ๋ ๋ฐ์ดํฐ ์ ์ฅ
if 'df_transactions' in locals():
saved_file = data_manager.save_transactions(df_transactions)
# ์ ์ฅ๋ ํ์ผ ๋ชฉ๋ก ํ์ธ
data_manager.list_saved_files()
# ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ
# loaded_df = data_manager.load_transactions('transactions_20240101_120000.csv')
๐๏ธ SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ฉ
๋๋์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ํจ์ฌ ํจ์จ์ ์ด์ผ! SQLite๋ ์ค์น ์์ด ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ด์ ํธ๋ฆฌํด. ๐๐ Python ์ฝ๋ - SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค
import sqlite3
from contextlib import contextmanager
class BlockchainDB:
def __init__(self, db_name='blockchain.db'):
self.db_name = db_name
self.init_database()
@contextmanager
def get_connection(self):
"""
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ปจํ
์คํธ ๋งค๋์
"""
conn = sqlite3.connect(self.db_name)
try:
yield conn
finally:
conn.close()
def init_database(self):
"""
๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ ์ด๊ธฐํ
"""
with self.get_connection() as conn:
cursor = conn.cursor()
# ๊ฑฐ๋ ํ
์ด๋ธ
cursor.execute('''
CREATE TABLE IF NOT EXISTS transactions (
tx_hash TEXT PRIMARY KEY,
block_number INTEGER,
timestamp DATETIME,
from_address TEXT,
to_address TEXT,
value REAL,
gas_price REAL,
gas_used INTEGER,
tx_fee REAL,
status INTEGER
)
''')
# ํ ํฐ ์ ์ก ํ
์ด๋ธ
cursor.execute('''
CREATE TABLE IF NOT EXISTS token_transfers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tx_hash TEXT,
block_number INTEGER,
token_address TEXT,
token_symbol TEXT,
from_address TEXT,
to_address TEXT,
value REAL,
timestamp DATETIME
)
''')
# ์ฃผ์ ํ
์ด๋ธ
cursor.execute('''
CREATE TABLE IF NOT EXISTS addresses (
address TEXT PRIMARY KEY,
label TEXT,
first_seen DATETIME,
last_seen DATETIME,
tx_count INTEGER DEFAULT 0,
total_received REAL DEFAULT 0,
total_sent REAL DEFAULT 0
)
''')
# ์ธ๋ฑ์ค ์์ฑ
cursor.execute('CREATE INDEX IF NOT EXISTS idx_block ON transactions(block_number)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_from ON transactions(from_address)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_to ON transactions(to_address)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_timestamp ON transactions(timestamp)')
conn.commit()
print("โ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ ์๋ฃ")
def insert_transaction(self, tx_data):
"""
๊ฑฐ๋ ๋ฐ์ดํฐ ์ฝ์
"""
with self.get_connection() as conn:
cursor = conn.cursor()
try:
cursor.execute('''
INSERT OR REPLACE INTO transactions
(tx_hash, block_number, timestamp, from_address, to_address,
value, gas_price, gas_used, tx_fee, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
tx_data['tx_hash'],
tx_data['block_number'],
tx_data['timestamp'],
tx_data['from_address'],
tx_data['to_address'],
tx_data['value'],
tx_data.get('gas_price', 0),
tx_data.get('gas_used', 0),
tx_data.get('tx_fee', 0),
tx_data.get('status', 1)
))
conn.commit()
return True
except Exception as e:
print(f"โ ๋ฐ์ดํฐ ์ฝ์
์คํจ: {e}")
return False
def insert_transactions_bulk(self, transactions):
"""
๋๋ ๊ฑฐ๋ ๋ฐ์ดํฐ ์ฝ์
"""
with self.get_connection() as conn:
cursor = conn.cursor()
data = [
(
tx['tx_hash'],
tx['block_number'],
tx['timestamp'],
tx['from_address'],
tx['to_address'],
tx['value'],
tx.get('gas_price', 0),
tx.get('gas_used', 0),
tx.get('tx_fee', 0),
tx.get('status', 1)
)
for tx in transactions
]
try:
cursor.executemany('''
INSERT OR REPLACE INTO transactions
(tx_hash, block_number, timestamp, from_address, to_address,
value, gas_price, gas_used, tx_fee, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', data)
conn.commit()
print(f"โ
{len(data)}๊ฑด์ ๊ฑฐ๋ ์ ์ฅ ์๋ฃ")
return True
except Exception as e:
print(f"โ ๋๋ ์ฝ์
์คํจ: {e}")
return False
def get_transactions_by_address(self, address, limit=100):
"""
ํน์ ์ฃผ์์ ๊ฑฐ๋ ์กฐํ
"""
with self.get_connection() as conn:
query = '''
SELECT * FROM transactions
WHERE from_address = ? OR to_address = ?
ORDER BY timestamp DESC
LIMIT ?
'''
df = pd.read_sql_query(query, conn, params=(address, address, limit))
return df
def get_transactions_by_date(self, start_date, end_date):
"""
๋ ์ง ๋ฒ์๋ก ๊ฑฐ๋ ์กฐํ
"""
with self.get_connection() as conn:
query = '''
SELECT * FROM transactions
WHERE timestamp BETWEEN ? AND ?
ORDER BY timestamp DESC
'''
df = pd.read_sql_query(query, conn, params=(start_date, end_date))
return df
def get_statistics(self):
"""
์ ์ฒด ํต๊ณ ์กฐํ
"""
with self.get_connection() as conn:
cursor = conn.cursor()
# ์ด ๊ฑฐ๋ ์
cursor.execute('SELECT COUNT(*) FROM transactions')
total_txs = cursor.fetchone()[0]
# ์ด ๊ฑฐ๋๋
cursor.execute('SELECT SUM(value) FROM transactions')
total_volume = cursor.fetchone()[0] or 0
# ๊ณ ์ ์ฃผ์ ์
cursor.execute('''
SELECT COUNT(DISTINCT address) FROM (
SELECT from_address as address FROM transactions
UNION
SELECT to_address as address FROM transactions
)
''')
unique_addresses = cursor.fetchone()[0]
# ๋ธ๋ก ๋ฒ์
cursor.execute('SELECT MIN(block_number), MAX(block_number) FROM transactions')
block_range = cursor.fetchone()
stats = {
'total_transactions': total_txs,
'total_volume': total_volume,
'unique_addresses': unique_addresses,
'block_range': block_range
}
return stats
def export_to_csv(self, output_file, query=None):
"""
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ด์ฉ์ CSV๋ก ๋ด๋ณด๋ด๊ธฐ
"""
with self.get_connection() as conn:
if query is None:
query = 'SELECT * FROM transactions'
df = pd.read_sql_query(query, conn)
df.to_csv(output_file, index=False)
print(f"๐ CSV ํ์ผ ์์ฑ: {output_file} ({len(df)}๊ฑด)")
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ ์์
db = BlockchainDB('my_blockchain.db')
# DataFrame์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ
if 'df_transactions' in locals():
transactions_list = df_transactions.to_dict('records')
db.insert_transactions_bulk(transactions_list)
# ํต๊ณ ์กฐํ
stats = db.get_statistics()
print(f"\n๐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํต๊ณ")
print(f"์ด ๊ฑฐ๋ ์: {stats['total_transactions']:,}")
print(f"์ด ๊ฑฐ๋๋: {stats['total_volume']:.4f} ETH")
print(f"๊ณ ์ ์ฃผ์ ์: {stats['unique_addresses']:,}")
print(f"๋ธ๋ก ๋ฒ์: {stats['block_range'][0]} ~ {stats['block_range'][1]}")
๐ก ๋ฐ์ดํฐ๋ฒ ์ด์ค vs CSV
CSV ์ฅ์ : ๊ฐ๋จํ๊ณ ์์ ์์ ๋ฐ๋ก ์ด์ด๋ณผ ์ ์์ด
DB ์ฅ์ : ๋น ๋ฅธ ๊ฒ์, ๋ณต์กํ ์ฟผ๋ฆฌ, ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ๋ฆฌ
์๊ท๋ชจ ํ๋ก์ ํธ๋ CSV, ๋๊ท๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ถ์ฒํด! ๐ฏ
CSV ์ฅ์ : ๊ฐ๋จํ๊ณ ์์ ์์ ๋ฐ๋ก ์ด์ด๋ณผ ์ ์์ด
DB ์ฅ์ : ๋น ๋ฅธ ๊ฒ์, ๋ณต์กํ ์ฟผ๋ฆฌ, ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ๋ฆฌ
์๊ท๋ชจ ํ๋ก์ ํธ๋ CSV, ๋๊ท๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ถ์ฒํด! ๐ฏ
๐จ ์ค์ ํ๋ก์ ํธ: ๊ฑฐ๋์ ์ ์ถ๊ธ ๋ชจ๋ํฐ๋ง
์ด์ ๋ฐฐ์ด ๋ด์ฉ์ ์ข ํฉํด์ ์ค์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณด์! ๊ฑฐ๋์ ์ง๊ฐ์ ์ ์ถ๊ธ์ ์ค์๊ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํ๋ ์์คํ ์ด์ผ. ์ด๊ฑด ์ค์ ๋ก ๋ง์ด ํ์ฉ๋๋ ๊ธฐ๋ฅ์ด๊ฑฐ๋ ! ๐ผ๐ Python ์ฝ๋ - ๊ฑฐ๋์ ๋ชจ๋ํฐ๋ง ์์คํ
class ExchangeMonitor:
def __init__(self, w3_instance, db_instance):
self.w3 = w3_instance
self.db = db_instance
self.exchange_addresses = {}
self.alert_threshold = 100 # ETH
def add_exchange(self, name, address):
"""
๋ชจ๋ํฐ๋งํ ๊ฑฐ๋์ ์ถ๊ฐ
"""
checksum_address = self.w3.to_checksum_address(address)
self.exchange_addresses[name] = checksum_address
print(f"โ
๊ฑฐ๋์ ์ถ๊ฐ: {name} ({checksum_address})")
def check_balance(self, exchange_name):
"""
๊ฑฐ๋์ ์์ก ํ์ธ
"""
if exchange_name not in self.exchange_addresses:
print(f"โ ๋ฑ๋ก๋์ง ์์ ๊ฑฐ๋์: {exchange_name}")
return None
address = self.exchange_addresses[exchange_name]
balance_wei = self.w3.eth.get_balance(address)
balance_eth = float(self.w3.from_wei(balance_wei, 'ether'))
return balance_eth
def analyze_flow(self, exchange_name, hours=24):
"""
ํน์ ๊ธฐ๊ฐ ๋์์ ์
์ถ๊ธ ํ๋ฆ ๋ถ์
"""
if exchange_name not in self.exchange_addresses:
return None
address = self.exchange_addresses[exchange_name]
# ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฑฐ๋ ์กฐํ
from datetime import datetime, timedelta
end_time = datetime.now()
start_time = end_time - timedelta(hours=hours)
df = self.db.get_transactions_by_date(
start_time.strftime('%Y-%m-%d %H:%M:%S'),
end_time.strftime('%Y-%m-%d %H:%M:%S')
)
# ํด๋น ๊ฑฐ๋์ ๊ด๋ จ ๊ฑฐ๋๋ง ํํฐ๋ง
exchange_txs = df[
(df['from_address'] == address) |
(df['to_address'] == address)
]
if len(exchange_txs) == 0:
print(f"์ต๊ทผ {hours}์๊ฐ ๋์ ๊ฑฐ๋ ์์")
return None
# ์
์ถ๊ธ ๊ตฌ๋ถ
deposits = exchange_txs[exchange_txs['to_address'] == address]
withdrawals = exchange_txs[exchange_txs['from_address'] == address]
analysis = {
'exchange': exchange_name,
'period_hours': hours,
'total_transactions': len(exchange_txs),
'deposits': {
'count': len(deposits),
'total': deposits['value'].sum(),
'average': deposits['value'].mean() if len(deposits) > 0 else 0
},
'withdrawals': {
'count': len(withdrawals),
'total': withdrawals['value'].sum(),
'average': withdrawals['value'].mean() if len(withdrawals) > 0 else 0
},
'net_flow': deposits['value'].sum() - withdrawals['value'].sum()
}
return analysis
def print_flow_report(self, analysis):
"""
์
์ถ๊ธ ๋ถ์ ๋ฆฌํฌํธ ์ถ๋ ฅ
"""
if not analysis:
return
print(f"\n{'='*60}")
print(f"๐ฆ {analysis['exchange']} ์
์ถ๊ธ ๋ถ์ ๋ฆฌํฌํธ")
print(f"๐
๋ถ์ ๊ธฐ๊ฐ: ์ต๊ทผ {analysis['period_hours']}์๊ฐ")
print(f"{'='*60}")
print(f"\n๐ฅ ์
๊ธ (Deposits)")
print(f" ๊ฑฐ๋ ์: {analysis['deposits']['count']}๊ฑด")
print(f" ์ด ์
๊ธ์ก: {analysis['deposits']['total']:.4f} ETH")
print(f" ํ๊ท ์
๊ธ์ก: {analysis['deposits']['average']:.4f} ETH")
print(f"\n๐ค ์ถ๊ธ (Withdrawals)")
print(f" ๊ฑฐ๋ ์: {analysis['withdrawals']['count']}๊ฑด")
print(f" ์ด ์ถ๊ธ์ก: {analysis['withdrawals']['total']:.4f} ETH")
print(f" ํ๊ท ์ถ๊ธ์ก: {analysis['withdrawals']['average']:.4f} ETH")
net_flow = analysis['net_flow']
flow_direction = "์ ์
" if net_flow > 0 else "์ ์ถ"
print(f"\n๐ฐ ์ ํ๋ฆ: {abs(net_flow):.4f} ETH ({flow_direction})")
# ํ์ฌ ์์ก
current_balance = self.check_balance(analysis['exchange'])
print(f"๐ผ ํ์ฌ ์์ก: {current_balance:.4f} ETH")
print(f"{'='*60}\n")
def monitor_large_transactions(self, block_number):
"""
๋๋ ๊ฑฐ๋ ๋ชจ๋ํฐ๋ง
"""
try:
block = self.w3.eth.get_block(block_number, full_transactions=True)
alerts = []
for tx in block['transactions']:
value_eth = float(self.w3.from_wei(tx['value'], 'ether'))
# ๊ฑฐ๋์ ๊ด๋ จ ๋๋ ๊ฑฐ๋ ๊ฐ์ง
for exchange_name, exchange_address in self.exchange_addresses.items():
if value_eth >= self.alert_threshold:
if tx['from'] == exchange_address:
alert = {
'type': 'WITHDRAWAL',
'exchange': exchange_name,
'amount': value_eth,
'to': tx['to'],
'tx_hash': tx['hash'].hex()
}
alerts.append(alert)
self.send_alert(alert)
elif tx['to'] == exchange_address:
alert = {
'type': 'DEPOSIT',
'exchange': exchange_name,
'amount': value_eth,
'from': tx['from'],
'tx_hash': tx['hash'].hex()
}
alerts.append(alert)
self.send_alert(alert)
return alerts
except Exception as e:
print(f"โ ๋ธ๋ก ๋ชจ๋ํฐ๋ง ์คํจ: {e}")
return []
def send_alert(self, alert):
"""
์๋ฆผ ์ ์ก
"""
emoji = "๐ค" if alert['type'] == 'WITHDRAWAL' else "๐ฅ"
print(f"\n๐จ {emoji} ๋๋ ๊ฑฐ๋ ๊ฐ์ง!")
print(f" ๊ฑฐ๋์: {alert['exchange']}")
print(f" ์ ํ: {alert['type']}")
print(f" ๊ธ์ก: {alert['amount']:.2f} ETH")
if alert['type'] == 'WITHDRAWAL':
print(f" ์์ ์: {alert['to']}")
else:
print(f" ์ก์ ์: {alert['from']}")
print(f" TX: {alert['tx_hash']}")
def run_monitoring(self, interval=15):
"""
์ค์๊ฐ ๋ชจ๋ํฐ๋ง ์คํ
"""
print("๐ ๊ฑฐ๋์ ๋ชจ๋ํฐ๋ง ์์...")
print(f"๋ชจ๋ํฐ๋ง ๋์: {', '.join(self.exchange_addresses.keys())}")
print(f"์๋ฆผ ์๊ณ๊ฐ: {self.alert_threshold} ETH\n")
last_block = self.w3.eth.block_number
try:
while True:
current_block = self.w3.eth.block_number
if current_block > last_block:
for block_num in range(last_block + 1, current_block + 1):
print(f"๐ฆ ๋ธ๋ก #{block_num} ๋ถ์ ์ค...")
alerts = self.monitor_large_transactions(block_num)
if alerts:
print(f"โ
{len(alerts)}๊ฑด์ ์๋ฆผ ๋ฐ์")
last_block = current_block
time.sleep(interval)
except KeyboardInterrupt:
print("\nโน๏ธ ๋ชจ๋ํฐ๋ง ์ข
๋ฃ")
# ๊ฑฐ๋์ ๋ชจ๋ํฐ๋ง ์์คํ
์ค์
monitor = ExchangeMonitor(w3, db)
# ์ฃผ์ ๊ฑฐ๋์ ์ฃผ์ ์ถ๊ฐ (์์)
monitor.add_exchange("Binance", "0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE")
monitor.add_exchange("Coinbase", "0x71660c4005BA85c37ccec55d0C4493E66Fe775d3")
monitor.add_exchange("Kraken", "0x2910543Af39abA0Cd09dBb2D50200b3E800A63D2")
# ์
์ถ๊ธ ํ๋ฆ ๋ถ์
analysis = monitor.analyze_flow("Binance", hours=24)
monitor.print_flow_report(analysis)
# ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ์์ (์ฃผ์ ํด์ ํ์ฌ ์คํ)
# monitor.run_monitoring(interval=15)
๐ฏ ์ค์ ํ์ฉ ํ
โข ๊ฑฐ๋์ ์ฃผ์ ํ์ธ: Etherscan์์ "Top Accounts" ๋ฉ๋ด๋ก ์ฃผ์ ๊ฑฐ๋์ ์ฃผ์ ํ์ธ
โข ์๋ฆผ ์ฐ๋: ํ ๋ ๊ทธ๋จ ๋ด์ด๋ ์ด๋ฉ์ผ๋ก ์ค์๊ฐ ์๋ฆผ ์ ์ก
โข ํจํด ๋ถ์: ๋๋ ์ถ๊ธ ํ ๊ฐ๊ฒฉ ๋ณ๋ ํจํด ํ์ต
โข ๋ค์ค ์ฒด์ธ: BSC, Polygon ๋ฑ ๋ค๋ฅธ ์ฒด์ธ๋ ๋์ ๋ชจ๋ํฐ๋ง
โข ์๋ ๊ฑฐ๋: ํน์ ํจํด ๊ฐ์ง ์ ์๋ ๋งค๋งค ์ ๋ต ์คํ
โข ๊ฑฐ๋์ ์ฃผ์ ํ์ธ: Etherscan์์ "Top Accounts" ๋ฉ๋ด๋ก ์ฃผ์ ๊ฑฐ๋์ ์ฃผ์ ํ์ธ
โข ์๋ฆผ ์ฐ๋: ํ ๋ ๊ทธ๋จ ๋ด์ด๋ ์ด๋ฉ์ผ๋ก ์ค์๊ฐ ์๋ฆผ ์ ์ก
โข ํจํด ๋ถ์: ๋๋ ์ถ๊ธ ํ ๊ฐ๊ฒฉ ๋ณ๋ ํจํด ํ์ต
โข ๋ค์ค ์ฒด์ธ: BSC, Polygon ๋ฑ ๋ค๋ฅธ ์ฒด์ธ๋ ๋์ ๋ชจ๋ํฐ๋ง
โข ์๋ ๊ฑฐ๋: ํน์ ํจํด ๊ฐ์ง ์ ์๋ ๋งค๋งค ์ ๋ต ์คํ
๐ง ์ฑ๋ฅ ์ต์ ํ ๋ฐ ํ
์ค์ ์ด์ ํ๊ฒฝ์์๋ ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ด ์ ๋ง ์ค์ํด! ๋ช ๊ฐ์ง ์ต์ ํ ๊ธฐ๋ฒ์ ์์๋ณด์. โก๐ ๋ฉํฐ์ค๋ ๋ฉ์ผ๋ก ์๋ ํฅ์
๐ Python ์ฝ๋ - ๋ฉํฐ์ค๋ ๋ฉ
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
class ParallelBlockAnalyzer:
def __init__(self, w3_instance, max_workers=5):
self.w3 = w3_instance
self.max_workers = max_workers
self.lock = threading.Lock()
self.results = []
def analyze_single_block(self, block_number):
"""
๋จ์ผ ๋ธ๋ก ๋ถ์
"""
try:
block = self.w3.eth.get_block(block_number, full_transactions=True)
block_data = {
'block_number': block_number,
'timestamp': block['timestamp'],
'tx_count': len(block['transactions']),
'total_value': sum(
float(self.w3.from_wei(tx['value'], 'ether'))
for tx in block['transactions']
)
}
return block_data
except Exception as e:
print(f"โ ๋ธ๋ก {block_number} ๋ถ์ ์คํจ: {e}")
return None
def analyze_blocks_parallel(self, start_block, end_block):
"""
์ฌ๋ฌ ๋ธ๋ก์ ๋ณ๋ ฌ๋ก ๋ถ์
"""
block_numbers = range(start_block, end_block + 1)
results = []
print(f"๐ {len(block_numbers)}๊ฐ ๋ธ๋ก ๋ณ๋ ฌ ๋ถ์ ์์...")
print(f"์์ปค ์: {self.max_workers}")
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
# ๋ชจ๋ ๋ธ๋ก ๋ถ์ ์์
์ ์ถ
future_to_block = {
executor.submit(self.analyze_single_block, block_num): block_num
for block_num in block_numbers
}
# ์๋ฃ๋ ์์
์ฒ๋ฆฌ
completed = 0
for future in as_completed(future_to_block):
block_num = future_to_block[future]
try:
result = future.result()
if result:
results.append(result)
completed += 1
if completed % 10 == 0:
progress = (completed / len(block_numbers)) * 100
print(f"์งํ๋ฅ : {progress:.1f}% ({completed}/{len(block_numbers)})")
except Exception as e:
print(f"โ ๋ธ๋ก {block_num} ์ฒ๋ฆฌ ์ค ์ค๋ฅ: {e}")
print(f"โ
๋ถ์ ์๋ฃ: {len(results)}๊ฐ ๋ธ๋ก")
return results
# ๋ณ๋ ฌ ๋ถ์ ์คํ
analyzer = ParallelBlockAnalyzer(w3, max_workers=10)
latest = w3.eth.block_number
# ์ต๊ทผ 100๊ฐ ๋ธ๋ก์ ๋ณ๋ ฌ๋ก ๋ถ์
results = analyzer.analyze_blocks_parallel(latest - 100, latest)
# ๊ฒฐ๊ณผ๋ฅผ DataFrame์ผ๋ก ๋ณํ
df_results = pd.DataFrame(results)
print(f"\n๐ ๋ถ์ ๊ฒฐ๊ณผ ์์ฝ")
print(f"ํ๊ท ๊ฑฐ๋ ์: {df_results['tx_count'].mean():.2f}")
print(f"ํ๊ท ๊ฑฐ๋๋: {df_results['total_value'].mean():.4f} ETH")
๐ก ๋ฉํฐ์ค๋ ๋ฉ ์ฃผ์์ฌํญ
์์ปค ์๋ฅผ ๋๋ฌด ๋ง์ด ์ค์ ํ๋ฉด API ์ ํ์ ๊ฑธ๋ฆด ์ ์์ด! Infura ๋ฌด๋ฃ ํ๋์ ์ด๋น 10 ์์ฒญ๊น์ง ๊ฐ๋ฅํ๋๊น, max_workers๋ 5~10 ์ ๋๊ฐ ์ ๋นํด. ์ ๋ฃ ํ๋์ด๋ฉด ๋ ๋๋ ค๋ ๋ผ! ๐ฏ
์์ปค ์๋ฅผ ๋๋ฌด ๋ง์ด ์ค์ ํ๋ฉด API ์ ํ์ ๊ฑธ๋ฆด ์ ์์ด! Infura ๋ฌด๋ฃ ํ๋์ ์ด๋น 10 ์์ฒญ๊น์ง ๊ฐ๋ฅํ๋๊น, max_workers๋ 5~10 ์ ๋๊ฐ ์ ๋นํด. ์ ๋ฃ ํ๋์ด๋ฉด ๋ ๋๋ ค๋ ๋ผ! ๐ฏ
๐พ ์บ์ฑ์ผ๋ก ์ค๋ณต ์์ฒญ ๋ฐฉ์ง
๐ Python ์ฝ๋ - ์บ์ฑ ์์คํ
from functools import lru_cache
import pickle
import hashlib
class CachedWeb3:
def __init__(self, w3_instance, cache_dir='cache'):
self.w3 = w3_instance
self.cache_dir = cache_dir
if not os.path.exists(cache_dir):
os.makedirs(cache_dir)
def _get_cache_key(self, method, *args):
"""
์บ์ ํค ์์ฑ
"""
key_string = f"{method}_{args}"
return hashlib.md5(key_string.encode()).hexdigest()
def _get_cache_path(self, cache_key):
"""
์บ์ ํ์ผ ๊ฒฝ๋ก
"""
return os.path.join(self.cache_dir, f"{cache_key}.pkl")
def _load_from_cache(self, cache_key):
"""
์บ์์์ ๋ฐ์ดํฐ ๋ก๋
"""
cache_path = self._get_cache_path(cache_key)
if os.path.exists(cache_path):
try:
with open(cache_path, 'rb') as f:
return pickle.load(f)
except:
return None
return None
def _save_to_cache(self, cache_key, data):
"""
๋ฐ์ดํฐ๋ฅผ ์บ์์ ์ ์ฅ
"""
cache_path = self._get_cache_path(cache_key)
try:
with open(cache_path, 'wb') as f:
pickle.dump(data, f)
except Exception as e:
print(f"โ ๏ธ ์บ์ ์ ์ฅ ์คํจ: {e}")
def get_block(self, block_number, full_transactions=False):
"""
๋ธ๋ก ์ ๋ณด ์กฐํ (์บ์ฑ)
"""
cache_key = self._get_cache_key('block', block_number, full_transactions)
# ์บ์ ํ์ธ
cached_data = self._load_from_cache(cache_key)
if cached_data:
print(f"๐พ ์บ์์์ ๋ธ๋ก #{block_number} ๋ก๋")
return cached_data
# ๋ธ๋ก์ฒด์ธ์์ ์กฐํ
print(f"๐ ๋ธ๋ก์ฒด์ธ์์ ๋ธ๋ก #{block_number} ์กฐํ")
block = self.w3.eth.get_block(block_number, full_transactions=full_transactions)
# ์บ์์ ์ ์ฅ
self._save_to_cache(cache_key, block)
return block
def clear_cache(self):
"""
์บ์ ์ ์ฒด ์ญ์
"""
import shutil
if os.path.exists(self.cache_dir):
shutil.rmtree(self.cache_dir)
os.makedirs(self.cache_dir)
print("๐๏ธ ์บ์ ์ญ์ ์๋ฃ")
# ์บ์ฑ ์ ์ฉ
cached_w3 = CachedWeb3(w3)
# ์ฒซ ๋ฒ์งธ ํธ์ถ - ๋ธ๋ก์ฒด์ธ์์ ์กฐํ
block1 = cached_w3.get_block(19000000)
# ๋ ๋ฒ์งธ ํธ์ถ - ์บ์์์ ๋ก๋ (ํจ์ฌ ๋น ๋ฆ!)
block2 = cached_w3.get_block(19000000)
โ ๏ธ ์๋ฌ ์ฒ๋ฆฌ ๋ฐ ์ฌ์๋ ๋ก์ง
๐ Python ์ฝ๋ - ์์ ์ ์ธ ์๋ฌ ์ฒ๋ฆฌ
import time
from functools import wraps
def retry_on_failure(max_retries=3, delay=1, backoff=2):
"""
์คํจ ์ ์ฌ์๋ํ๋ ๋ฐ์ฝ๋ ์ดํฐ
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
retries = 0
current_delay = delay
while retries < max_retries:
try:
return func(*args, **kwargs)
except Exception as e:
retries += 1
if retries >= max_retries:
print(f"โ {func.__name__} ์ต์ข
์คํจ: {e}")
raise
print(f"โ ๏ธ {func.__name__} ์คํจ (์๋ {retries}/{max_retries}): {e}")
print(f" {current_delay}์ด ํ ์ฌ์๋...")
time.sleep(current_delay)
current_delay *= backoff
return None
return wrapper
return decorator
class RobustBlockchainClient:
def __init__(self, w3_instance):
self.w3 = w3_instance
@retry_on_failure(max_retries=3, delay=1, backoff=2)
def get_block_safe(self, block_number):
"""
์์ ํ ๋ธ๋ก ์กฐํ
"""
return self.w3.eth.get_block(block_number, full_transactions=True)
@retry_on_failure(max_retries=5, delay=2, backoff=1.5)
def get_transaction_receipt(self, tx_hash):
"""
์์ ํ ํธ๋์ญ์
์์์ฆ ์กฐํ
"""
return self.w3.eth.get_transaction_receipt(tx_hash)
def batch_get_blocks(self, block_numbers):
"""
์ฌ๋ฌ ๋ธ๋ก์ ์์ ํ๊ฒ ์กฐํ
"""
results = []
failed = []
for block_num in block_numbers:
try:
block = self.get_block_safe(block_num)
results.append(block)
except Exception as e:
print(f"โ ๋ธ๋ก {block_num} ์กฐํ ์คํจ")
failed.append(block_num)
print(f"\nโ
์ฑ๊ณต: {len(results)}๊ฐ")
print(f"โ ์คํจ: {len(failed)}๊ฐ")
if failed:
print(f"์คํจํ ๋ธ๋ก: {failed}")
return results, failed
# ์์ ์ ์ธ ํด๋ผ์ด์ธํธ ์ฌ์ฉ
robust_client = RobustBlockchainClient(w3)
# ๋ธ๋ก ์กฐํ (์๋ ์ฌ์๋)
try:
block = robust_client.get_block_safe(19000000)
print("โ
๋ธ๋ก ์กฐํ ์ฑ๊ณต")
except Exception as e:
print(f"โ ๋ชจ๋ ์ฌ์๋ ์คํจ: {e}")
โ ๏ธ ํ๋ก๋์
ํ๊ฒฝ ์ฒดํฌ๋ฆฌ์คํธ
- โ API ํค ํ๊ฒฝ๋ณ์๋ก ๊ด๋ฆฌ
- โ ์๋ฌ ๋ก๊น ์์คํ ๊ตฌ์ถ
- โ ์ฌ์๋ ๋ก์ง ๊ตฌํ
- โ ์บ์ฑ์ผ๋ก ์ค๋ณต ์์ฒญ ๋ฐฉ์ง
- โ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐฑ์ ์๋ํ
- โ ๋ชจ๋ํฐ๋ง ๋ฐ ์๋ฆผ ์์คํ
- โ API ์์ฒญ ์ ํ ์ค์
- โ ๋ณด์ ์ทจ์ฝ์ ์ ๊ฒ
๐ ์ฌ๋ฅ๋ท์์ ๋ธ๋ก์ฒด์ธ ๊ฐ๋ฐ ๋ฐฐ์ฐ๊ธฐ
์ฌ๊ธฐ๊น์ง ๋ฐ๋ผ์๋ค๋ฉด ์ ๋ง ๋๋จํด! ๐ ํ์ง๋ง ํผ์ ๊ณต๋ถํ๋ค ๋งํ๋ ๋ถ๋ถ์ด ์์ ์ ์์์? ๊ทธ๋ด ๋๋ ์ฌ๋ฅ๋ท์ ํ์ฉํด๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ!์ฌ๋ฅ๋ท(https://www.jaenung.net)์๋ ๋ธ๋ก์ฒด์ธ ๊ฐ๋ฐ, ํ์ด์ฌ ํ๋ก๊ทธ๋๋ฐ, ๋ฐ์ดํฐ ๋ถ์ ๋ฑ ๋ค์ํ ๋ถ์ผ์ ์ ๋ฌธ๊ฐ๋ค์ด ์์ด. 1:1 ๋ฉํ ๋ง์ ๋ฐ๊ฑฐ๋, ํ๋ก์ ํธ๋ฅผ ์๋ขฐํ๊ฑฐ๋, ํจ๊ป ๊ณต๋ถํ ์คํฐ๋ ๊ทธ๋ฃน์ ์ฐพ์ ์๋ ์์ง! ๐
ํนํ ๋ธ๋ก์ฒด์ธ ๋ถ์ผ๋ ๋น ๋ฅด๊ฒ ๋ณํํ๊ธฐ ๋๋ฌธ์ ์ค๋ฌด ๊ฒฝํ์ด ์๋ ์ ๋ฌธ๊ฐ์ ์กฐ์ธ์ด ์ ๋ง ์ค์ํด. ์ฌ๋ฅ๋ท์์ ์์ ์๊ฒ ๋ง๋ ๋ฉํ ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ข์ ์ ํ์ด ๋ ๊ฑฐ์ผ! ๐ช
๐ ๋ ๋์๊ฐ๊ธฐ
๊ธฐ๋ณธ์ ์ธ ๋ธ๋ก์ฒด์ธ ๋ถ์ ํ๋ก๊ทธ๋จ์ ๋ง๋ค ์ ์๊ฒ ๋๋ค๋ฉด, ์ด์ ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ๋์ ํด๋ณผ ์ฐจ๋ก์ผ! ๐๐ ์ถ๊ฐ ํ์ต ์ฃผ์
๐ค ๋จธ์ ๋ฌ๋ ์ ์ฉ
๊ฑฐ๋ ํจํด์ ํ์ตํด์ ์ด์๊ฑฐ๋๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ๊ฑฐ๋, ๊ฐ๊ฒฉ ์์ธก ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณผ ์ ์์ด. scikit-learn์ด๋ TensorFlow๋ฅผ ํ์ฉํด๋ณด์!
๊ฑฐ๋ ํจํด์ ํ์ตํด์ ์ด์๊ฑฐ๋๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ๊ฑฐ๋, ๊ฐ๊ฒฉ ์์ธก ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณผ ์ ์์ด. scikit-learn์ด๋ TensorFlow๋ฅผ ํ์ฉํด๋ณด์!
๐ ๋์๋ณด๋ ๊ตฌ์ถ
Streamlit์ด๋ Dash๋ฅผ ์ฌ์ฉํด์ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ๋์๋ณด๋๋ฅผ ๋ง๋ค์ด๋ด. ์น ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ํ์ธํ ์ ์์ด์ ํธ๋ฆฌํด!
Streamlit์ด๋ Dash๋ฅผ ์ฌ์ฉํด์ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ๋์๋ณด๋๋ฅผ ๋ง๋ค์ด๋ด. ์น ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ํ์ธํ ์ ์์ด์ ํธ๋ฆฌํด!
๐ ๋ฉํฐ์ฒด์ธ ์ง์
์ด๋๋ฆฌ์๋ฟ๋ง ์๋๋ผ BSC, Polygon, Avalanche ๋ฑ ๋ค์ํ ์ฒด์ธ์ ๋์์ ๋ชจ๋ํฐ๋งํ๋ ์์คํ ์ผ๋ก ํ์ฅํด๋ณด์!
์ด๋๋ฆฌ์๋ฟ๋ง ์๋๋ผ BSC, Polygon, Avalanche ๋ฑ ๋ค์ํ ์ฒด์ธ์ ๋์์ ๋ชจ๋ํฐ๋งํ๋ ์์คํ ์ผ๋ก ํ์ฅํด๋ณด์!
๐ฌ ์๋ฆผ ์์คํ
ํ ๋ ๊ทธ๋จ ๋ด, ๋์ค์ฝ๋ ์นํ , ์ด๋ฉ์ผ ๋ฑ ๋ค์ํ ์๋ฆผ ์ฑ๋์ ์ฐ๋ํด์ ์ค์ํ ์ด๋ฒคํธ๋ฅผ ๋์น์ง ์๋๋ก ํ์!
ํ ๋ ๊ทธ๋จ ๋ด, ๋์ค์ฝ๋ ์นํ , ์ด๋ฉ์ผ ๋ฑ ๋ค์ํ ์๋ฆผ ์ฑ๋์ ์ฐ๋ํด์ ์ค์ํ ์ด๋ฒคํธ๋ฅผ ๋์น์ง ์๋๋ก ํ์!
๐ ๏ธ ์ ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๋๊ตฌ
| ๋ผ์ด๋ธ๋ฌ๋ฆฌ/๋๊ตฌ | ์ฉ๋ | ํน์ง |
|---|---|---|
| Web3.py | ์ด๋๋ฆฌ์ ์ํธ์์ฉ | ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๊ณ ํ์์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ |
| Brownie | ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐ | ํ ์คํธ์ ๋ฐฐํฌ๊ฐ ์ฌ์ด ํ๋ ์์ํฌ |
| The Graph | ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ ์ฟผ๋ฆฌ | GraphQL๋ก ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์กฐํ |
| Dune Analytics | ๋ฐ์ดํฐ ๋ถ์ ํ๋ซํผ | SQL๋ก ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ ๋ถ์ |
| Alchemy | ๋ธ๋ก์ฒด์ธ API | Infura์ ๊ฐ๋ ฅํ ๋์ |
| Moralis | Web3 ๋ฐฑ์๋ | NFT, DeFi ๋ฐ์ดํฐ ์ฝ๊ฒ ์กฐํ |
๐ก ์ค์ ํ & ๋ฒ ์คํธ ํ๋ํฐ์ค
๋ง์ง๋ง์ผ๋ก ์ค์ ํ๋ก์ ํธ๋ฅผ ์งํํ ๋ ๊ผญ ์์์ผ ํ ํ๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ! ๐ฏ
1๏ธโฃ ์๊ฒ ์์ํ๊ณ ์ ์ง์ ์ผ๋ก ํ์ฅ
์ฒ์๋ถํฐ ์๋ฒฝํ ์์คํ ์ ๋ง๋ค๋ ค๊ณ ํ์ง ๋ง! ๋จผ์ ๋จ์ํ ๊ธฐ๋ฅ๋ถํฐ ๊ตฌํํ๊ณ , ์ ๋์ํ๋์ง ํ์ธํ ํ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํด๋๊ฐ๋ ๊ฒ ์ข์.
์ฒ์๋ถํฐ ์๋ฒฝํ ์์คํ ์ ๋ง๋ค๋ ค๊ณ ํ์ง ๋ง! ๋จผ์ ๋จ์ํ ๊ธฐ๋ฅ๋ถํฐ ๊ตฌํํ๊ณ , ์ ๋์ํ๋์ง ํ์ธํ ํ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํด๋๊ฐ๋ ๊ฒ ์ข์.
2๏ธโฃ ํ
์คํธ๋ท์์ ์ถฉ๋ถํ ํ
์คํธ
๋ฉ์ธ๋ท์์ ๋ฐ๋ก ํ ์คํธํ๋ฉด ์ค์ ๊ฐ์ค๋น๊ฐ ๋๊ฐ! Goerli, Sepolia ๊ฐ์ ํ ์คํธ๋ท์์ ์ถฉ๋ถํ ํ ์คํธํ ํ์ ๋ฉ์ธ๋ท์ผ๋ก ์ฎ๊ธฐ์.
๋ฉ์ธ๋ท์์ ๋ฐ๋ก ํ ์คํธํ๋ฉด ์ค์ ๊ฐ์ค๋น๊ฐ ๋๊ฐ! Goerli, Sepolia ๊ฐ์ ํ ์คํธ๋ท์์ ์ถฉ๋ถํ ํ ์คํธํ ํ์ ๋ฉ์ธ๋ท์ผ๋ก ์ฎ๊ธฐ์.
3๏ธโฃ ์ฝ๋ ๋ฌธ์ํ๋ ํ์
๋์ค์ ์ฝ๋๋ฅผ ๋ค์ ๋ณผ ๋ ๋ฌด์จ ์๋ฏธ์ธ์ง ๋ชจ๋ฅผ ์ ์์ด. ์ฃผ์๊ณผ docstring์ ๊ผผ๊ผผํ๊ฒ ์์ฑํ๋ ์ต๊ด์ ๋ค์ด์!
๋์ค์ ์ฝ๋๋ฅผ ๋ค์ ๋ณผ ๋ ๋ฌด์จ ์๋ฏธ์ธ์ง ๋ชจ๋ฅผ ์ ์์ด. ์ฃผ์๊ณผ docstring์ ๊ผผ๊ผผํ๊ฒ ์์ฑํ๋ ์ต๊ด์ ๋ค์ด์!
4๏ธโฃ ๋ณด์์ ์ต์ฐ์ ์ผ๋ก
API ํค, ํ๋ผ์ด๋น ํค ๋ฑ ๋ฏผ๊ฐํ ์ ๋ณด๋ ์ ๋ ์ฝ๋์ ํ๋์ฝ๋ฉํ์ง ๋ง๊ณ , ํ๊ฒฝ๋ณ์๋ ๋ณ๋์ ์ค์ ํ์ผ๋ก ๊ด๋ฆฌํด์ผ ํด.
API ํค, ํ๋ผ์ด๋น ํค ๋ฑ ๋ฏผ๊ฐํ ์ ๋ณด๋ ์ ๋ ์ฝ๋์ ํ๋์ฝ๋ฉํ์ง ๋ง๊ณ , ํ๊ฒฝ๋ณ์๋ ๋ณ๋์ ์ค์ ํ์ผ๋ก ๊ด๋ฆฌํด์ผ ํด.
5๏ธโฃ ์ปค๋ฎค๋ํฐ ํ์ฉ
Stack Overflow, Reddit, Discord ๋ฑ์์ ํ๋ฐํ๊ฒ ์ง๋ฌธํ๊ณ ๋ต๋ณํ๋ฉด์ ๋ฐฐ์ฐ์. ํผ์ ๊ณ ๋ฏผํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋น ๋ฅด๊ฒ ์ฑ์ฅํ ์ ์์ด!
Stack Overflow, Reddit, Discord ๋ฑ์์ ํ๋ฐํ๊ฒ ์ง๋ฌธํ๊ณ ๋ต๋ณํ๋ฉด์ ๋ฐฐ์ฐ์. ํผ์ ๊ณ ๋ฏผํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋น ๋ฅด๊ฒ ์ฑ์ฅํ ์ ์์ด!
๐ฌ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ด! ๐ ํ์ด์ฌ์ผ๋ก ๋ธ๋ก์ฒด์ธ ๊ฑฐ๋๋ด์ญ์ ๋ถ์ํ๋ ํ๋ก๊ทธ๋จ์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ฒ์๋ถํฐ ๋๊น์ง ์ดํด๋ดค์ด.์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ๋ด์ฉ์ ์ ๋ฆฌํด๋ณด๋ฉด:
โ Web3.py๋ก ๋ธ๋ก์ฒด์ธ ๋ฐ์ดํฐ ์์ง
โ Pandas๋ก ๋ฐ์ดํฐ ๋ถ์ ๋ฐ ์๊ฐํ
โ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ์์คํ ๊ตฌ์ถ
โ ์ค๋งํธ ์ปจํธ๋ํธ ์ํธ์์ฉ
โ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ฉ ๋ฐ ์ต์ ํ
โ ์ค์ ํ๋ก์ ํธ ๊ตฌํ
์ด์ ๋๋ง์ ๋ธ๋ก์ฒด์ธ ๋ถ์ ๋๊ตฌ๋ฅผ ๋ง๋ค ์ ์๋ ๊ธฐ์ด๋ ๋ค ๊ฐ์ถฐ์ก์ด! ๋ฌผ๋ก ์ฒ์์๋ ์ด๋ ค์ธ ์ ์์ง๋ง, ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ๋ผํ๋ค ๋ณด๋ฉด ์ด๋์ ๋ฉ์ง ํ๋ก๊ทธ๋จ์ ๋ง๋ค๊ณ ์๋ ์์ ์ ๋ฐ๊ฒฌํ๊ฒ ๋ ๊ฑฐ์ผ. ๐ช
๋ธ๋ก์ฒด์ธ ๊ธฐ์ ์ ๊ณ์ ๋ฐ์ ํ๊ณ ์๊ณ , ์๋ก์ด ๊ธฐํ๋ค์ด ๋์์์ด ์๊ฒจ๋๊ณ ์์ด. ์ด ๊ธ์์ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์์ ๋ง์ ํ๋ก์ ํธ๋ฅผ ์์ํด๋ณด๋ ๊ฑด ์ด๋? ๐
ํน์ ๋งํ๋ ๋ถ๋ถ์ด ์๊ฑฐ๋ ๋ ๊น์ด ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. ํจ๊ป ์ฑ์ฅํ๋ ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ์์ ๋ง์ ๊ฒ์ ๋ฐฐ์ธ ์ ์์ ๊ฑฐ์ผ!
์, ์ด์ ์ง์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์คํํด๋ณผ ์๊ฐ์ด์ผ! ํ์ด์ ๋น์ด! ๐โจ
๐ Happy Coding!
๋ธ๋ก์ฒด์ธ์ ์ธ๊ณ๋ ๋ฌด๊ถ๋ฌด์งํด!
๊ณ์ ํํํ๊ณ ๋ฐฐ์ฐ๋ฉด์ ์ฑ์ฅํ์! ๐
๊ด๋ จ ํค์๋
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.

๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.