Skip to content

Commit

Permalink
Merge branch 'release/0.1.26'
Browse files Browse the repository at this point in the history
  • Loading branch information
xeroc committed May 29, 2018
2 parents a02e687 + 1c39f06 commit e426a6b
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 64 deletions.
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
# Python Library for PeerPlays

## Master:

[![docs master](https://readthedocs.org/projects/python-peerplays/badge/?version=master)](http://python-peerplays.readthedocs.io/en/latest/)
[![Build Status](https://travis-ci.org/PBSA/python-peerplays.svg?branch=master)](https://travis-ci.org/PBSA/python-peerplays)
[![codecov](https://codecov.io/gh/pbsa/python-peerplays/branch/master/graph/badge.svg)](https://codecov.io/gh/pbsa/python-peerplays)

## Develop:

[![docs master](https://readthedocs.org/projects/python-peerplays/badge/?version=develop)](http://python-peerplays.readthedocs.io/en/latest/)
[![Build Status](https://travis-ci.org/PBSA/python-peerplays.svg?branch=develop)](https://travis-ci.org/PBSA/python-peerplays)
[![codecov](https://codecov.io/gh/pbsa/python-peerplays/branch/develop/graph/badge.svg)](https://codecov.io/gh/pbsa/python-peerplays)


Python Library for PeerPlays
========================
This is a communications library which allows interface with the Peerplays blockchain directly and without the need for a cli_wallet. It provides a wallet interface and can construct any kind of transactions and properly sign them for broadcast.

Installation
------------
## Installation

Install with `pip3`:
```bash
$ pip3 install peerplays
```

$ pip3 install peerplays
11 changes: 6 additions & 5 deletions peerplays/amount.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,7 @@ class Amount(dict):
Amount("1 USD") * 2
Amount("15 GOLD") + Amount("0.5 GOLD")
"""
def __init__(
self,
*args,
**kwargs
):
def __init__(self, *args, **kwargs):
self["asset"] = {}

amount = kwargs.get("amount", None)
Expand Down Expand Up @@ -169,6 +165,11 @@ def __float__(self):
def __int__(self):
return int(self["amount"] * 10 ** self["asset"]["precision"])

def __neg__(self):
a = self.copy()
a["amount"] = -float(a)
return a

def __add__(self, other):
a = self.copy()
if isinstance(other, Amount):
Expand Down
20 changes: 19 additions & 1 deletion peerplays/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class WalletLocked(Exception):
pass


class RPCConnectionRequired(Exception):
""" An RPC connection is required
"""
pass


class AccountExistsException(Exception):
""" The requested account already exists
"""
Expand All @@ -29,6 +35,12 @@ class AssetDoesNotExistsException(Exception):
pass


class InvalidAssetException(Exception):
""" An invalid asset has been provided
"""
pass


class InsufficientAuthorityError(Exception):
""" The transaction requires signature of a higher authority
"""
Expand Down Expand Up @@ -133,7 +145,7 @@ class RuleDoesNotExistException(Exception):


class ObjectNotInProposalBuffer(Exception):
""" Couldn't find object to relative 0.0.x
""" Object was not found in proposal
"""
pass

Expand Down Expand Up @@ -166,3 +178,9 @@ class WrongMemoKey(Exception):
""" The memo provided is not equal the one on the blockchain
"""
pass


class KeyNotFound(Exception):
""" Key not found
"""
pass
6 changes: 4 additions & 2 deletions peerplays/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ def __init__(self, *args, **kwargs):
elif "blockchain_instance" in kwargs and kwargs["blockchain_instance"]:
self.blockchain = kwargs["blockchain_instance"]
else:
if kwargs:
set_shared_config(kwargs)
self.blockchain = shared_blockchain_instance()

@property
Expand Down Expand Up @@ -71,6 +69,10 @@ def set_shared_config(config):
"""
assert isinstance(config, dict)
SharedInstance.config.update(config)
# if one is already set, delete
if SharedInstance.instance:
clear_cache()
SharedInstance.instance = None


shared_peerplays_instance = shared_blockchain_instance
Expand Down
82 changes: 54 additions & 28 deletions peerplays/memo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,40 @@ class Memo(object):
.. code-block:: python
from peerplays.memo import Memo
m = Memo("peerplayseu", "wallet.xeroc")
from bitshares.memo import Memo
m = Memo("bitshareseu", "wallet.xeroc")
m.bitshares.wallet.unlock("secret")
enc = (m.encrypt("foobar"))
print(enc)
>> {'nonce': '17329630356955254641',
'message': '8563e2bb2976e0217806d642901a2855'}
>> {'nonce': '17329630356955254641', 'message': '8563e2bb2976e0217806d642901a2855'}
print(m.decrypt(enc))
>> foobar
To decrypt a memo, simply use
.. code-block:: python
from bitshares.memo import Memo
m = Memo()
m.bitshares.wallet.unlock("secret")
print(memo.decrypt(op_data["memo"]))
if ``op_data`` being the payload of a transfer operation.
"""
def __init__(
self,
from_account,
to_account,
**kwargs
):
def __init__(self, from_account=None, to_account=None, **kwargs):
BlockchainInstance.__init__(self, **kwargs)

self.to_account = Account(
to_account, blockchain_instance=self.blockchain)
self.from_account = Account(
from_account, blockchain_instance=self.blockchain)
if to_account:
self.to_account = Account(to_account, blockchain_instance=self.blockchain)
if from_account:
self.from_account = Account(from_account, blockchain_instance=self.blockchain)

def unlock_wallet(self, *args, **kwargs):
""" Unlock the library internal wallet
"""
self.blockchain.wallet.unlock(*args, **kwargs)
return self

def encrypt(self, memo):
""" Encrypt a memo
Expand All @@ -62,14 +74,16 @@ def encrypt(self, memo):
self.from_account["options"]["memo_key"]
)
if not memo_wif:
raise MissingKeyError(
"Memo key for %s missing!" % self.from_account["name"])
raise MissingKeyError("Memo key for %s missing!" % self.from_account["name"])

if not hasattr(self, 'chain_prefix'):
self.chain_prefix = self.blockchain.prefix

enc = PPYMemo.encode_memo(
PrivateKey(memo_wif),
PublicKey(
self.to_account["options"]["memo_key"],
prefix=self.blockchain.rpc.chain_params["prefix"]
prefix=self.chain_prefix
),
nonce,
memo
Expand All @@ -92,20 +106,32 @@ def decrypt(self, memo):
if not memo:
return None

memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
self.to_account["options"]["memo_key"]
)
if not memo_wif:
raise MissingKeyError(
"Memo key for %s missing!" % self.to_account["name"])
# We first try to decode assuming we received the memo
try:
memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
memo["to"]
)
pubkey = memo["from"]
except KeyNotFound:
try:
# if that failed, we assume that we have sent the memo
memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey(
memo["from"]
)
pubkey = memo["to"]
except KeyNotFound:
# if all fails, raise exception
raise MissingKeyError(
"Non of the required memo keys are installed!"
"Need any of {}".format(
[memo["to"], memo["from"]]))

if not hasattr(self, 'chain_prefix'):
self.chain_prefix = self.blockchain.prefix

# TODO: Use pubkeys of the message, not pubkeys of account!
return PPYMemo.decode_memo(
PrivateKey(memo_wif),
PublicKey(
self.from_account["options"]["memo_key"],
prefix=self.blockchain.rpc.chain_params["prefix"]
),
PublicKey(pubkey, prefix=self.chain_prefix),
memo.get("nonce"),
memo.get("message")
)
4 changes: 2 additions & 2 deletions peerplays/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import logging
from binascii import hexlify, unhexlify
from graphenebase.ecdsa import verify_message, sign_message
from .instance import BlockchainInstance
from peerplaysbase.account import PublicKey
from peerplays.account import Account
from .instance import BlockchainInstance
from .account import Account
from .exceptions import (
InvalidMessageSignature,
AccountDoesNotExistsException,
Expand Down
5 changes: 4 additions & 1 deletion peerplays/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ def process_account(self, message):
""" This is used for processing of account Updates. It will
return instances of :class:peerplays.account.AccountUpdate`
"""
self.on_account(AccountUpdate(message))
self.on_account(AccountUpdate(
message,
blockchain_instance=self.blockchain
))

def listen(self):
""" This call initiates the listening/notification process. It
Expand Down
24 changes: 13 additions & 11 deletions peerplays/peerplays.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,6 @@ def is_connected(self):
def prefix(self):
return self.rpc.chain_params["prefix"]

def newWallet(self, pwd):
""" Create a new wallet. This method is basically only calls
:func:`peerplays.wallet.create`.
:param str pwd: Password to use for the new wallet
:raises peerplays.exceptions.WalletExists: if there is already a
wallet created
"""
self.wallet.create(pwd)

def set_default_account(self, account):
""" Set the default account to be used
"""
Expand Down Expand Up @@ -408,7 +398,7 @@ def new_proposal(
proposal_review,
blockchain_instance=self,
parent=parent,
**kwargs,
**kwargs
)
if parent:
parent.appendOps(proposal)
Expand Down Expand Up @@ -1317,6 +1307,10 @@ def event_update(
"prefix": self.prefix
}

# Do not try to update status of it doesn't change it on the chain
if event["status"] == status:
status = None

if event_group_id:
if event_group_id[0] == "1":
# Test if object exists
Expand Down Expand Up @@ -1365,6 +1359,10 @@ def event_update_status(
account = Account(account)
event = Event(event_id)

# Do not try to update status of it doesn't change it on the chain
if event["status"] == status:
status = None

op = operations.Event_update_status(**{
"fee": {"amount": 0, "asset_id": "1.3.0"},
"event_id": event["id"],
Expand Down Expand Up @@ -1530,6 +1528,10 @@ def betting_market_group_update(
account = Account(account, blockchain_instance=self)
bmg = BettingMarketGroup(betting_market_group_id)

# Do not try to update status of it doesn't change it on the chain
if bmg["status"] == status:
status = None

op_data = {
"fee": {"amount": 0, "asset_id": "1.3.0"},
"betting_market_group_id": bmg["id"],
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ exclude =
build,
# This contains builds of flake8 that we don't want to check
dist
max-complexity = 10
max-complexity = 14
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
ascii = codecs.lookup('ascii')
codecs.register(lambda name, enc=ascii: {True: enc}.get(name == 'mbcs'))

VERSION = '0.1.25'
VERSION = '0.1.26'

setup(
name='peerplays',
Expand Down
2 changes: 1 addition & 1 deletion tests/test_betting.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def test_lists(self):

def test_event_status_update(self):
def get_object(self, *args, **kwargs):
return {"id": "1.18.1234"}
return {"id": "1.18.1234", "status": "finished"}

with mock.patch(
"peerplaysapi.node.PeerPlaysNodeRPC.get_object",
Expand Down
6 changes: 3 additions & 3 deletions tests/test_peerplays.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ def __init__(self, *args, **kwargs):

self.ppy = PeerPlays(
nobroadcast=True,
wif={"active": wif}
wif=[wif]
)
set_shared_peerplays_instance(self.ppy)
self.ppy.set_default_account("init0")
self.mock()
self.mymock()

def mock(self):
def mymock(self):
# Inject test data into cache
_cache = ObjectCache(default_expiration=60 * 60 * 1, no_overwrite=True)
for i in _objects:
Expand Down

0 comments on commit e426a6b

Please sign in to comment.