Skip to content
This repository was archived by the owner on May 16, 2019. It is now read-only.

Commit 6a8df11

Browse files
author
Tom Galloway
committed
Merge branch 'master' into market_listeners_tests
2 parents 2935ba4 + 77abf30 commit 6a8df11

File tree

8 files changed

+86
-96
lines changed

8 files changed

+86
-96
lines changed

README.md

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,49 @@
1+
# OpenBazaar Server
12
[![Build Status](https://travis-ci.org/OpenBazaar/OpenBazaar-Server.svg?branch=master)](https://travis-ci.org/OpenBazaar/OpenBazaar-Server) [![Coverage Status](https://coveralls.io/repos/OpenBazaar/OpenBazaar-Server/badge.svg?branch=master&service=github)](https://coveralls.io/github/OpenBazaar/OpenBazaar-Server?branch=master) [![Slack Status](https://openbazaar-slackin-drwasho.herokuapp.com/badge.svg)](https://openbazaar-slackin-drwasho.herokuapp.com)
23

3-
- This contains most of the backend networking for OpenBazaar. Going forward, the relevant parts of the current OpenBazaar repo will likely be merged into this.
4-
- If you are looking to contribute to the OpenBazaar backend, this is the repo you want to work on.
5-
- The reference client that interacts with the OpenBazaar backend [is found here](https://github.com/OpenBazaar/OpenBazaar-Client)
4+
This repo contains the OpenBazaar networking daemon that can be used to access the p2p network. It establishes connections and maintains
5+
a Kademlia style DHT. Rest and websocket APIs are available for clients to communicate with the daemon.
66

7-
Installation notes:
8-
---------------------
9-
You will need Python 2 and pip installed on your system.
7+
## Install
108

11-
Depending on your configuration, you may also need to install python-dev, libffi-dev and python-pylint-common. If you're on Linux, you can do so using your operating system's standard package manager (ex. `sudo apt-get install python-dev`)
12-
13-
To install all Python requirements, run:
9+
Pre-built installers which bundle the client and server components can be found [here](https://github.com/OpenBazaar/OpenBazaar-Installer/releases).
1410

11+
To install just this server:
1512
```bash
1613
pip install -r requirements.txt
1714
```
1815

19-
Running Unit Tests (optional and non-Windows only)
20-
```
21-
pip install -r test_requirements.txt
22-
bash
23-
make
24-
```
25-
26-
If everything has installed fine, you should get a message that everything went OK.
16+
Depending on your system configuration you may need to install some additional dependencies. You can find more detailed, OS specific, instructions [here](https://slack-files.com/T02FPGBKB-F0KJU1CLX-cbbcf8a02c).
2717

28-
You can now start the server on testnet (recommended at this point) with:
18+
## Usage
2919

3020
```bash
31-
python openbazaard.py start --testnet
21+
python openbazaard.py start --help
3222
```
3323

34-
To run on the regular network:
35-
36-
```bash
37-
python openbazaard.py start
3824
```
39-
40-
Various options, including those related to logging and debugging, can be displayed like so:
41-
42-
```bash
43-
python openbazaard.py start --help
25+
usage: python openbazaard.py start [<args>]
26+
27+
Start the OpenBazaar server
28+
29+
optional arguments:
30+
-h, --help show this help message and exit
31+
-d, --daemon run the server in the background as a daemon
32+
-t, --testnet use the test network
33+
-l LOGLEVEL, --loglevel LOGLEVEL
34+
set the logging level [debug, info, warning, error,
35+
critical]
36+
-p PORT, --port PORT set the network port
37+
-a ALLOWIP, --allowip ALLOWIP
38+
only allow api connections from this ip
39+
-r RESTAPIPORT, --restapiport RESTAPIPORT
40+
set the rest api port
41+
-w WEBSOCKETPORT, --websocketport WEBSOCKETPORT
42+
set the websocket api port
43+
-b HEARTBEATPORT, --heartbeatport HEARTBEATPORT
44+
set the heartbeat port
45+
--pidfile PIDFILE name of the pid file
4446
```
4547

46-
License
47-
---------------------
48+
## License
4849
OpenBazaar Server is licensed under the [MIT License](LICENSE).

api/restapi.py

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -389,21 +389,21 @@ def update_profile(self, request):
389389

390390
u = objects.Profile()
391391
if "name" in request.args:
392-
u.name = request.args["name"][0]
392+
u.name = request.args["name"][0].decode("utf8")
393393
if "location" in request.args:
394394
# This needs to be formatted. Either here or from the UI.
395395
u.location = CountryCode.Value(request.args["location"][0].upper())
396396
if "handle" in request.args:
397397
if blockchainid.validate(request.args["handle"][0], self.keychain.guid.encode("hex")):
398-
u.handle = request.args["handle"][0]
398+
u.handle = request.args["handle"][0].decode("utf8")
399399
self.db.profile.set_temp_handle("")
400400
else:
401401
u.handle = ""
402-
self.db.profile.set_temp_handle(request.args["handle"][0])
402+
self.db.profile.set_temp_handle(request.args["handle"][0].decode("utf8"))
403403
if "about" in request.args:
404-
u.about = request.args["about"][0]
404+
u.about = request.args["about"][0].decode("utf8")
405405
if "short_description" in request.args:
406-
u.short_description = request.args["short_description"][0]
406+
u.short_description = request.args["short_description"][0].decode("utf8")
407407
if "nsfw" in request.args:
408408
p.profile.nsfw = str_to_bool(request.args["nsfw"][0])
409409
if "vendor" in request.args:
@@ -413,17 +413,17 @@ def update_profile(self, request):
413413
if "moderation_fee" in request.args:
414414
u.moderation_fee = round(float(request.args["moderation_fee"][0]), 2)
415415
if "website" in request.args:
416-
u.website = request.args["website"][0]
416+
u.website = request.args["website"][0].decode("utf8")
417417
if "email" in request.args:
418-
u.email = request.args["email"][0]
418+
u.email = request.args["email"][0].decode("utf8")
419419
if "primary_color" in request.args:
420-
u.primary_color = int(request.args["primary_color"][0])
420+
p.profile.primary_color = int(request.args["primary_color"][0])
421421
if "secondary_color" in request.args:
422-
u.secondary_color = int(request.args["secondary_color"][0])
422+
p.profile.secondary_color = int(request.args["secondary_color"][0])
423423
if "background_color" in request.args:
424-
u.background_color = int(request.args["background_color"][0])
424+
p.profile.background_color = int(request.args["background_color"][0])
425425
if "text_color" in request.args:
426-
u.text_color = int(request.args["text_color"][0])
426+
p.profile.text_color = int(request.args["text_color"][0])
427427
if "avatar" in request.args:
428428
u.avatar_hash = unhexlify(request.args["avatar"][0])
429429
if "header" in request.args:
@@ -452,8 +452,10 @@ def add_social_account(self, request):
452452
try:
453453
p = Profile(self.db)
454454
if "account_type" in request.args and "username" in request.args:
455-
p.add_social_account(request.args["account_type"][0], request.args["username"][0],
456-
request.args["proof"][0] if "proof" in request.args else None)
455+
p.add_social_account(request.args["account_type"][0].decode("utf8"),
456+
request.args["username"][0].decode("utf8"),
457+
request.args["proof"][0].decode("utf8") if
458+
"proof" in request.args else None)
457459
else:
458460
raise Exception("Missing required fields")
459461
request.write(json.dumps({"success": True}))
@@ -1061,35 +1063,11 @@ def check_for_payment(self, request):
10611063
request.finish()
10621064
return server.NOT_DONE_YET
10631065
try:
1064-
file_path = DATA_FOLDER + "purchases/unfunded/" + request.args["order_id"][0] + ".json"
1065-
with open(file_path, 'r') as filename:
1066-
order = json.load(filename, object_pairs_hook=OrderedDict)
1067-
c = Contract(self.db, contract=order, testnet=self.protocol.testnet)
10681066
self.protocol.blockchain.refresh_connection()
1069-
c.blockchain = self.protocol.blockchain
1070-
c.notification_listener = self.mserver.protocol.get_notification_listener()
1071-
c.is_purchase = True
1072-
addr = c.contract["buyer_order"]["order"]["payment"]["address"]
1073-
1074-
def history_fetched(ec, history):
1075-
if not ec:
1076-
# pylint: disable=W0612
1077-
# pylint: disable=W0640
1078-
for objid, txhash, index, height, value in history:
1079-
def cb_txpool(ec, result):
1080-
if ec:
1081-
self.protocol.blockchain.fetch_transaction(txhash, cb_chain)
1082-
else:
1083-
c.on_tx_received(None, None, None, None, result)
1084-
1085-
def cb_chain(ec, result):
1086-
if not ec:
1087-
c.on_tx_received(None, None, None, None, result)
1088-
1089-
self.protocol.blockchain.fetch_txpool_transaction(txhash, cb_txpool)
1090-
1091-
self.protocol.blockchain.fetch_history2(addr, history_fetched)
1092-
1067+
check_order_for_payment(request.args["order_id"][0], self.db,
1068+
self.protocol.blockchain.refresh_connection(),
1069+
self.mserver.protocol.get_notification_listener(),
1070+
self.protocol.testnet)
10931071
request.write(json.dumps({"success": True}, indent=4))
10941072
request.finish()
10951073
return server.NOT_DONE_YET
@@ -1182,7 +1160,7 @@ def history_fetched(ec, history):
11821160
@authenticated
11831161
def dispute_contract(self, request):
11841162
try:
1185-
self.mserver.open_dispute(request.args["order_id"][0], request.args["claim"][0])
1163+
self.mserver.open_dispute(request.args["order_id"][0], request.args["claim"][0].decode("utf8"))
11861164
request.write(json.dumps({"success": True}, indent=4))
11871165
request.finish()
11881166
return server.NOT_DONE_YET
@@ -1204,7 +1182,7 @@ def cb(resp):
12041182
request.finish()
12051183

12061184
d = self.mserver.close_dispute(request.args["order_id"][0],
1207-
request.args["resolution"][0],
1185+
request.args["resolution"][0].decode("utf8"),
12081186
request.args["buyer_percentage"][0],
12091187
request.args["vendor_percentage"][0],
12101188
request.args["moderator_percentage"][0],

api/ws.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def dataReceived(self, payload):
272272
elif request_json["request"]["command"] == "send_message":
273273
self.send_message(message_id, request_json["request"]["guid"],
274274
request_json["request"]["handle"],
275-
request_json["request"]["message"],
275+
request_json["request"]["message"].decode("utf8"),
276276
request_json["request"]["subject"],
277277
request_json["request"]["message_type"],
278278
request_json["request"]["public_key"])

config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from ConfigParser import ConfigParser
1313
from urlparse import urlparse
1414

15-
PROTOCOL_VERSION = 14
15+
PROTOCOL_VERSION = 1
1616
CONFIG_FILE = join(os.getcwd(), 'ob.cfg')
1717

1818
# FIXME probably a better way to do this. This curretly checks two levels deep.
@@ -92,7 +92,7 @@ def _platform_agnostic_data_folder(data_folder):
9292
elif _is_linux():
9393
name = '.openbazaar'
9494
else:
95-
name = 'OpenBazaar'
95+
name = join(os.getenv('APPDATA'), 'OpenBazaar')
9696

9797
return name
9898

db/datastore.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ def _create_database(database_path):
157157
cursor.execute('''CREATE INDEX index_listing ON ratings(listing);''')
158158
cursor.execute('''CREATE INDEX index_rating_id ON ratings(ratingID);''')
159159

160+
cursor.execute('''CREATE TABLE transactions(tx BLOB);''')
161+
160162
cursor.execute('''CREATE TABLE settings(id INTEGER PRIMARY KEY, refundAddress TEXT, currencyCode TEXT,
161163
country TEXT, language TEXT, timeZone TEXT, notifications INTEGER, shippingAddresses BLOB, blocked BLOB,
162164
termsConditions TEXT, refundPolicy TEXT, moderatorList BLOB, username TEXT, password TEXT)''')
@@ -563,16 +565,19 @@ def get_conversations(self):
563565
val = cursor.fetchone()
564566
if val[0] is not None:
565567
avatar_hash = None
568+
handle = ""
566569
try:
567570
with open(DATA_FOLDER + 'cache/' + g[0], "r") as filename:
568571
profile = filename.read()
569572
p = objects.Profile()
570573
p.ParseFromString(profile)
571574
avatar_hash = p.avatar_hash.encode("hex")
575+
handle = p.handle
572576
except Exception:
573577
pass
574578
ret.append({"guid": g[0],
575579
"avatar_hash": avatar_hash,
580+
"handle": handle,
576581
"last_message": val[1],
577582
"timestamp": val[2],
578583
"public_key": val[3].encode("hex"),

market/contracts.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ def add_purchase_info(self,
349349
order_json["buyer_order"]["order"]["payment"]["redeem_script"] = redeem_script.encode("hex")
350350
payment_address = str(P2SHBitcoinAddress.from_redeemScript(redeem_script))
351351
order_json["buyer_order"]["order"]["payment"]["address"] = payment_address
352+
order_json["buyer_order"]["order"]["payment"]["refund_tx_fee"] = TRANSACTION_FEE
352353
else:
353354
chaincode = sha256(str(random.getrandbits(256))).digest().encode("hex")
354355
order_json["buyer_order"]["order"]["payment"]["chaincode"] = chaincode
@@ -632,10 +633,10 @@ def add_receipt(self,
632633
signatures.append(signature_obj)
633634

634635
receipt_json["buyer_receipt"]["receipt"]["payout"] = {}
635-
if tx.multisign(signatures, redeem_script):
636-
tx.broadcast(self.blockchain)
637-
self.log.info("broadcasting payout tx %s to network" % tx.get_hash())
638-
receipt_json["buyer_receipt"]["receipt"]["payout"]["txid"] = tx.get_hash()
636+
tx.multisign(signatures, redeem_script)
637+
tx.broadcast(self.blockchain)
638+
self.log.info("broadcasting payout tx %s to network" % tx.get_hash())
639+
receipt_json["buyer_receipt"]["receipt"]["payout"]["txid"] = tx.get_hash()
639640

640641
receipt_json["buyer_receipt"]["receipt"]["payout"]["signature(s)"] = buyer_signatures
641642
receipt_json["buyer_receipt"]["receipt"]["payout"]["value"] = tx.get_out_value()
@@ -975,10 +976,13 @@ def process_refund(self, refund_json, blockchain, notification_listener):
975976
outpoints = json.loads(self.db.purchases.get_outpoint(order_id))
976977
refund_address = self.contract["buyer_order"]["order"]["refund_address"]
977978
redeem_script = self.contract["buyer_order"]["order"]["payment"]["redeem_script"]
978-
value = int(float(refund_json["refund"]["value"]) * 100000000)
979+
in_value = 0
980+
for outpoint in outpoints:
981+
in_value += outpoint["value"]
982+
out_value = in_value - long(self.contract["buyer_order"]["order"]["payment"]["refund_tx_fee"])
979983
tx = BitcoinTransaction.make_unsigned(outpoints, refund_address,
980984
testnet=self.testnet,
981-
out_value=value)
985+
out_value=out_value)
982986
chaincode = self.contract["buyer_order"]["order"]["payment"]["chaincode"]
983987
masterkey_b = bitcointools.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey)
984988
buyer_priv = derive_childkey(masterkey_b, chaincode, bitcointools.MAINNET_PRIVATE)
@@ -1000,7 +1004,7 @@ def process_refund(self, refund_json, blockchain, notification_listener):
10001004
tx.broadcast(blockchain)
10011005
self.log.info("broadcasting refund tx %s to network" % tx.get_hash())
10021006

1003-
self.db.sales.update_status(order_id, 7)
1007+
self.db.purchases.update_status(order_id, 7)
10041008
file_path = DATA_FOLDER + "purchases/trade receipts/" + order_id + ".json"
10051009
with open(file_path, 'w') as outfile:
10061010
outfile.write(json.dumps(self.contract, indent=4))
@@ -1020,7 +1024,6 @@ def process_refund(self, refund_json, blockchain, notification_listener):
10201024
handle = ""
10211025
notification_listener.notify(buyer_guid, handle, "refund", order_id, title, image_hash)
10221026

1023-
10241027
def verify(self, sender_key):
10251028
"""
10261029
Validate that an order sent over by a buyer is filled out correctly.
@@ -1328,11 +1331,11 @@ def check_unfunded_for_payment(db, libbitcoin_client, notification_listener, tes
13281331

13291332
def check_order_for_payment(order_id, db, libbitcoin_client, notification_listener, testnet=False):
13301333
try:
1331-
if os.path.exists(DATA_FOLDER + "purchases/unfunded/" + order_id[0] + ".json"):
1332-
file_path = DATA_FOLDER + "purchases/unfunded/" + order_id[0] + ".json"
1334+
if os.path.exists(DATA_FOLDER + "purchases/unfunded/" + order_id + ".json"):
1335+
file_path = DATA_FOLDER + "purchases/unfunded/" + order_id + ".json"
13331336
is_purchase = True
1334-
elif os.path.exists(DATA_FOLDER + "store/contracts/unfunded/" + order_id[0] + ".json"):
1335-
file_path = DATA_FOLDER + "store/contracts/unfunded/" + order_id[0] + ".json"
1337+
elif os.path.exists(DATA_FOLDER + "store/contracts/unfunded/" + order_id + ".json"):
1338+
file_path = DATA_FOLDER + "store/contracts/unfunded/" + order_id + ".json"
13361339
is_purchase = False
13371340
with open(file_path, 'r') as filename:
13381341
order = json.load(filename, object_pairs_hook=OrderedDict)

market/network.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,20 +1024,27 @@ def refund(self, order_id):
10241024
contract["buyer_order"]["order"]["id"]["pubkeys"]["guid"],
10251025
encoder=nacl.encoding.HexEncoder).to_curve25519_public_key()
10261026
refund_address = contract["buyer_order"]["order"]["refund_address"]
1027-
tx = BitcoinTransaction.make_unsigned(outpoints, refund_address,
1028-
testnet=self.protocol.multiplexer.testnet)
10291027
chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"]
10301028
masterkey_v = bitcointools.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey)
10311029
vendor_priv = derive_childkey(masterkey_v, chaincode, bitcointools.MAINNET_PRIVATE)
10321030

10331031
refund_json = {"refund": {}}
10341032
refund_json["refund"]["order_id"] = order_id
10351033
if "moderator" in contract["buyer_order"]["order"]:
1034+
in_value = 0
1035+
for outpoint in outpoints:
1036+
in_value += outpoint["value"]
1037+
out_value = in_value - long(contract["buyer_order"]["order"]["payment"]["refund_tx_fee"])
1038+
tx = BitcoinTransaction.make_unsigned(outpoints, refund_address,
1039+
testnet=self.protocol.multiplexer.testnet,
1040+
out_value=out_value)
10361041
redeem_script = contract["buyer_order"]["order"]["payment"]["redeem_script"]
10371042
sigs = tx.create_signature(vendor_priv, redeem_script)
10381043
refund_json["refund"]["value"] = round(tx.get_out_value() / float(100000000), 8)
10391044
refund_json["refund"]["signature(s)"] = sigs
10401045
else:
1046+
tx = BitcoinTransaction.make_unsigned(outpoints, refund_address,
1047+
testnet=self.protocol.multiplexer.testnet)
10411048
tx.sign(vendor_priv)
10421049
tx.broadcast(self.protocol.multiplexer.blockchain)
10431050
self.log.info("broadcasting refund tx %s to network" % tx.get_hash())

0 commit comments

Comments
 (0)