def main(): k_m = KeyManager() um = UTXOManager(k_m.my_address()) i_k_m = KeyManager() u_k_m = KeyManager() t1 = CoinbaseTransaction(k_m.my_address()) t2 = CoinbaseTransaction(k_m.my_address()) t3 = CoinbaseTransaction(k_m.my_address()) t4 = Transaction([TransactionInput(t1.to_dict(), 0)], [ TransactionOutput(u_k_m.my_address(), 10.0), TransactionOutput(i_k_m.my_address(), 20.0) ]) transactions = [] transactions.append(t1.to_dict()) transactions.append(t2.to_dict()) transactions.append(t3.to_dict()) transactions.append(t4.to_dict()) um.extract_utxos(transactions) balance = um.my_balance print(balance)
class SimpleBC_Gui(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.parent.protocol('WM_DELETE_WINDOW', self.quit) self.coin_balance = StringVar(self.parent, '0') self.status_message = StringVar(self.parent, 'Ready') self.initApp() self.setupGUI() def quit(self, event=None): """ アプリの終了 """ self.parent.destroy() def initApp(self): """ ClientCoreとの接続含めて必要な初期化処理はここで実行する """ print('SimpleBitcoin client is now activating ...: ') self.km = KeyManager() self.um = UTXOManager(self.km.my_address()) # テスト用途(本来はこんな処理しない) t1 = CoinbaseTransaction(self.km.my_address()) t2 = CoinbaseTransaction(self.km.my_address()) t3 = CoinbaseTransaction(self.km.my_address()) transactions = [] transactions.append(t1.to_dict()) transactions.append(t2.to_dict()) transactions.append(t3.to_dict()) self.um.extract_utxos(transactions) self.update_balance() def display_info(self, title, info): """ ダイアログボックスを使ったメッセージの表示 """ f = Tk() label = Label(f, text=title) label.pack() info_area = Text(f, width=70, height=50) info_area.insert(INSERT, info) info_area.pack() def update_status(self, info): """ 画面下部のステータス表示内容を変更する """ self.status_message.set(info) def update_balance(self): """ 総額表示の内容を最新状態に合わせて変更する """ bal = str(self.um.my_balance) self.coin_balance.set(bal) def create_menu(self): """ メニューバーに表示するメニューを定義する """ top = self.winfo_toplevel() self.menuBar = Menu(top) top['menu'] = self.menuBar self.subMenu = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label='Menu', menu=self.subMenu) self.subMenu.add_command(label='Show My Address', command=self.show_my_address) self.subMenu.add_command( label='Load my Keys', command=self.show_input_dialog_for_key_loading) self.subMenu.add_command(label='Update Blockchain', command=self.update_block_chain) self.subMenu.add_separator() self.subMenu.add_command(label='Quit', command=self.quit) self.subMenu2 = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label='Settings', menu=self.subMenu2) self.subMenu2.add_command(label='Renew my Keys', command=self.renew_my_keypairs) self.subMenu2.add_command(label='Connection Info', command=self.edit_conn_info) self.subMenu3 = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label='Advance', menu=self.subMenu3) self.subMenu3.add_command(label='Show logs', command=self.open_log_window) self.subMenu3.add_command(label='Show Blockchain', command=self.show_my_block_chain) def show_my_address(self): f = Tk() label = Label(f, text='My Address') label.pack() key_info = Text(f, width=70, height=10) my_address = self.km.my_address() key_info.insert(INSERT, my_address) key_info.pack() def show_input_dialog_for_key_loading(self): def load_my_keys(): # ファイル選択ダイアログの表示 f2 = Tk() f2.withdraw() fTyp = [("", "*.pem")] iDir = os.path.abspath(os.path.dirname(__file__)) messagebox.showinfo('Load key pair', 'please choose your key file') f_name = filedialog.askopenfilename(filetypes=fTyp, initialdir=iDir) try: file = open(f_name) data = file.read() target = binascii.unhexlify(data) # TODO: 本来は鍵ペアのファイルが不正などの異常系処理を考えるべき self.km.import_key_pair(target, p_phrase.get()) except Exception as e: print(e) finally: file.close() f.destroy() f2.destroy() self.um = UTXOManager(self.km.my_address()) self.um.my_balance = 0 self.update_balance() f = Tk() label0 = Label(f, text='Please enter pass phrase for your key pair') frame1 = ttk.Frame(f) label1 = ttk.Label(frame1, text='Pass Phrase:') p_phrase = StringVar() entry1 = ttk.Entry(frame1, textvariable=p_phrase) button1 = ttk.Button(frame1, text='Load', command=load_my_keys) label0.grid(row=0, column=0, sticky=(N, E, S, W)) frame1.grid(row=1, column=0, sticky=(N, E, S, W)) label1.grid(row=2, column=0, sticky=E) entry1.grid(row=2, column=1, sticky=W) button1.grid(row=3, column=1, sticky=W) def update_block_chain(self): pass def renew_my_keypairs(self): """ 利用する鍵ペアを更新する。 """ def save_my_pem(): self.km = KeyManager() my_pem = self.km.export_key_pair(p_phrase.get()) my_pem_hex = binascii.hexlify(my_pem).decode('ascii') # とりあえずファイル名は固定 path = 'my_key_pair.pem' f1 = open(path, 'a') f1.write(my_pem_hex) f1.close() f.destroy() self.um = UTXOManager(self.km.my_address()) self.um.my_balance = 0 self.update_balance() f = Tk() f.title('New Key Gene') label0 = Label(f, text='Please enter pass phrase for your new key pair') frame1 = ttk.Frame(f) label1 = ttk.Label(frame1, text='Pass Phrase:') p_phrase = StringVar() entry1 = ttk.Entry(frame1, textvariable=p_phrase) button1 = ttk.Button(frame1, text='Generate', command=save_my_pem) label0.grid(row=0, column=0, sticky=(N, E, S, W)) frame1.grid(row=1, column=0, sticky=(N, E, S, W)) label1.grid(row=2, column=0, sticky=E) entry1.grid(row=2, column=1, sticky=W) button1.grid(row=3, column=1, sticky=W) def edit_conn_info(self): """ Coreノードへの接続情報の編集 """ pass def open_log_window(self): """ 別ウィンドウでログ情報を表示する。デバッグ用 """ pass def show_my_block_chain(self): """ 自分が保持しているブロックチェーンの中身を確認する """ pass def setupGUI(self): """ 画面に必要なパーツを並べる """ self.parent.bind('<Control-q>', self.quit) self.parent.title("SimpleBitcoin GUI") self.pack(fill=BOTH, expand=1) self.create_menu() lf = LabelFrame(self, text='Current Balance') lf.pack(side=TOP, fill='both', expand='yes', padx=7, pady=7) lf2 = LabelFrame(self, text="") lf2.pack(side=BOTTOM, fill='both', expand='yes', padx=7, pady=7) #所持コインの総額表示領域のラベル self.balance = Label(lf, textvariable=self.coin_balance, font='Helvetica 20') self.balance.pack() #受信者となる相手の公開鍵 self.label = Label(lf2, text='Recipient Address:') self.label.grid(row=0, pady=5) self.recipient_pubkey = Entry(lf2, bd=2) self.recipient_pubkey.grid(row=0, column=1, pady=5) # 送金額 self.label2 = Label(lf2, text='Amount to pay :') self.label2.grid(row=1, pady=5) self.amountBox = Entry(lf2, bd=2) self.amountBox.grid(row=1, column=1, pady=5, sticky='NSEW') # 手数料 self.label3 = Label(lf2, text='Fee (Optional) :') self.label3.grid(row=2, pady=5) self.feeBox = Entry(lf2, bd=2) self.feeBox.grid(row=2, column=1, pady=5, sticky='NSEW') # 間隔の開け方がよくわからんので空文字で場所確保 self.label4 = Label(lf2, text='') self.label4.grid(row=3, pady=5) # 送金実行ボタン self.sendBtn = Button(lf2, text='\nSend Coin(s)\n', command=self.sendCoins) self.sendBtn.grid(row=4, column=1, sticky='NSEW') # 下部に表示するステータスバー stbar = Label(self.winfo_toplevel(), textvariable=self.status_message, bd=1, relief=SUNKEN, anchor=W) stbar.pack(side=BOTTOM, fill=X) # 送金実行ボタン押下時の処理実体 def sendCoins(self): sendAtp = self.amountBox.get() recipientKey = self.recipient_pubkey.get() sendFee = self.feeBox.get() if not sendAtp: messagebox.showwarning('Warning', 'Please enter the Amount to pay.') elif len(recipientKey) <= 1: messagebox.showwarning('Warning', 'Please enter the Recipient Address.') elif not sendFee: sendFee = 0 else: result = messagebox.askyesno( 'Confirmation', 'Sending {} SimpleBitcoins to :\n {}'.format( sendAtp, recipientKey)) if result: if 0 < len(self.um.utxo_txs): print('Sending {} SimpleBitcoins to reciever:\n {}'.format( sendAtp, recipientKey)) else: messagebox.showwarning('Short of Coin.', 'Not enough coin to be sent...') return utxo, idx = self.um.get_utxo_tx(0) t = Transaction([TransactionInput(utxo, idx)], [TransactionOutput(recipientKey, sendAtp)]) counter = 1 # TransactionInputが送信額を超えるまで繰り返して取得しTransactionとして完成させる while t.is_enough_inputs(sendFee) is not True: new_utxo, new_idx = self.um.get_utxo_tx(counter) t.inputs.append(TransactionInput(new_utxo, new_idx)) counter += 1 if counter > len(self.um.utxo_txs): messagebox.showwarning('Short of Coin.', 'Not enough coin to be sent...') break # 正常なTransactionが生成できた時だけ秘密鍵で署名を実行する if t.is_enough_inputs(sendFee) is True: # まずお釣り用Transactionを作る change = t.compute_change(sendFee) t.outputs.append( TransactionOutput(self.km.my_address(), change)) to_be_signed = json.dumps(t.to_dict(), sort_keys=True) signed = self.km.compute_digital_signature(to_be_signed) new_tx = json.loads(to_be_signed) new_tx['signature'] = signed # TODO: 本来はここで出来上がったTransactionを送信する処理を入れる print('signed new_tx:', json.dumps(new_tx)) # 実験的にお釣り分の勘定のため新しく生成したTransactionをUTXOとして追加しておくが # 本来はブロックチェーンの更新に合わせて再計算した方が適切 self.um.put_utxo_tx(t.to_dict()) to_be_deleted = 0 del_list = [] while to_be_deleted < counter: del_tx = self.um.get_utxo_tx(to_be_deleted) del_list.append(del_tx) to_be_deleted += 1 for dx in del_list: self.um.remove_utxo_tx(dx) self.amountBox.delete(0, END) self.feeBox.delete(0, END) self.recipient_pubkey.delete(0, END) self.update_balance()