Compare commits
2 Commits
d8a29c0a11
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d7ecab6494 | |||
| 8061fdba9b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
|||||||
venv/*
|
venv/*
|
||||||
mine_data/*
|
mine_data/*
|
||||||
mariadb_data/*
|
mariadb_data/*
|
||||||
|
*.pem
|
||||||
|
*__pycache__*
|
||||||
|
*.swp
|
||||||
|
|||||||
295
cli.py
Normal file
295
cli.py
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
from typing import Optional
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "wikideck")));
|
||||||
|
|
||||||
|
from Mine.Block import Block
|
||||||
|
from Mine.Transaction import Transaction
|
||||||
|
|
||||||
|
WIKIDECK_URL = os.getenv('WIKIDECK_URL', 'http://localhost:8080/');
|
||||||
|
|
||||||
|
|
||||||
|
rsa_private_key: Optional[rsa.RSAPrivateKey] = None;
|
||||||
|
msg_array: list[str] = [""];
|
||||||
|
private_key_file: str = "privatekey.pem";
|
||||||
|
public_key_file: str = "publickey.pem";
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
if (msg_array[0]):
|
||||||
|
print(f"Last Action: {msg_array[0]}");
|
||||||
|
|
||||||
|
print("\n--- Wikideck CLI ---");
|
||||||
|
print("1. Create RSA Keypair");
|
||||||
|
print("2. Save Private Key");
|
||||||
|
print("3. Load RSA Keypair");
|
||||||
|
print("4. Save Public Key")
|
||||||
|
print("5. Mine a Block");
|
||||||
|
print("6. Generate a Transaction");
|
||||||
|
print("7. View Deck");
|
||||||
|
print("0. Exit");
|
||||||
|
print("\n-------------------");
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice: int = int(input("Select an option: ").strip());
|
||||||
|
except ValueError:
|
||||||
|
msg_array[0] = "Invalid Input. Please Choose a Number Between 0-6.";
|
||||||
|
clear_console();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
if choice == 0:
|
||||||
|
break;
|
||||||
|
elif choice == 1:
|
||||||
|
opt_generate_keypair(65537, 2048);
|
||||||
|
elif choice == 2:
|
||||||
|
opt_save_private_key(rsa_private_key);
|
||||||
|
elif choice == 3:
|
||||||
|
opt_load_private_key();
|
||||||
|
elif choice == 4:
|
||||||
|
opt_save_public_key(rsa_private_key);
|
||||||
|
elif choice == 5:
|
||||||
|
opt_mine_block();
|
||||||
|
elif choice == 6:
|
||||||
|
opt_generate_transaction();
|
||||||
|
elif choice == 7:
|
||||||
|
opt_view_deck();
|
||||||
|
else:
|
||||||
|
msg_array[0] = "Invalid Input. Please Choose a Number Between 0-6.";
|
||||||
|
|
||||||
|
clear_console();
|
||||||
|
|
||||||
|
def opt_generate_keypair(exponent=65537, size=2048):
|
||||||
|
global rsa_private_key;
|
||||||
|
rsa_private_key = rsa.generate_private_key(
|
||||||
|
public_exponent = exponent,
|
||||||
|
key_size = size,
|
||||||
|
)
|
||||||
|
msg_array[0] = "RSA Keypair Generated";
|
||||||
|
return rsa_private_key;
|
||||||
|
|
||||||
|
def opt_save_private_key(rsa, filename=private_key_file):
|
||||||
|
if rsa is None:
|
||||||
|
msg_array[0] = "No RSA Keypair to extract private key. Please generate one first.";
|
||||||
|
return None;
|
||||||
|
else:
|
||||||
|
with open(filename, "wb") as file:
|
||||||
|
pem = rsa.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
|
encryption_algorithm=serialization.NoEncryption()
|
||||||
|
)
|
||||||
|
file.write(pem);
|
||||||
|
msg_array[0] = f"RSA Private Key Saved to {filename}";
|
||||||
|
|
||||||
|
def opt_save_public_key(rsa, filename=public_key_file):
|
||||||
|
if rsa is None:
|
||||||
|
msg_array[0] = "No RSA Keypair to extract public key. Please generate one first.";
|
||||||
|
return None;
|
||||||
|
|
||||||
|
public_key = rsa.public_key();
|
||||||
|
|
||||||
|
public_pem = public_key.public_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(filename, "wb") as file:
|
||||||
|
file.write(public_pem);
|
||||||
|
msg_array[0] = f"RSA Public Key Saved to {filename}";
|
||||||
|
|
||||||
|
def opt_load_private_key():
|
||||||
|
global rsa_private_key;
|
||||||
|
if not os.path.exists(private_key_file):
|
||||||
|
msg_array[0] = f"No saved key found ({private_key_file} missing)";
|
||||||
|
return None;
|
||||||
|
|
||||||
|
with open(private_key_file, "rb") as file:
|
||||||
|
rsa_private_key = serialization.load_pem_private_key(
|
||||||
|
file.read(),
|
||||||
|
password=None,
|
||||||
|
)
|
||||||
|
msg_array[0] = f"RSA Private Key Loaded From {private_key_file}";
|
||||||
|
|
||||||
|
def get_private_key_from_file(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
msg_array[0] = f"No key file found ({path} missing)";
|
||||||
|
return None;
|
||||||
|
|
||||||
|
with open(path, "rb") as file:
|
||||||
|
key = serialization.load_pem_private_key(
|
||||||
|
file.read(),
|
||||||
|
password=None,
|
||||||
|
);
|
||||||
|
msg_array[0] = f"RSA Private Key Gotten From {path}"; #inaccessible
|
||||||
|
|
||||||
|
return key;
|
||||||
|
|
||||||
|
def opt_mine_block(path = None):
|
||||||
|
|
||||||
|
global rsa_private_key;
|
||||||
|
|
||||||
|
if (path):
|
||||||
|
rsa_private_key = get_private_key_from_file(path);
|
||||||
|
if not (rsa_private_key):
|
||||||
|
return None;
|
||||||
|
|
||||||
|
if rsa_private_key is None:
|
||||||
|
msg_array[0] = "You must load or generate an RSA keypair first.";
|
||||||
|
return;
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(f"{WIKIDECK_URL}/blocks");
|
||||||
|
if response.status_code != 200:
|
||||||
|
msg_array[0] = f"Failed to fetch block to mine: {response.status_code}";
|
||||||
|
return;
|
||||||
|
|
||||||
|
block_to_mine = Block(data = response.json());
|
||||||
|
block_to_mine.mine(rsa_private_key);
|
||||||
|
|
||||||
|
response = requests.post(f"{WIKIDECK_URL}/blocks", json=block_to_mine.as_dict());
|
||||||
|
if response.status_code == 200:
|
||||||
|
msg_array[0] = "Block successfully mined and submitted";
|
||||||
|
else:
|
||||||
|
msg_array[0] = f"Failed to submit mined block: {response.status_code}";
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
msg_array[0] = f"Error during mining: {str(e)}";
|
||||||
|
|
||||||
|
def opt_generate_transaction(path = None, recv = None):
|
||||||
|
global rsa_private_key;
|
||||||
|
|
||||||
|
if (path):
|
||||||
|
rsa_private_key = get_private_key_from_file(path);
|
||||||
|
if not (rsa_private_key):
|
||||||
|
return None;
|
||||||
|
|
||||||
|
|
||||||
|
if rsa_private_key is None:
|
||||||
|
msg_array[0] = "You must load or generate an RSA keypair first.";
|
||||||
|
return;
|
||||||
|
|
||||||
|
if not (recv):
|
||||||
|
print("\nPaste the recipient's RSA Public Key (PEM format). End with an Empty Line (Press enter twice): ");
|
||||||
|
lines = [];
|
||||||
|
while True:
|
||||||
|
line = input();
|
||||||
|
if not line.strip():
|
||||||
|
break;
|
||||||
|
lines.append(line);
|
||||||
|
|
||||||
|
receiver_pem = "\n".join(lines);
|
||||||
|
|
||||||
|
try:
|
||||||
|
receiver_key = serialization.load_pem_public_key(receiver_pem.encode("utf-8"));
|
||||||
|
except Exception:
|
||||||
|
msg_array[0] = "Invalid public key format";
|
||||||
|
return;
|
||||||
|
|
||||||
|
else:
|
||||||
|
if not os.path.isfile(recv):
|
||||||
|
msg_array[0] = f"Reciever public key file not found {recv}";
|
||||||
|
return None;
|
||||||
|
with open(recv, "rb") as recv_file:
|
||||||
|
receiver_key = serialization.load_pem_public_key(recv_file.read());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
cards = fetch_cards_json(rsa_private_key);
|
||||||
|
|
||||||
|
if not cards:
|
||||||
|
msg_array[0] = "You have no cards to send";
|
||||||
|
return;
|
||||||
|
|
||||||
|
print("\nYour cards:");
|
||||||
|
|
||||||
|
for i, card in enumerate(cards):
|
||||||
|
print(f"{i+1}. Card ID: {card['cardId']}, Page ID: {card['pageId']}");
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
index: int = int(input("Select a card number to send: ").strip()) - 1;
|
||||||
|
|
||||||
|
if not (0 <= index < len(cards)):
|
||||||
|
raise ValueError;
|
||||||
|
except ValueError:
|
||||||
|
msg_array[0] = "Invalid card selection";
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_card = cards[index];
|
||||||
|
|
||||||
|
tx = Transaction(
|
||||||
|
cardId = selected_card['cardId'],
|
||||||
|
sender = rsa_private_key.public_key(),
|
||||||
|
receiver=receiver_key,
|
||||||
|
authorPrivateKey=rsa_private_key
|
||||||
|
);
|
||||||
|
|
||||||
|
response = requests.post(f"{WIKIDECK_URL}/transactions", json=tx.as_dict());
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
msg_array[0] = f"Transaction failed: {response.status_code}";
|
||||||
|
else:
|
||||||
|
msg_array[0] = "Transaction submitted successfully";
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
msg_array[0] = f"Error creating transaction: {str(e)}";
|
||||||
|
|
||||||
|
|
||||||
|
def opt_view_deck():
|
||||||
|
|
||||||
|
global rsa_private_key;
|
||||||
|
if rsa_private_key is None:
|
||||||
|
msg_array[0] = "You must load or generate an RSA keypair first.";
|
||||||
|
return;
|
||||||
|
|
||||||
|
try:
|
||||||
|
cards = fetch_cards_json(rsa_private_key);
|
||||||
|
|
||||||
|
|
||||||
|
if len(cards) <= 0:
|
||||||
|
msg_array[0] = "You have no cards to view";
|
||||||
|
return;
|
||||||
|
|
||||||
|
msg = "Successfully listed deck.\n"
|
||||||
|
for card in cards:
|
||||||
|
msg += f"Card ID: {card['cardId']}, Page ID: {card['pageId']}\n"
|
||||||
|
msg_array[0] = msg
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
msg_array[0] = f"Error fetching cards: {str(e)}";
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_cards_json(rsa):
|
||||||
|
pem = rsa.public_key().public_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
||||||
|
).decode("utf-8");
|
||||||
|
|
||||||
|
response = requests.get(f"{WIKIDECK_URL}/cards", params={"publicKey": pem});
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
msg_array[0] = f"Failed to fetch cards: {response.status_code}";
|
||||||
|
return;
|
||||||
|
|
||||||
|
cards = response.json();
|
||||||
|
return cards;
|
||||||
|
|
||||||
|
|
||||||
|
def clear_console():
|
||||||
|
os.system('cls' if os.name == 'nt' else 'clear');
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main();
|
||||||
3
client-requirements.txt
Normal file
3
client-requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
cryptography
|
||||||
|
dotenv
|
||||||
|
wikipedia
|
||||||
@@ -13,6 +13,7 @@ services:
|
|||||||
MINE_DB_HOST: mariadb-mine
|
MINE_DB_HOST: mariadb-mine
|
||||||
MINE_DB_USER: mine
|
MINE_DB_USER: mine
|
||||||
MINE_DB_PASSWORD: 123abc
|
MINE_DB_PASSWORD: 123abc
|
||||||
|
MINE_LOG_FILE: /tmp/mine.log
|
||||||
depends_on:
|
depends_on:
|
||||||
- mariadb-mine
|
- mariadb-mine
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import base64
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
import mariadb
|
import mariadb
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@@ -181,6 +182,8 @@ class Database():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
logging.basicConfig(filename=os.getenv('MINE_LOG_FILE', '/var/log/mine.log'), level=logging.INFO)
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
delay = 2
|
delay = 2
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -195,6 +198,7 @@ class Database():
|
|||||||
for each in self.SQL_CREATE_TABLES:
|
for each in self.SQL_CREATE_TABLES:
|
||||||
self.conn.cursor().execute(each)
|
self.conn.cursor().execute(each)
|
||||||
except mariadb.Error as e:
|
except mariadb.Error as e:
|
||||||
|
self.logger.error(e)
|
||||||
time.sleep(delay := delay**2)
|
time.sleep(delay := delay**2)
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
@@ -239,28 +243,23 @@ class Database():
|
|||||||
|
|
||||||
def get_blocks(self):
|
def get_blocks(self):
|
||||||
cur = self.conn.cursor()
|
cur = self.conn.cursor()
|
||||||
cur.execute(self.SQL_GET_LAST_BLOCK)
|
cur.execute(self.SQL_GET_BLOCKS)
|
||||||
blocks = cur.fetchall()
|
blocks = cur.fetchall()
|
||||||
if blocks:
|
return [
|
||||||
blockCard = self.get_card_by_block_id(lastBlock[0])
|
Block(
|
||||||
blockTransactions = self.get_transactions_by_block_id(lastBlock[0])
|
blockId = uuid.UUID(block[0]),
|
||||||
return [
|
previousHash = block[1],
|
||||||
Block(
|
timestamp = datetime.datetime.strptime(
|
||||||
blockId = uuid.UUID(block[0]),
|
block[2],
|
||||||
previousHash = block[1],
|
"%Y-%m-%d %H:%M:%S.%f%z"
|
||||||
timestamp = datetime.datetime.strptime(
|
),
|
||||||
block[2],
|
height = block[3],
|
||||||
"%Y-%m-%d %H:%M:%S.%f%z"
|
difficulty = block[4],
|
||||||
),
|
nonce = block[5],
|
||||||
height = block[3],
|
card = self.get_card_by_block_id(block[0]),
|
||||||
difficulty = block[4],
|
transactions = self.get_transactions_by_block_id(block[0])
|
||||||
nonce = block[5],
|
) for block in blocks
|
||||||
card = blockCard,
|
] if blocks else []
|
||||||
transactions = blockTransactions
|
|
||||||
)
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_last_block(self):
|
def get_last_block(self):
|
||||||
cur = self.conn.cursor()
|
cur = self.conn.cursor()
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ def generate_origin_block():
|
|||||||
@mine.get('/')
|
@mine.get('/')
|
||||||
def index_get():
|
def index_get():
|
||||||
try:
|
try:
|
||||||
return jsonify([each.as_dict() for each in db.get_blocks()])
|
blocks = db.get_blocks()
|
||||||
|
return flask.jsonify([block.as_dict() for block in blocks]) if blocks else flask.jsonify({})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return flask.jsonify(
|
return flask.jsonify(
|
||||||
{'Error': str(e)}
|
{'Error': str(e)}
|
||||||
@@ -171,6 +172,8 @@ def cards_get():
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
return flask.jsonify([card.as_dict() for card in deck] if deck else [])
|
return flask.jsonify([card.as_dict() for card in deck] if deck else [])
|
||||||
|
else:
|
||||||
|
return flask.jsonify({'Error': "No public key."}), 400
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return flask.jsonify(
|
return flask.jsonify(
|
||||||
{'Error': str(e)}
|
{'Error': str(e)}
|
||||||
|
|||||||
155
wikideck_cli.py
Executable file
155
wikideck_cli.py
Executable file
@@ -0,0 +1,155 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
from cli import opt_generate_keypair
|
||||||
|
from cli import opt_save_private_key
|
||||||
|
from cli import opt_load_private_key
|
||||||
|
from cli import opt_save_public_key
|
||||||
|
from cli import opt_mine_block
|
||||||
|
from cli import opt_generate_transaction
|
||||||
|
from cli import opt_view_deck
|
||||||
|
from cli import msg_array
|
||||||
|
from cli import get_private_key_from_file
|
||||||
|
from cli import fetch_cards_json
|
||||||
|
|
||||||
|
DEFAULT_FILENAME: str = "privatekey";
|
||||||
|
|
||||||
|
def resolve_path(path: str | None) -> str | None:
|
||||||
|
if not path or path.strip() == "":
|
||||||
|
return None;
|
||||||
|
|
||||||
|
path = path.strip();
|
||||||
|
|
||||||
|
if not path.endswith(".pem"):
|
||||||
|
path += ".pem";
|
||||||
|
|
||||||
|
if os.path.exists(path) and os.path.isfile(path):
|
||||||
|
return path;
|
||||||
|
|
||||||
|
return None;
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_path_for_key_creation(filename:str | None) -> str:
|
||||||
|
default_name = "privatekey.pem";
|
||||||
|
|
||||||
|
if not filename or filename.strip() == "":
|
||||||
|
return default_name;
|
||||||
|
|
||||||
|
filename = filename.strip();
|
||||||
|
|
||||||
|
if os.path.isdir(filename):
|
||||||
|
return os.path.join(filename, default_name);
|
||||||
|
|
||||||
|
if not filename.endswith(".pem"):
|
||||||
|
filename += ".pem";
|
||||||
|
|
||||||
|
dir_path = os.path.dirname(filename);
|
||||||
|
if dir_path and not os.path.exists(dir_path):
|
||||||
|
os.makedirs(dir_path);
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
|
||||||
|
def get_first_pem_file():
|
||||||
|
pem_files = glob.glob("*.pem");
|
||||||
|
|
||||||
|
if pem_files:
|
||||||
|
first_pem = min(pem_files, key=os.path.getmtime);
|
||||||
|
return first_pem;
|
||||||
|
else:
|
||||||
|
return None;
|
||||||
|
|
||||||
|
def handle_createkey(args):
|
||||||
|
rsa_key = opt_generate_keypair();
|
||||||
|
filepath = resolve_path_for_key_creation(args.output);
|
||||||
|
opt_save_private_key(rsa_key, filepath);
|
||||||
|
print(msg_array[0]);
|
||||||
|
public_path = f"pub_{filepath}"
|
||||||
|
opt_save_public_key(rsa_key, public_path);
|
||||||
|
|
||||||
|
def handle_mine(args):
|
||||||
|
file = resolve_path(args.use);
|
||||||
|
if not file:
|
||||||
|
file = get_first_pem_file();
|
||||||
|
if not file:
|
||||||
|
msg_array[0] = "No valid private key found";
|
||||||
|
return;
|
||||||
|
|
||||||
|
opt_mine_block(file);
|
||||||
|
|
||||||
|
|
||||||
|
def handle_tx(args):
|
||||||
|
|
||||||
|
file = resolve_path(args.use);
|
||||||
|
if not file:
|
||||||
|
file = get_first_pem_file();
|
||||||
|
if not file:
|
||||||
|
msg_array[0] = "No valid private key found";
|
||||||
|
return;
|
||||||
|
|
||||||
|
recv = resolve_path(args.receiver);
|
||||||
|
if args.receiver and not recv:
|
||||||
|
msg_array[0] = "No valid public key found (receiver)";
|
||||||
|
return;
|
||||||
|
|
||||||
|
opt_generate_transaction(file, recv);
|
||||||
|
|
||||||
|
|
||||||
|
def handle_deck(args):
|
||||||
|
file = resolve_path(args.use);
|
||||||
|
if not file:
|
||||||
|
file = get_first_pem_file();
|
||||||
|
if not file:
|
||||||
|
msg_array[0] = "No valid private key found";
|
||||||
|
return;
|
||||||
|
|
||||||
|
rsa = get_private_key_from_file(file);
|
||||||
|
if rsa is None:
|
||||||
|
return;
|
||||||
|
|
||||||
|
cards = fetch_cards_json(rsa);
|
||||||
|
|
||||||
|
if len(cards) < 1:
|
||||||
|
msg_array[0] = "You have no cards to view";
|
||||||
|
return;
|
||||||
|
|
||||||
|
for i, card in enumerate(cards):
|
||||||
|
print(f"{i+1}. Card ID: {card['cardId']}, Page ID: {card['pageId']}");
|
||||||
|
|
||||||
|
|
||||||
|
def build_parser():
|
||||||
|
parser = argparse.ArgumentParser(description="Wikideck CLI");
|
||||||
|
subparsers = parser.add_subparsers(dest="command", required=True);
|
||||||
|
|
||||||
|
#createkey
|
||||||
|
p_create = subparsers.add_parser("createkey",aliases=["ck"], help="Create an RSA keypair and save it to the current directory");
|
||||||
|
p_create.add_argument("-O", "--output", help="Optional custom filename (.pem)");
|
||||||
|
p_create.set_defaults(func=handle_createkey);
|
||||||
|
|
||||||
|
#mine
|
||||||
|
p_mine = subparsers.add_parser("mine", help="Mine a block, using the first ./*.pem by default.");
|
||||||
|
p_mine.add_argument("-u", "--use", help="Use specified keypair (path to .pem file)");
|
||||||
|
p_mine.set_defaults(func=handle_mine);
|
||||||
|
|
||||||
|
#transaction
|
||||||
|
p_transaction = subparsers.add_parser("transaction", aliases=["tx"], help="Generate a transaction, using the first ./*.pem by default.");
|
||||||
|
p_transaction.add_argument("-u", "--use", help="Use specified keypair (path to .pem file)");
|
||||||
|
p_transaction.add_argument("-to", "--receiver", help="Send to specified public key (path to .pem file)");
|
||||||
|
p_transaction.set_defaults(func=handle_tx);
|
||||||
|
|
||||||
|
#deck
|
||||||
|
p_deck = subparsers.add_parser("deck", help="Show all cards tied to the private key, using the first ./*.pem by default.");
|
||||||
|
p_deck.add_argument("-u", "--use", help="Use specified keypair (path to .pem file)");
|
||||||
|
p_deck.set_defaults(func=handle_deck);
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = build_parser();
|
||||||
|
args = parser.parse_args();
|
||||||
|
args.func(args);
|
||||||
|
print(msg_array[0]);
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user