Implement gambling
This commit is contained in:
145
wallet.py
145
wallet.py
@@ -1,6 +1,6 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
import base64, socket, sys, time
|
||||
import base64, hashlib, socket, sys, time
|
||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
|
||||
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, PublicFormat, NoEncryption
|
||||
|
||||
@@ -27,33 +27,75 @@ def write_transaction(timestamp, message, amount):
|
||||
|
||||
def show_balance(public_key):
|
||||
public_key_raw = public_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
|
||||
with open("blockchain", "rb") as f:
|
||||
total_amount = 0
|
||||
while True:
|
||||
block = f.read(292)
|
||||
if len(block) != 292:
|
||||
break
|
||||
miner = block[180:212]
|
||||
timestamp = int.from_bytes(block[244:252], "big")
|
||||
if block[0:148] != 148 * b"\0":
|
||||
sender = block[4:36]
|
||||
receiver = block[36:68]
|
||||
amount = int.from_bytes(block[68:76], "big")
|
||||
fee = int.from_bytes(block[76:84], "big")
|
||||
if sender == public_key_raw:
|
||||
write_transaction(timestamp, format_address(receiver), - amount - fee)
|
||||
total_amount -= (amount + fee)
|
||||
if receiver == public_key_raw:
|
||||
write_transaction(timestamp, format_address(sender), amount)
|
||||
total_amount += amount
|
||||
else:
|
||||
fee = 0
|
||||
if miner == public_key_raw:
|
||||
write_transaction(timestamp, "mining reward", 100 + fee)
|
||||
total_amount += 100 + fee
|
||||
print(81 * "\u2500")
|
||||
amount_string = f"\U0001f955 \x1b[1;37m{format_amount(total_amount, 41, False)}\x1b[0m"
|
||||
print(21 * " " + f"\x1b[1;37mYour balance:\x1b[0m{amount_string}")
|
||||
try:
|
||||
with open("blockchain", "rb") as f:
|
||||
total_amount = 0
|
||||
block_counter = 0
|
||||
pending_bets = [[]]
|
||||
while True:
|
||||
block = f.read(293)
|
||||
if len(block) != 293:
|
||||
break
|
||||
miner = block[181:213]
|
||||
timestamp = int.from_bytes(block[245:253], "big")
|
||||
if block[0] == 1:
|
||||
# Payment
|
||||
sender = block[5:37]
|
||||
receiver = block[37:69]
|
||||
amount = int.from_bytes(block[69:77], "big")
|
||||
fee = int.from_bytes(block[77:85], "big")
|
||||
if sender == public_key_raw:
|
||||
write_transaction(timestamp, format_address(receiver), - amount)
|
||||
if fee > 0:
|
||||
write_transaction(timestamp, 39 * " " + "(fee)", - fee)
|
||||
total_amount -= (amount + fee)
|
||||
if receiver == public_key_raw:
|
||||
write_transaction(timestamp, format_address(sender), amount)
|
||||
total_amount += amount
|
||||
elif block[0] == 2:
|
||||
# Gambling
|
||||
transaction_id = block[1:5]
|
||||
player = block[5:37]
|
||||
amount = int.from_bytes(block[37:45], "big")
|
||||
fee = int.from_bytes(block[45:53], "big")
|
||||
if player == public_key_raw:
|
||||
write_transaction(timestamp, "- gambling -", -amount)
|
||||
if fee > 0:
|
||||
write_transaction(timestamp, 39 * " " + "(fee)", - fee)
|
||||
total_amount -= (amount + fee)
|
||||
pending_bets[-1].append((transaction_id, amount))
|
||||
elif block[0] == 3:
|
||||
# Reveal transaction
|
||||
reveal_info = f.read(5376)
|
||||
revealer = block[1:33]
|
||||
R = reveal_info[0:256]
|
||||
relevant_bets = pending_bets[0]
|
||||
pending_bets = pending_bets[1:]
|
||||
fee = 100
|
||||
for (transaction_id, gambling_amount) in relevant_bets:
|
||||
to_hash = transaction_id + public_key_raw + R
|
||||
if hashlib.sha256(to_hash).digest()[0] >= 0x80:
|
||||
write_transaction(timestamp, f"Won gambling with {format_amount(gambling_amount, 0, False)}", 2 * gambling_amount)
|
||||
total_amount += 2 * gambling_amount
|
||||
else:
|
||||
write_transaction(timestamp, f"Lost gambling with {format_amount(gambling_amount, 0, False)}", 0)
|
||||
if revealer == public_key_raw:
|
||||
write_transaction(timestamp, "revealing reward", 1500)
|
||||
total_amount += 1500
|
||||
else:
|
||||
fee = 0
|
||||
if miner == public_key_raw:
|
||||
write_transaction(timestamp, "mining reward", 100 + fee)
|
||||
total_amount += 100 + fee
|
||||
if block_counter % 256 == 255:
|
||||
pending_bets.append([])
|
||||
block_counter += 1
|
||||
print(81 * "\u2500")
|
||||
amount_string = f"\U0001f955 \x1b[1;37m{format_amount(total_amount, 41, False)}\x1b[0m"
|
||||
print(21 * " " + f"\x1b[1;37mYour balance:\x1b[0m{amount_string}")
|
||||
except FileNotFoundError:
|
||||
print("File \"blockchain\" not found.\nThis wallet script requires a running node with at least 1 block in the current directory.", file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
def parse_amount(amount):
|
||||
amount = amount.replace(",", ".")
|
||||
@@ -61,10 +103,12 @@ def parse_amount(amount):
|
||||
if len(parts) == 1:
|
||||
return int(parts[0]) * 100
|
||||
elif len(parts) == 2:
|
||||
if len(parts[1]) > 2:
|
||||
if len(parts[1]) == 0 or len(parts[1]) > 2:
|
||||
raise Exception(f"Invalid amount: {amount}")
|
||||
coins = int(parts[0])
|
||||
cents = int(parts[1])
|
||||
coins = int(parts[0]) if parts[0] != "" else 0
|
||||
cents = int(parts[1]) if parts[1] != "" else 0
|
||||
if len(parts[1]) == 1:
|
||||
cents *= 10
|
||||
return coins * 100 + cents
|
||||
raise Exception(f"Invalid amount: {amount}")
|
||||
|
||||
@@ -81,14 +125,17 @@ def find_free_id(public_key_raw):
|
||||
with open("blockchain", "rb") as f:
|
||||
used_ids = set()
|
||||
while True:
|
||||
block = f.read(292)
|
||||
if len(block) != 292:
|
||||
block = f.read(293)
|
||||
if len(block) != 293:
|
||||
break
|
||||
if block[0:148] != 148 * b"\0":
|
||||
transaction_id = int.from_bytes(block[0:4], "big")
|
||||
sender = block[4:36]
|
||||
transaction_type = block[0]
|
||||
if transaction_type in (1, 2):
|
||||
transaction_id = int.from_bytes(block[1:5], "big")
|
||||
sender = block[5:37]
|
||||
if sender == public_key_raw:
|
||||
used_ids.add(transaction_id)
|
||||
elif transaction_type == 3:
|
||||
f.read(5376)
|
||||
for possible_id in range(0, 2**32):
|
||||
if possible_id not in used_ids:
|
||||
return possible_id
|
||||
@@ -106,15 +153,34 @@ def send_payment(private_key, target, amount, fee):
|
||||
fee = parse_amount_checked(fee)
|
||||
public_key_raw = private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
|
||||
transaction_id = find_free_id(public_key_raw)
|
||||
transaction_prefix = transaction_id.to_bytes(4, "big") + \
|
||||
transaction_prefix = b"\x01" + \
|
||||
transaction_id.to_bytes(4, "big") + \
|
||||
public_key_raw + \
|
||||
target_raw + \
|
||||
amount.to_bytes(8, "big") + \
|
||||
fee.to_bytes(8, "big")
|
||||
signature = private_key.sign(transaction_prefix)
|
||||
transaction = transaction_prefix + signature
|
||||
request = b"\0\0\0\0\x09" + transaction
|
||||
send_transaction(transaction)
|
||||
|
||||
def gamble(private_key, amount, fee):
|
||||
amount = parse_amount_checked(amount)
|
||||
if amount == 0:
|
||||
raise Exception("Amount must not be zero")
|
||||
fee = parse_amount_checked(fee)
|
||||
public_key_raw = private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
|
||||
transaction_id = find_free_id(public_key_raw)
|
||||
transaction_prefix = b"\x02" + \
|
||||
transaction_id.to_bytes(4, "big") + \
|
||||
public_key_raw + \
|
||||
amount.to_bytes(8, "big") + \
|
||||
fee.to_bytes(8, "big")
|
||||
signature = private_key.sign(transaction_prefix)
|
||||
transaction = transaction_prefix + signature + 32 * b"\0"
|
||||
send_transaction(transaction)
|
||||
|
||||
def send_transaction(transaction):
|
||||
request = b"\0\0\0\0\x09" + transaction
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
try:
|
||||
s.connect(("::1", 62039))
|
||||
@@ -136,6 +202,7 @@ def usage_info():
|
||||
print("Usage:", file=sys.stderr)
|
||||
print(" ./wallet.py # see your past transactions and balance", file=sys.stderr)
|
||||
print(" ./wallet.py pay <target> <amount> <fee> # send carrotcoins to someone else", file=sys.stderr)
|
||||
print(" ./wallet.py gamble <amount> <fee> # set an arbitrary amount on a 50:50 bet", file=sys.stderr)
|
||||
|
||||
def main():
|
||||
try:
|
||||
@@ -156,6 +223,8 @@ def main():
|
||||
show_balance(public_key)
|
||||
elif len(sys.argv) == 5 and sys.argv[1] == "pay":
|
||||
send_payment(private_key, *sys.argv[2:5])
|
||||
elif len(sys.argv) == 4 and sys.argv[1] == "gamble":
|
||||
gamble(private_key, *sys.argv[2:4])
|
||||
else:
|
||||
usage_info()
|
||||
exit(1)
|
||||
|
||||
Reference in New Issue
Block a user