Skip to content

Commit 7f9914e

Browse files
committed
ch4. ethereum smart contract
1 parent 36b4b64 commit 7f9914e

7 files changed

+932
-0
lines changed

ch4_eth_smartContract/NFTWallet.ipynb

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"from flask import Flask\n",
10+
"from flask import render_template\n",
11+
"from flask import request\n",
12+
"\n",
13+
"import requests\n",
14+
"import json\n",
15+
"import os"
16+
]
17+
},
18+
{
19+
"cell_type": "code",
20+
"execution_count": null,
21+
"metadata": {},
22+
"outputs": [],
23+
"source": [
24+
"# Flask 앱 선언\n",
25+
"app = Flask(__name__, template_folder=os.getcwd())"
26+
]
27+
},
28+
{
29+
"cell_type": "markdown",
30+
"metadata": {},
31+
"source": [
32+
"NFT Wallet 사이트\n",
33+
"첫 접속시에는 NFT_Wallet_login.html 파일을 랜더링\n",
34+
"POST 방식으로 NFT의 스마트컨트랙트 주소를 입력한 경우,\n",
35+
"> 알맞은 지갑주소일 경우 NFT_Wallet.html 파일 랜더링\n",
36+
"> 잘못된 지갑주소일 경우 에러 메시지 띄움"
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"metadata": {},
43+
"outputs": [],
44+
"source": [
45+
"@app.route('/', methods=['GET', 'POST'])\n",
46+
"def login():\n",
47+
" if request.method=='POST':\n",
48+
" \n",
49+
" contract_address = request.form.to_dict(flat=False)['smart_contract_addr'][0] \n",
50+
" print(contract_address)\n",
51+
" # 블록 정보 호출\n",
52+
" headers = {'Content-Type' : 'application/json; charset=utf-8'}\n",
53+
" res = requests.get(\"http://localhost:5000/chain\", headers=headers)\n",
54+
" res_json = json.loads(res.content)\n",
55+
" nft_TF = False\n",
56+
" ## 스마트 컨트랙트를 호출 및 실행\n",
57+
" for _block in res_json['chain']:\n",
58+
" for _tx in _block['transactions']:\n",
59+
" if _tx['smart_contract']['contract_address'] == contract_address:\n",
60+
" exec( _tx['smart_contract']['contract_code']) \n",
61+
" nft_TF = True\n",
62+
" break\n",
63+
" if nft_TF:\n",
64+
"# print(myNFT)\n",
65+
" return render_template(\"NFT_Wallet.html\", \n",
66+
" nft_name = _tx['smart_contract']['contract_code'].split(\"'\")[3], \n",
67+
" nft_img_url = _tx['smart_contract']['contract_code'].split(\"'\")[7],\n",
68+
" nft_addresss = contract_address\n",
69+
" )\n",
70+
" else:\n",
71+
" return \"잘못된 지갑주소입니다.\"\n",
72+
"\n",
73+
" \n",
74+
" return render_template('NFT_Wallet_login.html')\n",
75+
"app.run(port=8082)"
76+
]
77+
}
78+
],
79+
"metadata": {
80+
"language_info": {
81+
"name": "python"
82+
}
83+
},
84+
"nbformat": 4,
85+
"nbformat_minor": 2
86+
}

ch4_eth_smartContract/NFT_Wallet.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<h1><center> pyETH NFT Wallet </center> </h1>
2+
3+
<div>
4+
<div align="center">NFT NAME : {{nft_name}}</div><br>
5+
<div align="center">NFT Address : {{nft_addresss}}</div><br>
6+
<div align="center"><img src = {{nft_img_url}} align="center"></div>
7+
8+
</div>
9+
10+
<hr>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<h1><center> pyETH NFT Wallet </center> </h1>
2+
3+
<form action="/" method="POST">
4+
<div class="form-group">
5+
<input type="text" name="smart_contract_addr" placeholder="NFT의 스마트컨트랙트 주소를 입력해주세요!" size="80">
6+
</div>
7+
<div class="form-group">
8+
<input type="submit" value="확인" />
9+
</div>
10+
</form>
11+
12+
<hr>
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"스마트 컨트렉트 내의 텍스트를 코드로 인식하여 실행해야 하는데 이때 exec 함수가 동작한다\n",
8+
"블록 조회로 스마트 컨트렉트 내용 확인 가능\n",
9+
"해당 블록 내에서 우리가 저장한 스마트 컨트렉트의 주소로 스마트 컨트렉트 코드를 찾은 뒤 해당 코드를 exec 함수를 통해 실행"
10+
]
11+
},
12+
{
13+
"cell_type": "code",
14+
"execution_count": null,
15+
"metadata": {},
16+
"outputs": [],
17+
"source": [
18+
"def func_add(a,b):\n",
19+
" return a+b\n",
20+
"\n",
21+
"print(func_add(3,5))"
22+
]
23+
}
24+
],
25+
"metadata": {
26+
"language_info": {
27+
"name": "python"
28+
}
29+
},
30+
"nbformat": 4,
31+
"nbformat_minor": 2
32+
}

