Repackage as python module

This commit is contained in:
Jay Graber 2017-07-28 17:23:32 -07:00
parent 043958b840
commit 94abea7bc2
21 changed files with 147 additions and 61 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.pyc *.pyc
xcatdb/ xcatdb/
xcat.egg-info/

View File

@ -1,2 +0,0 @@
python-bitcoinlib
plyvel

View File

@ -1 +0,0 @@
2E8ASX0w

17
setup.py Normal file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env python
from setuptools import setup, find_packages
from xcat import version
setup(
name="xcat",
version=version,
entry_points = {
"console_scripts": ['xcat = xcat.cli:main']
},
description="Xcat is a package to facilitate cross-chain atomic transactions.",
author="arcalinea and arielgabizon",
author_email="xcat@z.cash",
license="MIT",
url="http://github.com/zcash/xcat",
packages=find_packages()
)

7
xcat-runner.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from xcat.xcat import main
if __name__ == '__main__':
main()

5
xcat/__init__.py Normal file
View File

@ -0,0 +1,5 @@
"""
Xcat is an implementation of a cross-chain atomic transaction. The protocol currently support trades between Zcash and Bitcoin.
"""
version_info = (0, 1)
version = '.'.join(map(str, version_info))

2
xcat/__main__.py Normal file
View File

@ -0,0 +1,2 @@
from .cli import main
main()

View File

@ -14,13 +14,13 @@ from bitcoin.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_ENDIF, OP_HA
from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH
from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret, P2SHBitcoinAddress, P2PKHBitcoinAddress from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret, P2SHBitcoinAddress, P2PKHBitcoinAddress
from utils import * from xcat.utils import *
import zcash import zcash
import zcash.rpc import zcash.rpc
import pprint, json import pprint, json
from zXcat import parse_script from xcat.zcashRPC import parse_script
# SelectParams('testnet') # SelectParams('testnet')
SelectParams('regtest') SelectParams('regtest')

View File

@ -1,14 +1,16 @@
import argparse, textwrap import argparse, textwrap
from utils import * from xcat.utils import *
import database as db import xcat.database as db
import bXcat, zXcat import xcat.bitcoinRPC
from trades import * import xcat.zcashRPC
from xcat import * import xcat.userInput
from xcat.trades import *
from xcat.protocol import *
import ast import ast
def save_state(trade): def save_state(trade, tradeid):
save(trade) save(trade)
db.create db.create(trade, tradeid)
def checkSellStatus(trade): def checkSellStatus(trade):
if trade.buy.get_status() == 'funded': if trade.buy.get_status() == 'funded':
@ -49,38 +51,58 @@ def checkBuyStatus(trade):
print("TXID after buyer redeem", txid) print("TXID after buyer redeem", txid)
print("XCAT trade complete!") print("XCAT trade complete!")
# Import a trade in hex, and save to db
def importtrade(hexstr):
trade = x2s(hexstr)
trade = instantiateTrade(ast.literal_eval(trade))
save_state(trade)
# Export a trade by its tradeid
def exporttrade(tradeid):
# trade = get_trade()
trade = db.get(tradeid)
hexstr = s2x(str(trade))
print(trade)
print(hexstr)
def newtrade(tradeid):
erase_trade()
role = 'seller'
print("Creating new XCAT trade...")
trade = seller_init(Trade())
# Save it to leveldb
# db.create(trade)
save_state(trade, tradeid)
def instantiateTrade(trade): def instantiateTrade(trade):
return Trade(buy=Contract(trade['buy']), sell=Contract(trade['sell'])) return Trade(buy=Contract(trade['buy']), sell=Contract(trade['sell']))
if __name__ == '__main__': def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent('''\ description=textwrap.dedent('''\
== Trades == == Trades ==
newtrade - create a new trade newtrade - create a new trade
checktrades - check for actions to be taken on existing trades checktrades - check for actions to be taken on existing trades
importtrade "hexstr" - import an existing trade from a hex string importtrade "hexstr" - import an existing trade from a hex string
exporttrade - export the data of an existing xcat trade as a hex string exporttrade - export the data of an existing trade as a hex string. Takes the tradeid as an argument
findtrade - find a trade by the txid of the currency being traded out of findtrade - find a trade by the txid of the currency being traded out of
''')) '''))
parser.add_argument("command", action="store", help="list commands") parser.add_argument("command", action="store", help="list commands")
parser.add_argument("argument", action="store", nargs="*", help="add an argument") parser.add_argument("argument", action="store", nargs="*", help="add an argument")
# parser.add_argument("--daemon", "-d", action="store_true", help="Run as daemon process") # parser.add_argument("--daemon", "-d", action="store_true", help="Run as daemon process")
# TODO: function to view available trades
# TODO: function to tell if tradeid already exists for newtrade
args = parser.parse_args() args = parser.parse_args()
# how to hold state of role # how to hold state of role
command = args.command command = args.command
if command == 'importtrade': if command == 'importtrade':
hexstr = args.argument[0] hexstr = args.argument[0]
trade = x2s(hexstr) importtrade(hexstr)
trade = instantiateTrade(ast.literal_eval(trade))
save_state(trade)
# print(trade.toJ)
elif command == 'exporttrade': elif command == 'exporttrade':
trade = get_trade() tradeid = args.argument[0]
hexstr = s2x(str(trade)) exporttrade(tradeid)
print(trade)
print(hexstr)
elif command == 'checktrades': elif command == 'checktrades':
trade = get_trade() trade = get_trade()
trade = instantiateTrade(trade) trade = instantiateTrade(trade)
@ -91,12 +113,12 @@ if __name__ == '__main__':
role = 'buyer' role = 'buyer'
checkBuyStatus(trade) checkBuyStatus(trade)
elif command == 'newtrade': elif command == 'newtrade':
erase_trade() try:
role = 'seller' tradeid = args.argument[0]
print("Creating new XCAT trade...") newtrade(tradeid)
trade = seller_init(Trade()) except:
# Save it to leveldb tradeid = userInput.enter_trade_id()
db.create(trade) newtrade(tradeid)
elif command == "daemon": elif command == "daemon":
#TODO: implement #TODO: implement
print("Run as daemon process") print("Run as daemon process")

