-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwallet.py
More file actions
99 lines (84 loc) · 4.04 KB
/
wallet.py
File metadata and controls
99 lines (84 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# pyncoin/wallet.py
''' Implements the pyncoin wallet, a high-level user interface for pyncoin transactions. '''
import os
from decimal import Decimal
import ecdsa
from transaction import Transaction, TxIn, TxOut
from utils import UnauthorizedError
class Wallet:
def __init__(self, private_key_location):
''' Initializes the wallet.
Params:
- private_key_location (str): The location of the private key PEM file. If the
private key file is not found in the given location, a new key will be
generated and saved to the same location.
'''
self.private_key = None
try:
with open(private_key_location, 'rb') as pk_file:
pk_bin = pk_file.read()
self.private_key = ecdsa.SigningKey.from_pem(pk_bin)
except FileNotFoundError:
print('private key file not found')
if not self.private_key:
print('generating private key...')
self.private_key = ecdsa.SigningKey.generate()
pk_bin = self.private_key.to_pem()
print('saving private key...')
dir_name = os.path.dirname(private_key_location)
if not os.path.exists(dir_name):
os.makedirs(dir_name)
with open(private_key_location, 'wb') as pk_file:
pk_file.write(pk_bin)
def get_public_key(self):
''' Returns the public key of this wallet.
Returns (bytes): The raw public key of this wallet.
'''
public_key = self.private_key.get_verifying_key()
return public_key.to_string()
def get_private_key(self):
return self.private_key.to_string()
def get_balance(self, unspent_tx_outs):
''' Gets the balance of a given address.
Params:
- address (bytes): The address of the wallet
- unspent_tx_outs (list<transaction.UnspentTxOut>): The current unspent
transaction outputs of the blockchain
Returns (Decimal): The balance of the given address
'''
return sum([uTxO.amount for uTxO in unspent_tx_outs if uTxO.address == self.get_public_key()])
@staticmethod
def find_tx_outs_for_amount(amount, my_unspent_tx_outs):
amount = Decimal(amount)
current_amount = Decimal(0)
included_unspent_tx_outs = []
for my_unspent_tx_out in my_unspent_tx_outs:
included_unspent_tx_outs.append(my_unspent_tx_out)
current_amount += my_unspent_tx_out.amount
if current_amount > amount:
left_over_amount = current_amount - amount
return (included_unspent_tx_outs, left_over_amount)
raise UnauthorizedError('not enough coins to send transaction ' +
'or there are pending transactions from this address')
def create_tx_outs(self, receiver_address, amount, left_over_amount):
amount = Decimal(amount)
tx_out_1 = TxOut(receiver_address, amount)
tx_outs = [tx_out_1]
if left_over_amount > 0:
my_address = self.get_public_key()
left_over_tx_out = TxOut(my_address, left_over_amount)
tx_outs.append(left_over_tx_out)
return tx_outs
def create_transaction(self, receiver_address, amount, unspent_tx_outs, tx_pool):
amount = Decimal(amount)
my_address = self.get_public_key()
private_key = self.get_private_key()
my_uTxOs = [uTxO for uTxO in unspent_tx_outs if uTxO.address == my_address]
filtered_my_uTxOs = tx_pool.filtered_unspent_tx_outs(my_uTxOs)
(included_uTxOs, left_over_amount) = Wallet.find_tx_outs_for_amount(amount, filtered_my_uTxOs)
unsigned_tx_ins = [TxIn(uTxO.tx_out_id, uTxO.tx_out_index) for uTxO in included_uTxOs]
tx_outs = self.create_tx_outs(receiver_address, amount, left_over_amount)
tx = Transaction(unsigned_tx_ins, tx_outs)
for index, tx_in in enumerate(tx.tx_ins):
tx_in.signature = tx.sign_input(index, private_key, unspent_tx_outs)
return tx