|
@@ -16,8 +16,8 @@ from binascii import hexlify
|
|
|
import logging
|
|
import logging
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s")
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)-8s %(message)s")
|
|
|
|
|
|
|
|
-from src.blockchain import Blockchain
|
|
|
|
|
from src.block import Block
|
|
from src.block import Block
|
|
|
|
|
+from src.blockchain import Blockchain
|
|
|
from src.transaction import Transaction, TransactionTarget, TransactionInput
|
|
from src.transaction import Transaction, TransactionTarget, TransactionInput
|
|
|
from src.crypto import Signing
|
|
from src.crypto import Signing
|
|
|
|
|
|
|
@@ -80,26 +80,45 @@ def private_signing(path):
|
|
|
raise ValueError("The specified key is not a private key.")
|
|
raise ValueError("The specified key is not a private key.")
|
|
|
return val
|
|
return val
|
|
|
|
|
|
|
|
|
|
+def wallet_file(path):
|
|
|
|
|
+ try:
|
|
|
|
|
+ with open(path, "rb") as f:
|
|
|
|
|
+ contents = f.read()
|
|
|
|
|
+ except FileNotFoundError:
|
|
|
|
|
+ return [], path
|
|
|
|
|
+ return list(Signing.read_many_private(contents)), path
|
|
|
|
|
+
|
|
|
def main():
|
|
def main():
|
|
|
parser = argparse.ArgumentParser(description="Wallet.")
|
|
parser = argparse.ArgumentParser(description="Wallet.")
|
|
|
parser.add_argument("--miner-port", default=40203, type=int,
|
|
parser.add_argument("--miner-port", default=40203, type=int,
|
|
|
help="The RPC port of the miner to connect to.")
|
|
help="The RPC port of the miner to connect to.")
|
|
|
|
|
+ parser.add_argument("--wallet", type=wallet_file, default=([],None),
|
|
|
|
|
+ help="The wallet file containing the private keys to use.")
|
|
|
subparsers = parser.add_subparsers(dest="command")
|
|
subparsers = parser.add_subparsers(dest="command")
|
|
|
|
|
+
|
|
|
|
|
+ balance = subparsers.add_parser("create-address",
|
|
|
|
|
+ help="Creates new addresses and stores their secret keys in the wallet.")
|
|
|
|
|
+ balance.add_argument("file", nargs="+", type=argparse.FileType("wb"),
|
|
|
|
|
+ help="Path to a file where the address should be stored.")
|
|
|
|
|
+
|
|
|
balance = subparsers.add_parser("show-balance",
|
|
balance = subparsers.add_parser("show-balance",
|
|
|
help="Shows the current balance of the public key "
|
|
help="Shows the current balance of the public key "
|
|
|
"stored in the specified file.")
|
|
"stored in the specified file.")
|
|
|
- balance.add_argument("key", nargs="+", type=Signing.from_file)
|
|
|
|
|
|
|
+ balance.add_argument("key", nargs="*", type=Signing.from_file)
|
|
|
|
|
+
|
|
|
trans = subparsers.add_parser("show-transactions",
|
|
trans = subparsers.add_parser("show-transactions",
|
|
|
help="Shows all transactions involving the public key "
|
|
help="Shows all transactions involving the public key "
|
|
|
"stored in the specified file.")
|
|
"stored in the specified file.")
|
|
|
- trans.add_argument("key", nargs="+", type=Signing.from_file)
|
|
|
|
|
|
|
+ trans.add_argument("key", nargs="*", type=Signing.from_file)
|
|
|
|
|
+
|
|
|
subparsers.add_parser("show-network",
|
|
subparsers.add_parser("show-network",
|
|
|
help="Prints networking information about the miner.")
|
|
help="Prints networking information about the miner.")
|
|
|
|
|
+
|
|
|
transfer = subparsers.add_parser("transfer", help="Transfer money.")
|
|
transfer = subparsers.add_parser("transfer", help="Transfer money.")
|
|
|
transfer.add_argument("--private-key", type=private_signing,
|
|
transfer.add_argument("--private-key", type=private_signing,
|
|
|
- default=[], action="append", required=True,
|
|
|
|
|
|
|
+ default=[], action="append", required=False,
|
|
|
help="The private key(s) whose coins should be used for the transfer.")
|
|
help="The private key(s) whose coins should be used for the transfer.")
|
|
|
- transfer.add_argument("--change-key", type=Signing.from_file, required=True,
|
|
|
|
|
|
|
+ transfer.add_argument("--change-key", type=Signing.from_file, required=False,
|
|
|
help="The private key where any remaining coins are sent to.")
|
|
help="The private key where any remaining coins are sent to.")
|
|
|
transfer.add_argument("--transaction-fee", type=int, default=0,
|
|
transfer.add_argument("--transaction-fee", type=int, default=0,
|
|
|
help="The transaction fee you want to pay to the miner.")
|
|
help="The transaction fee you want to pay to the miner.")
|
|
@@ -111,13 +130,31 @@ def main():
|
|
|
url = "http://localhost:{}/".format(args.miner_port)
|
|
url = "http://localhost:{}/".format(args.miner_port)
|
|
|
s = requests.session()
|
|
s = requests.session()
|
|
|
|
|
|
|
|
|
|
+ def get_keys(keys):
|
|
|
|
|
+ all_keys = keys + args.wallet[0]
|
|
|
|
|
+ if not all_keys:
|
|
|
|
|
+ print("missing key or wallet", file=sys.stderr)
|
|
|
|
|
+ parser.parse_args(["--help"])
|
|
|
|
|
+ return all_keys
|
|
|
|
|
+
|
|
|
if args.command == 'show-transactions':
|
|
if args.command == 'show-transactions':
|
|
|
- for key in args.key:
|
|
|
|
|
|
|
+ for key in get_keys(args.key):
|
|
|
for trans in get_transactions(s, url, key):
|
|
for trans in get_transactions(s, url, key):
|
|
|
print(trans.to_json_compatible())
|
|
print(trans.to_json_compatible())
|
|
|
|
|
+ print()
|
|
|
|
|
+ elif args.command == "create-address":
|
|
|
|
|
+ if not args.wallet[1]:
|
|
|
|
|
+ print("no wallet specified", file=sys.stderr)
|
|
|
|
|
+ parser.parse_args(["--help"])
|
|
|
|
|
+
|
|
|
|
|
+ keys = [Signing.generate_private_key() for _ in args.file]
|
|
|
|
|
+ Signing.write_many_private(args.wallet[1], args.wallet[0] + keys)
|
|
|
|
|
+ for fp, key in zip(args.file, keys):
|
|
|
|
|
+ fp.write(key.as_bytes())
|
|
|
|
|
+ fp.close()
|
|
|
elif args.command == 'show-balance':
|
|
elif args.command == 'show-balance':
|
|
|
total = 0
|
|
total = 0
|
|
|
- for pubkey, balance in show_balance(s, url, args.key):
|
|
|
|
|
|
|
+ for pubkey, balance in show_balance(s, url, get_keys(args.key)):
|
|
|
print("{}: {}".format(hexlify(pubkey.as_bytes()), balance))
|
|
print("{}: {}".format(hexlify(pubkey.as_bytes()), balance))
|
|
|
total += balance
|
|
total += balance
|
|
|
print()
|
|
print()
|
|
@@ -130,7 +167,13 @@ def main():
|
|
|
print("Missing amount to transfer for last target key.\n", file=sys.stderr)
|
|
print("Missing amount to transfer for last target key.\n", file=sys.stderr)
|
|
|
parser.parse_args(["--help"])
|
|
parser.parse_args(["--help"])
|
|
|
targets = [TransactionTarget(k, a) for k, a in zip(args.target[::2], args.target[1::2])]
|
|
targets = [TransactionTarget(k, a) for k, a in zip(args.target[::2], args.target[1::2])]
|
|
|
- build_transaction(s, url, args.private_key, targets, args.change_key, args.transaction_fee)
|
|
|
|
|
|
|
+ change_key = args.change_key
|
|
|
|
|
+ if not change_key:
|
|
|
|
|
+ get_keys([]) # shows error if no wallet
|
|
|
|
|
+ change_key = Signing.generate_private_key()
|
|
|
|
|
+ Signing.write_many_private(args.wallet[1], args.wallet[0] + [change_key])
|
|
|
|
|
+
|
|
|
|
|
+ build_transaction(s, url, get_keys(args.private_key), targets, change_key, args.transaction_fee)
|
|
|
else:
|
|
else:
|
|
|
print("You need to specify what to do.\n", file=sys.stderr)
|
|
print("You need to specify what to do.\n", file=sys.stderr)
|
|
|
parser.parse_args(["--help"])
|
|
parser.parse_args(["--help"])
|