View File

@ -1,29 +1,35 @@
import plyvel import plyvel
from utils import * from .utils import *
import binascii import binascii
import sys import sys
import json import json
db = plyvel.DB('/tmp/testdb', create_if_missing=True) db = plyvel.DB('/tmp/testdb', create_if_missing=True)
trade = get_trade() # trade = get_trade()
## txid we retrieve by # ## txid we retrieve by
if trade and trade.sell: # if trade and trade.sell:
if hasattr(trade.sell, 'fund_tx'): # if hasattr(trade.sell, 'fund_tx'):
txid = trade.sell.fund_tx # txid = trade.sell.fund_tx
# Takes object, saves json as bytes # Takes object, saves json as bytes
def create(trade): def create(trade, tradeid):
trade = trade.toJSON() trade = trade.toJSON()
db.put(b(tradeid), b(trade))
# Uses the funding txid as the key to save trade
def createByFundtx(trade):
trade = trade.toJSON()
# # Save trade by initiating txid
jt = json.loads(trade) jt = json.loads(trade)
txid = jt['sell']['fund_tx'] txid = jt['sell']['fund_tx']
# Save trade by initiating txid
db.put(b(txid), b(trade)) db.put(b(txid), b(trade))
def get(txid): def get(txid):
return db.get(b(txid)) return db.get(b(txid))
# db.delete(b'hello') # db.delete(b'hello')
db.get(b'test')
# hexstr = get(txid) # hexstr = get(txid)
# print(x2s(hexstr)) # print(x2s(hexstr))
@ -33,8 +39,9 @@ def print_entries():
with db.iterator() as it: with db.iterator() as it:
for k, v in it: for k, v in it:
j = json.loads(x2s(b2x(v))) j = json.loads(x2s(b2x(v)))
print("Key:", k)
print('val: ', j) print('val: ', j)
print('sell: ', j['sell']) # print('sell: ', j['sell'])
# print_entries() # print_entries()
# txid = '1171aeda64eff388b3568fa4675d0ca78852911109bbe42e0ef11ad6bf1b159e' # txid = '1171aeda64eff388b3568fa4675d0ca78852911109bbe42e0ef11ad6bf1b159e'

View File