ch4_eth_smartContract/node.ipynb

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"블록체인 객체 속 smart contract 부분 추가"
8+
]
9+
},
10+
{
11+
"cell_type": "code",
12+
"execution_count": null,
13+
"metadata": {},
14+
"outputs": [],
15+
"source": [
16+
"import hashlib # hash 함수용 sha256 사용할 라이브러리\n",
17+
"import json\n",
18+
"from time import time\n",
19+
"import random\n",
20+
"import requests\n",
21+
"from flask import Flask, request, jsonify\n",
22+
"import datetime"
23+
]
24+
},
25+
{
26+
"cell_type": "code",
27+
"execution_count": null,
28+
"metadata": {},
29+
"outputs": [],
30+
"source": [
31+
"class Blockchain(object):\n",
32+
" \n",
33+
" def __init__(self):\n",
34+
" self.chain = [] # chain에 여러 block들 들어옴\n",
35+
" self.current_transaction = [] # 임시 transaction 넣어줌\n",
36+
" self.nodes = set() # Node 목록을 보관\n",
37+
" self.new_block(previous_hash=1, proof=100) # genesis block 생성\n",
38+
"\n",
39+
" @staticmethod\n",
40+
" def hash(block):\n",
41+
" block_string = json.dumps(block, sort_keys=True).encode() \n",
42+
" return hashlib.sha256(block_string).hexdigest() # hash 라이브러리로 sha256 사용\n",
43+
" @property\n",
44+
" def last_block(self):\n",
45+
" return self.chain[-1] # 체인의 마지막 블록 가져오기!!\n",
46+
"\n",
47+
" @staticmethod\n",
48+
" def valid_proof(last_proof, proof):\n",
49+
" guess = str(last_proof + proof).encode() # 전 proof와 구할 proof 문자열 연결\n",
50+
" guess_hash = hashlib.sha256(guess).hexdigest() # 이 hash 값 저장\n",
51+
" return guess_hash[:4] == \"0000\" # 앞 4자리가 0000 이면 True (알맞은 nonce값을 찾음)\n",
52+
"\n",
53+
" def pow(self, last_proof):\n",
54+
" proof = random.randint(-1000000,1000000)\n",
55+
" while self.valid_proof(last_proof, proof) is False: # valid proof 함수 활용(아래 나옴), 맞을 때까지 반복적으로 검증\n",
56+
" proof = random.randint(-1000000,1000000)\n",
57+
" return proof\n",
58+
"\n",
59+
" def new_transaction(self, sender, recipient, amount, smart_contract):\n",
60+
" self.current_transaction.append(\n",
61+
" {\n",
62+
" 'sender' : sender, # 송신자\n",
63+
" 'recipient' : recipient, # 수신자\n",
64+
" 'amount' : amount, # 금액\n",
65+
" 'timestamp':time(),\n",
66+
" 'smart_contract' : smart_contract\n",
67+
" }\n",
68+
" )\n",
69+
" return self.last_block['index'] + 1 \n",
70+
"\n",
71+
" def new_block(self, proof, previous_hash=None):\n",
72+
" block = {\n",
73+
" 'index' : len(self.chain)+1,\n",
74+
" 'timestamp' : time(), # timestamp from 1970\n",
75+
" 'transactions' : self.current_transaction,\n",
76+
" 'nonce' : proof,\n",
77+
" 'previous_hash' : previous_hash or self.hash(self.chain[-1]),\n",
78+
" }\n",
79+
" block['hash'] = self.hash(block)\n",
80+
" self.current_transaction = []\n",
81+
" self.chain.append(block) \n",
82+
" return block\n",
83+
"\n",
84+
" def valid_chain(self, chain):\n",
85+
" last_block = chain[0] \n",
86+
" current_index = 1\n",
87+
"\n",
88+
" while current_index < len(chain): \n",
89+
" block = chain[current_index]\n",
90+
" \n",
91+
" print('%s' % last_block)\n",
92+
" print('%s' % block)\n",
93+
" print(\"\\n--------\\n\")\n",
94+
" if block['previous_hash'] != self.hash(last_block):\n",
95+
" return False\n",
96+
" \n",
97+
" block_copy = block.copy()\n",
98+
" block_copy.pop('hash')\n",
99+
" if block['hash'] != self.hash(block_copy):\n",
100+
" return False\n",
101+
" \n",
102+
" last_block = block\n",
103+
" current_index += 1\n",
104+
" return True"
105+
]
106+
},
107+
{
108+
"cell_type": "markdown",
109+
"metadata": {},
110+
"source": [
111+
"블록체인 객체 기반 노드 생성"
112+
]
113+
},
114+
{
115+
"cell_type": "code",
116+
"execution_count": null,
117+
"metadata": {},
118+
"outputs": [],
119+
"source": [
120+
"blockchain = Blockchain()\n",
121+
"my_ip = '0.0.0.0'\n",
122+
"my_port = '5000'\n",
123+
"node_identifier = 'node_'+my_port\n",
124+
"mine_owner = 'master'\n",
125+
"mine_profit = 0.1"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": null,
131+
"metadata": {},
132+
"outputs": [],
133+
"source": [
134+
"app = Flask(__name__)\n",
135+
"\n",
136+
"@app.route('/chain', methods=['GET'])\n",
137+
"def full_chain():\n",
138+
" print(\"chain info requested!!\")\n",
139+
" response = {\n",
140+
" 'chain' : blockchain.chain, \n",
141+
" 'length' : len(blockchain.chain), \n",
142+
" }\n",
143+
" return jsonify(response), 200\n",
144+
"\n",
145+
"@app.route('/transactions/new', methods=['POST'])\n",
146+
"def new_transaction():\n",
147+
" values = request.get_json() \n",
148+
" print(\"transactions_new!!! : \", values)\n",
149+
" required = ['sender', 'recipient', 'amount','smart_contract'] ## 송신자(sender), 수신자(recipient), 금액(amount),의 존재여부 만 확인에 더하여 스마트컨트랙트(smart_contract)의 존재여부 확인\n",
150+
"\n",
151+
" if not all(k in values for k in required):\n",
152+
" return 'missing values', 400\n",
153+
" contract_address = hashlib.sha256(str(datetime.datetime.now()).encode() ).hexdigest()\n",
154+
" values['smart_contract'][\"contract_address\"] = contract_address ## 거래의 스마트 컨트랙트에 대한 컨트랙트 주소(contract_address)를 부여\n",
155+
"\n",
156+
"\n",
157+
" index = blockchain.new_transaction(values['sender'],values['recipient'],\n",
158+
"values['amount'], values['smart_contract']) \n",
159+
" \n",
160+
" response = {'message' : 'Transaction will be added to Block {%s}' % index, \"contract_address\":contract_address}\n",
161+
" return jsonify(response), 201\n",
162+
"\n",
163+
"\n",
164+
"@app.route('/mine', methods=['GET'])\n",
165+
"def mine():\n",
166+
" print(\"MINING STARTED\") \n",
167+
" last_block = blockchain.last_block\n",
168+
" last_proof = last_block['nonce']\n",
169+
" proof = blockchain.pow(last_proof) \n",
170+
"\n",
171+
" blockchain.new_transaction(\n",
172+
" sender=mine_owner, \n",
173+
" recipient=node_identifier, \n",
174+
" amount=mine_profit, # coinbase transaction \n",
175+
" smart_contract={\"contract_address\":\"mining_profit\"}, \n",
176+
" )\n",
177+
" \n",
178+
" previous_hash = blockchain.hash(last_block)\n",
179+
" block = blockchain.new_block(proof, previous_hash)\n",
180+
" print(\"MINING FINISHED\")\n",
181+
"\n",
182+
" response = {\n",
183+
" 'message' : 'new block found',\n",
184+
" 'index' : block['index'],\n",
185+
" 'transactions' : block['transactions'],\n",
186+
" 'nonce' : block['nonce'],\n",
187+
" 'previous_hash' : block['previous_hash'],\n",
188+
" 'hash' : block['hash']\n",
189+
" }\n",
190+
" \n",
191+
" return jsonify(response), 200\n",
192+
"\n",
193+
"\n",
194+
"if __name__ == '__main__':\n",
195+
" app.run(host=my_ip, port=my_port)"
196+
]
197+
}
198+
],
199+
"metadata": {
200+
"language_info": {
201+
"name": "python"
202+
}
203+
},
204+
"nbformat": 4,
205+
"nbformat_minor": 2
206+
}

0 commit comments

Comments
 (0)