Save secret in key/value store

This commit is contained in:
Jay Graber 2017-08-02 18:06:09 -07:00
parent 22e4821ca7
commit e78072d0aa
6 changed files with 62 additions and 63 deletions

View File

@ -18,14 +18,14 @@ def checkSellStatus(tradeid):
status = seller_check_status(trade) status = seller_check_status(trade)
print("In checkSellStatus", status) print("In checkSellStatus", status)
# if trade.buy.get_status() == 'funded': # if trade.buy.get_status() == 'funded':
if status == 'initFund': if status == 'init':
userInput.authorize_fund_sell(trade) userInput.authorize_fund_sell(trade)
fund_tx = fund_sell_contract(trade) fund_tx = fund_sell_contract(trade)
print("Sent fund_tx", fund_tx) print("Sent fund_tx", fund_tx)
trade.sell.fund_tx = fund_tx trade.sell.fund_tx = fund_tx
save_state(trade, tradeid) save_state(trade, tradeid)
elif status == 'buyerFunded': elif status == 'buyerFunded':
secret = userInput.retrieve_password() secret = db.get_secret(tradeid)
print("SECRET found in checksellactions", secret) print("SECRET found in checksellactions", secret)
txs = seller_redeem_p2sh(trade, secret) txs = seller_redeem_p2sh(trade, secret)
print("TXS IN SELLER REDEEM BUYER TX", txs) print("TXS IN SELLER REDEEM BUYER TX", txs)
@ -50,7 +50,10 @@ def buyer_check_status(trade):
elif sellState == 'funded' and buyState == 'funded': elif sellState == 'funded' and buyState == 'funded':
return 'buyerFunded' # step2 return 'buyerFunded' # step2
elif sellState == 'empty' and buyState == 'empty': elif sellState == 'empty' and buyState == 'empty':
return 'buyerRedeemed' # step4 if hasattr(trade.sell, 'redeem_tx'):
return 'buyerRedeemed' # step4
else:
return 'init'
def seller_check_status(trade): def seller_check_status(trade):
sellState = check_fund_status(trade.sell.currency, trade.sell.p2sh) sellState = check_fund_status(trade.sell.currency, trade.sell.p2sh)
@ -66,14 +69,16 @@ def seller_check_status(trade):
if hasattr(trade.buy, 'redeem_tx'): if hasattr(trade.buy, 'redeem_tx'):
return 'buyerRedeemed' # step4 return 'buyerRedeemed' # step4
else: else:
return 'initFund' # step0 return 'init' # step0
# TODO: function to calculate appropriate locktimes between chains # TODO: function to calculate appropriate locktimes between chains
def checkBuyStatus(tradeid): def checkBuyStatus(tradeid):
trade = db.get(tradeid) trade = db.get(tradeid)
status = buyer_check_status(trade) status = buyer_check_status(trade)
print("In checkBuyStatus", status) print("In checkBuyStatus", status)
if status == 'buyerRedeemed': if status == 'init':
print("Trade has not yet started, waiting for seller to fund the sell p2sh.")
elif status == 'buyerRedeemed':
print("This trade is complete, both sides redeemed.") print("This trade is complete, both sides redeemed.")
# elif trade.sell.get_status() == 'funded' and trade.buy.get_status() != 'redeemed': # elif trade.sell.get_status() == 'funded' and trade.buy.get_status() != 'redeemed':
elif status == 'sellerFunded': elif status == 'sellerFunded':
@ -132,11 +137,12 @@ def exporttrade(tradeid, wormhole=False):
trade = db.get(tradeid) trade = db.get(tradeid)
hexstr = s2x(trade.toJSON()) hexstr = s2x(trade.toJSON())
if wormhole: if wormhole:
tradefile = os.path.join(root_dir, '.tmp/{0}'.format(tradeid)) tradefile = os.path.join(ROOT_DIR, '.tmp/{0}'.format(tradeid))
print(tradefile)
with open(tradefile, '+w') as outfile: with open(tradefile, '+w') as outfile:
outfile.write(hexstr) outfile.write(hexstr)
print("Exporting trade to buyer using magic wormhole.") print("Exporting trade to buyer using magic wormhole.")
subprocess.call('wormhole', 'send', tradefile) subprocess.call('wormhole send {0}'.format(tradefile), shell=True)
else: else:
print(hexstr) print(hexstr)
return hexstr return hexstr
@ -167,12 +173,11 @@ def newtrade(tradeid):
erase_trade() erase_trade()
role = 'seller' role = 'seller'
print("Creating new XCAT trade...") print("Creating new XCAT trade...")
trade = seller_init(Trade()) trade = seller_init(tradeid)
print("Use 'xcat exporttrade <tradeid> to export the trade and sent to the buyer.'") print("Use 'xcat exporttrade <tradeid> to export the trade and sent to the buyer.'")
save_state(trade, tradeid) save_state(trade, tradeid)
def main(): def main():
root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent('''\ description=textwrap.dedent('''\
== Trades == == Trades ==
@ -197,26 +202,26 @@ def main():
if args.wormhole: if args.wormhole:
wormhole_importtrade() wormhole_importtrade()
else: else:
if len(args.argument) != 2: if len(args.arguments) != 2:
print("Usage: importtrade [tradeid] [hexstring]") print("Usage: importtrade [tradeid] [hexstring]")
exit() exit()
tradeid = args.argument[0] tradeid = args.arguments[0]
hexstr = args.argument[1] hexstr = args.arguments[1]
importtrade(tradeid, hexstr) importtrade(tradeid, hexstr)
elif command == 'exporttrade': elif command == 'exporttrade':
tradeid = args.argument[0] tradeid = args.arguments[0]
exporttrade(tradeid, args.wormhole) exporttrade(tradeid, args.wormhole)
elif command == "findtrade": elif command == "findtrade":
print("Finding trade") print("Finding trade")
key = args.argument[0] key = args.arguments[0]
findtrade(key) findtrade(key)
elif command == 'checktrade': elif command == 'checktrade':
tradeid = args.argument[0] tradeid = args.arguments[0]
checktrade(tradeid) checktrade(tradeid)
elif command == 'newtrade': elif command == 'newtrade':
print("in new trade") print("in new trade")
try: try:
tradeid = args.argument[0] tradeid = args.arguments[0]
newtrade(tradeid) newtrade(tradeid)
except: except:
tradeid = userInput.enter_trade_id() tradeid = userInput.enter_trade_id()
@ -226,16 +231,16 @@ def main():
print("Run as daemon process") print("Run as daemon process")
# Ad hoc testing of workflow starts here # Ad hoc testing of workflow starts here
elif command == "step1": elif command == "step1":
tradeid = args.argument[0] tradeid = args.arguments[0]
checkSellStatus(tradeid) checkSellStatus(tradeid)
elif command == "step2": elif command == "step2":
# trade = get_trade() # trade = get_trade()
tradeid = args.argument[0] tradeid = args.arguments[0]
checkBuyStatus(tradeid) checkBuyStatus(tradeid)
elif command == "step3": elif command == "step3":
tradeid = args.argument[0] tradeid = args.arguments[0]
checkSellStatus(tradeid) checkSellStatus(tradeid)
# TODO: When trade finishes, delete wormhole file in tmp dir. # TODO: When trade finishes, delete wormhole file in tmp dir.
elif command == "step4": elif command == "step4":
tradeid = args.argument[0] tradeid = args.arguments[0]
checkBuyStatus(tradeid) checkBuyStatus(tradeid)

View File

@ -8,7 +8,8 @@ from xcat.trades import *
import xcat.bitcoinRPC as bitcoinRPC import xcat.bitcoinRPC as bitcoinRPC
db = plyvel.DB('/tmp/testdb', create_if_missing=True) db = plyvel.DB('/tmp/xcatDB', create_if_missing=True)
preimageDB = plyvel.DB('/tmp/preimageDB', create_if_missing=True)
# Takes dict or obj, saves json str as bytes # Takes dict or obj, saves json str as bytes
def create(trade, tradeid): def create(trade, tradeid):
@ -26,8 +27,8 @@ def createByFundtx(trade):
txid = jt['sell']['fund_tx'] txid = jt['sell']['fund_tx']
db.put(b(txid), b(trade)) db.put(b(txid), b(trade))
def get(txid): def get(tradeid):
rawtrade = db.get(b(txid)) rawtrade = db.get(b(tradeid))
tradestr = str(rawtrade, 'utf-8') tradestr = str(rawtrade, 'utf-8')
trade = instantiate(tradestr) trade = instantiate(tradestr)
return trade return trade
@ -38,7 +39,18 @@ def instantiate(trade):
trade = Trade(buy=Contract(tradestr['buy']), sell=Contract(tradestr['sell']), commitment=tradestr['commitment']) trade = Trade(buy=Contract(tradestr['buy']), sell=Contract(tradestr['sell']), commitment=tradestr['commitment'])
return trade return trade
#############################################
###### Preimages stored by tradeid ##########
#############################################
# Stores secret locally in key/value store by tradeid
def save_secret(tradeid, secret):
res = preimageDB.put(b(tradeid), b(secret))
def get_secret(tradeid):
secret = preimageDB.get(b(tradeid))
secret = str(secret, 'utf-8')
return secret
# db.delete(b'hello') # db.delete(b'hello')
# testtrade = get('test') # testtrade = get('test')

View File

@ -6,6 +6,7 @@ import xcat.bitcoinRPC as bitcoinRPC
from xcat.utils import * from xcat.utils import *
from xcat.trades import Contract, Trade from xcat.trades import Contract, Trade
import xcat.userInput as userInput import xcat.userInput as userInput
import xcat.db as db
def find_secret_from_fundtx(currency, p2sh, fundtx): def find_secret_from_fundtx(currency, p2sh, fundtx):
print("Fund tx in protocol.py", fundtx) print("Fund tx in protocol.py", fundtx)
@ -162,7 +163,8 @@ def buyer_fulfill(trade):
print("Please wait for the seller to remove your funds from escrow to complete the trade.") print("Please wait for the seller to remove your funds from escrow to complete the trade.")
print_trade('buyer') print_trade('buyer')
def seller_init(trade): def seller_init(tradeid):
trade = Trade()
# TODO: pass in amounts, or get from cli. {"amounts": {"buy": {}, "sell": {}}} # TODO: pass in amounts, or get from cli. {"amounts": {"buy": {}, "sell": {}}}
amounts = userInput.get_trade_amounts() amounts = userInput.get_trade_amounts()
sell = amounts['sell'] sell = amounts['sell']
@ -183,8 +185,10 @@ def seller_init(trade):
print(trade.sell.__dict__) print(trade.sell.__dict__)
print(trade.buy.__dict__) print(trade.buy.__dict__)
secret = userInput.create_password() secret = generate_password()
save_secret(secret) db.save_secret(tradeid, secret)
print("\nGenerated a secret preimage to lock funds. This will only be stored locally: ", secret)
hash_of_secret = sha256(secret) hash_of_secret = sha256(secret)
# TODO: Implement locktimes and mock block passage of time # TODO: Implement locktimes and mock block passage of time
sell_locktime = 20 sell_locktime = 20

View File

@ -1,4 +1,5 @@
from xcat.utils import * from xcat.utils import *
from xcat.db import *
def enter_trade_id(): def enter_trade_id():
tradeid = input("Enter a unique identifier for this trade: ") tradeid = input("Enter a unique identifier for this trade: ")
@ -26,23 +27,6 @@ def get_trade_amounts():
amounts['buy'] = buy amounts['buy'] = buy
return amounts return amounts
def create_password():
secret = input("Initiating trade: Create a password to place the funds in escrow: ")
# TODO: hash and store secret only locally.
if secret == '':
secret = generate_password()
print('Remember your password:', secret)
# Saving secret locally for now
save_secret(secret)
return secret
def retrieve_password():
secret = input("Enter the secret you used to lock the funds in order to redeem:")
if secret == '':
secret = get_secret()
print(secret)
return secret
def authorize_fund_sell(htlcTrade): def authorize_fund_sell(htlcTrade):
print('To complete your sell, send {0} {1} to this p2sh: {2}'.format(htlcTrade.sell.amount, htlcTrade.sell.currency, htlcTrade.sell.p2sh)) print('To complete your sell, send {0} {1} to this p2sh: {2}'.format(htlcTrade.sell.amount, htlcTrade.sell.currency, htlcTrade.sell.p2sh))
response = input("Type 'enter' to allow this program to send funds on your behalf.") response = input("Type 'enter' to allow this program to send funds on your behalf.")

View File

@ -2,6 +2,9 @@ import hashlib, json, random, binascii
import xcat.trades as trades import xcat.trades as trades
import xcat.bitcoinRPC as bitcoinRPC import xcat.bitcoinRPC as bitcoinRPC
import xcat.zcashRPC as zcashRPC import xcat.zcashRPC as zcashRPC
import os
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
############################################ ############################################
########### Data conversion utils ########## ########### Data conversion utils ##########
@ -63,38 +66,30 @@ def is_myaddr(address):
########### Preimage utils ################# ########### Preimage utils #################
############################################ ############################################
def generate_password():
s = "1234567890abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
passlen = 32
p = "".join(random.sample(s,passlen))
return p
def sha256(secret): def sha256(secret):
preimage = secret.encode('utf8') preimage = secret.encode('utf8')
h = hashlib.sha256(preimage).digest() h = hashlib.sha256(preimage).digest()
return h return h
def generate_password():
s = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
passlen = 8
p = "".join(random.sample(s,passlen))
return p
# caching the secret locally for now...
def get_secret():
with open('xcat/secret.json') as data_file:
for line in data_file:
return line.strip('\n')
def save_secret(secret):
with open('xcat/secret.json', 'w+') as outfile:
outfile.write(secret)
############################################# #############################################
######### xcat.json temp file ############# ######### xcat.json temp file #############
############################################# #############################################
xcatjson = os.path.join(ROOT_DIR, '.tmp/xcat.json')
def save_trade(trade): def save_trade(trade):
print("Trade in save_trade", trade) print("Trade in save_trade", trade)
with open('xcat/xcat.json', 'w+') as outfile: with open(xcatjson, 'w+') as outfile:
json.dump(trade, outfile) json.dump(trade, outfile)
def get_trade(): def get_trade():
with open('xcat/xcat.json') as data_file: with open(xcatjson) as data_file:
xcatdb = json.load(data_file) xcatdb = json.load(data_file)
sell = trades.Contract(xcatdb['sell']) sell = trades.Contract(xcatdb['sell'])
buy = trades.Contract(xcatdb['buy']) buy = trades.Contract(xcatdb['buy'])
@ -102,7 +97,7 @@ def get_trade():
return trade return trade
def erase_trade(): def erase_trade():
with open('xcat.json', 'w') as outfile: with open(xcatjson, 'w') as outfile:
outfile.write('') outfile.write('')
def save(trade): def save(trade):

View File

@ -1 +0,0 @@
{"commitment": "ecd72edc27561378233ce2208358238fbd329f330bdd37596ff333a6a01323cd", "buy": {"redeemblocknum": 133, "p2sh": "t2PBPZSfLa9jBm2XyXtBF4GxnV65zdor9Q3", "locktime": 10, "fund_tx": "3b8ddbda1204f92d338e719772804395de0e9c8baaf50535edfa2a24ee4f22f2", "amount": 0.02, "redeem_tx": "549b73694a435f5db79e6dd21d39f9ac60cfbdf8ca15ed96f20cc5e66fb63e21", "currency": "zcash", "redeemScript": "63a820ecd72edc27561378233ce2208358238fbd329f330bdd37596ff333a6a01323cd8876a91465741c273525f5f4622d4b22b47168dab3055dc167028500b17576a914c04b595fc34f553ee756f9d9ad824462e75f4bfc6888ac", "initiator": "tmJxng1U3EMJaTRSDFT2SZZxCmXdJ7NRhZv", "fulfiller": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc"}, "sell": {"redeemblocknum": 1081, "p2sh": "2NAycoLt43cPiXobAbASMkS6MwTWGpHbhio", "fund_tx": "e00144584303af28028bd51053bd67ae2cc085461b84bf4ee3fda30d14690763", "amount": 0.01, "redeem_tx": "57c4997351a588fd7694648aa5e7a6326cd83a4195e3f843340918334ed32d3f", "currency": "bitcoin", "redeemScript": "63a820ecd72edc27561378233ce2208358238fbd329f330bdd37596ff333a6a01323cd8876a914a581a5faa98ffb1cbe3ee75e1b4945ff18ec231e67023904b17576a914208462e3b373cf9e2b0b16e0d59eeb066f4873856888ac", "initiator": "miUtWZ2n71X3yahNu52eradR8vJxQRGw3Z", "fulfiller": "mvc56qCEVj6p57xZ5URNC3v7qbatudHQ9b"}}