@ -1,35 +1,35 @@
import zXcat
import bXcat
from utils import *
from waiting import * from waiting import *
from time import sleep from time import sleep
import json import json
import os, sys import os, sys
from pprint import pprint from pprint import pprint
from trades import Contract, Trade import xcat.zcashRPC
import userInput import xcat.bitcoinRPC
from xcat.utils import *
from xcat.trades import Contract, Trade
import xcat.userInput
def check_p2sh(currency, address): def check_p2sh(currency, address):
if currency == 'bitcoin': if currency == 'bitcoin':
print("Checking funds in Bitcoin p2sh") print("Checking funds in Bitcoin p2sh")
return bXcat.check_funds(address) return bitcoinRPC.check_funds(address)
else: else:
print("Checking funds in Zcash p2sh") print("Checking funds in Zcash p2sh")
return zXcat.check_funds(address) return zcashRPC.check_funds(address)
def create_htlc(currency, funder, redeemer, commitment, locktime): def create_htlc(currency, funder, redeemer, commitment, locktime):
print("Commitment in create_htlc", commitment) print("Commitment in create_htlc", commitment)
if currency == 'bitcoin': if currency == 'bitcoin':
sell_p2sh = bXcat.hashtimelockcontract(funder, redeemer, commitment, locktime) sell_p2sh = bitcoinRPC.hashtimelockcontract(funder, redeemer, commitment, locktime)
else: else:
sell_p2sh = zXcat.hashtimelockcontract(funder, redeemer, commitment, locktime) sell_p2sh = zcashRPC.hashtimelockcontract(funder, redeemer, commitment, locktime)
return sell_p2sh return sell_p2sh
def fund_htlc(currency, p2sh, amount): def fund_htlc(currency, p2sh, amount):
if currency == 'bitcoin': if currency == 'bitcoin':
txid = bXcat.fund_htlc(p2sh, amount) txid = bitcoinRPC.fund_htlc(p2sh, amount)
else: else:
txid = zXcat.fund_htlc(p2sh, amount) txid = zcashRPC.fund_htlc(p2sh, amount)
return txid return txid
# #
# def fund_buy_contract(trade): # def fund_buy_contract(trade):
@ -80,25 +80,25 @@ def create_buy_p2sh(trade, commitment, locktime):
def auto_redeem_p2sh(contract, secret): def auto_redeem_p2sh(contract, secret):
currency = contract.currency currency = contract.currency
if currency == 'bitcoin': if currency == 'bitcoin':
res = bXcat.auto_redeem(contract, secret) res = bitcoinRPC.auto_redeem(contract, secret)
else: else:
res = zXcat.auto_redeem(contract, secret) res = zcashRPC.auto_redeem(contract, secret)
return res return res
def redeem_p2sh(contract, secret): def redeem_p2sh(contract, secret):
currency = contract.currency currency = contract.currency
if currency == 'bitcoin': if currency == 'bitcoin':
res = bXcat.redeem_contract(contract, secret) res = bitcoinRPC.redeem_contract(contract, secret)
else: else:
res = zXcat.redeem_contract(contract, secret) res = zcashRPC.redeem_contract(contract, secret)
return res return res
def parse_secret(chain, txid): def parse_secret(chain, txid):
if chain == 'bitcoin': if chain == 'bitcoin':
secret = bXcat.parse_secret(txid) secret = bitcoinRPC.parse_secret(txid)
else: else:
secret = zXcat.parse_secret(txid) secret = zcashRPC.parse_secret(txid)
#### Main functions determining user flow from command line #### Main functions determining user flow from command line
def buyer_redeem(trade): def buyer_redeem(trade):
@ -112,9 +112,9 @@ def buyer_redeem(trade):
currency = trade.sell.currency currency = trade.sell.currency
# Buy contract is where seller disclosed secret in redeeming # Buy contract is where seller disclosed secret in redeeming
if trade.buy.currency == 'bitcoin': if trade.buy.currency == 'bitcoin':
secret = bXcat.parse_secret(trade.buy.redeem_tx) secret = bitcoinRPC.parse_secret(trade.buy.redeem_tx)
else: else:
secret = zXcat.parse_secret(trade.buy.redeem_tx) secret = zcashRPC.parse_secret(trade.buy.redeem_tx)
print("Found secret in seller's redeem tx", secret) print("Found secret in seller's redeem tx", secret)
redeem_tx = redeem_p2sh(trade.sell, secret) redeem_tx = redeem_p2sh(trade.sell, secret)
setattr(trade.sell, 'redeem_tx', redeem_tx) setattr(trade.sell, 'redeem_tx', redeem_tx)

1
xcat/secret.json Normal file
View File

@ -0,0 +1 @@
OBbU9kny

View File

@ -1,5 +1,5 @@
import zXcat import xcat.zcash
import bXcat import xcat.bitcoin
from xcat import * from xcat import *
htlcTrade = Trade() htlcTrade = Trade()

21
xcat/tests/test_db.py Normal file
View File

@ -0,0 +1,21 @@
import xcat.database as db
import unittest, json
import xcat.trades as trades
class DatabaseTest(unittest.TestCase):
def setUp(self):
self.data = {"sell": {"amount": 3.5, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9147788b4511a25fba1092e67b307a6dcdb6da125d967022a04b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", "redeemblocknum": 1066, "currency": "bitcoin", "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp", "p2sh": "2MuYSQ1uQ4CJg5Y5QL2vMmVPHNJ2KT5aJ6f", "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", "fund_tx": "5c5e91a89a08b2d6698f50c9fd9bb2fa22da6c74e226c3dd63d59511566a2fdb"}, "buy": {"amount": 1.2, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b167023f0db17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", "redeemblocknum": 3391, "currency": "zcash", "locktime": 10, "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ", "p2sh": "t2HP59RpfR34nBCWH4VVD497tkc2ikzgniP", "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY"}, "commitment": "03d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b6"}
self.sell = trades.Contract(self.data['sell'])
def test_create(self):
sell = trades.Contract(self.data['sell'])
buy = trades.Contract(self.data['buy'])
trade = trades.Trade(sell, buy, commitment=self.data['commitment'])
db.create(trade, 'test')
def test_get(self):
trade = db.get('test')
print("Trade")
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1 @@
{"sell": {"amount": 3.5, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9147788b4511a25fba1092e67b307a6dcdb6da125d967022a04b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", "redeemblocknum": 1066, "currency": "bitcoin", "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp", "p2sh": "2MuYSQ1uQ4CJg5Y5QL2vMmVPHNJ2KT5aJ6f", "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", "fund_tx": "5c5e91a89a08b2d6698f50c9fd9bb2fa22da6c74e226c3dd63d59511566a2fdb"}, "buy": {"amount": 1.2, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b167023f0db17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", "redeemblocknum": 3391, "currency": "zcash", "locktime": 10, "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ", "p2sh": "t2HP59RpfR34nBCWH4VVD497tkc2ikzgniP", "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY"}, "commitment": "03d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b6"}

View File

@ -1,4 +1,8 @@
from utils import * from xcat.utils import *
def enter_trade_id():
tradeid = input("Enter a unique identifier for this trade: ")
return tradeid
def get_trade_amounts(): def get_trade_amounts():
amounts = {} amounts = {}

View File

@ -1,5 +1,5 @@
import hashlib, json, random, binascii import hashlib, json, random, binascii
import trades import xcat.trades
############################################ ############################################
########### Data conversion utils ########## ########### Data conversion utils ##########

1
xcat/xcat.json Normal file
View File

@ -0,0 +1 @@
{"sell": {"amount": 3.5, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9147788b4511a25fba1092e67b307a6dcdb6da125d967022a04b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", "redeemblocknum": 1066, "currency": "bitcoin", "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp", "p2sh": "2MuYSQ1uQ4CJg5Y5QL2vMmVPHNJ2KT5aJ6f", "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", "fund_tx": "5c5e91a89a08b2d6698f50c9fd9bb2fa22da6c74e226c3dd63d59511566a2fdb"}, "buy": {"amount": 1.2, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b167023f0db17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", "redeemblocknum": 3391, "currency": "zcash", "locktime": 10, "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ", "p2sh": "t2HP59RpfR34nBCWH4VVD497tkc2ikzgniP", "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY"}, "commitment": "03d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b6"}

View File

@ -16,7 +16,7 @@ from zcash.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_ENDIF, OP_HASH
from zcash.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH from zcash.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH
from zcash.wallet import CBitcoinAddress, CBitcoinSecret, P2SHBitcoinAddress, P2PKHBitcoinAddress from zcash.wallet import CBitcoinAddress, CBitcoinSecret, P2SHBitcoinAddress, P2PKHBitcoinAddress
from utils import * from xcat.utils import *
# SelectParams('testnet') # SelectParams('testnet')
SelectParams('regtest') SelectParams('regtest')