Giter VIP home page Giter VIP logo

beem's People

Contributors

alexpmorris avatar antonmosich avatar broncotc avatar crokkon avatar dependabot[bot] avatar dkedzierski avatar dnotestein avatar drov0 avatar e-d-a avatar economicstudio avatar emre avatar espoem avatar fxnormaluser avatar grctest avatar holgern avatar mariusz-trela avatar maxpatternman avatar mwfiae avatar netuoso avatar nickfost avatar pablomat avatar photobook-hive avatar pyup-bot avatar sicarius97 avatar skoptci avatar smileychris avatar svitx avatar vogel76 avatar xeroc avatar zapata avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

beem's Issues

Account.history() fails with float division by zero exception

Expected behavior

Account.history(start, stop) with start and stop being datetime instances should return all account operations between the given timestamps

Actual behavior

Account.history(start, stop) sometimes fails with a ZeroDivisionError exception:

Traceback (most recent call last):
  File "history.py", line 15, in <module>
    for op in a.history(start, stop):
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 1566, in history
    op_est = self.estimate_virtual_op_num(start, stop_diff=1)
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 1333, in estimate_virtual_op_num
    op_diff = (blocktime - formatTimeString(trx["timestamp"])).total_seconds() / factor
ZeroDivisionError: float division by zero

How to reproduce

What actually fails is the op number lookup for a given timestamp via Account.estimate_virtual_op_num(). Here's a minimum example to reproduce the problem:

from beem.account import Account
from datetime import datetime, timedelta
from beem.utils import addTzInfo
a = Account("berniesanders")
start = addTzInfo(datetime(2017, 11, 16, 23, 23, 11))
print(a.estimate_virtual_op_num(start))

Output:

# python bug_divbyzero.py 
Traceback (most recent call last):
  File "bug_divbyzero.py", line 9, in <module>
    print(a.estimate_virtual_op_num(start))
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 1333, in estimate_virtual_op_num
    op_diff = (blocktime - formatTimeString(trx["timestamp"])).total_seconds() / factor
ZeroDivisionError: float division by zero

The following quick-hack solves the problem in this case:

diff --git a/beem/account.py b/beem/account.py
index e100a58..c840185 100644
--- a/beem/account.py
+++ b/beem/account.py
@@ -1329,6 +1329,7 @@ class Account(BlockchainObject):
                     factor = (formatTimeString(op_start_last[0][1]["timestamp"]) - formatTimeString(trx["timestamp"])).total_seconds() / diff_op
                 elif not isinstance(blocktime, (datetime, date, time)) and diff_op != 0:
                     factor = (op_start_last[0][1]["block"] - trx["block"]) / diff_op
+                factor = min(1, factor)
             if isinstance(blocktime, (datetime, date, time)):
                 op_diff = (blocktime - formatTimeString(trx["timestamp"])).total_seconds() / factor
             else:

However, there are more instances where a division by factor is done and I'm not sure if the change affects the correctness of the resulting block number.

Environment

# beempy --version
beempy, version 0.19.40
# python --version
Python 3.6.5

Move Changelog from README.rst

With how enormous the changelog is, it makes the README.rst file (which, as the name implies, should be read in it's entirety) much too long.

With the frequent updates to beem, keeping the changelog there is unsustainable. I propose moving it to an another file (changelog.rst?) or into the Wiki pages of the repository.

comment.upvote doesn't work on some cases

Expected behavior

Comment class in beem.comment has a helper method to initiate upvotes called as .upvote.

This should work as expected on all cases.

Actual behavior

Beem fails to create an upvote transaction if the comment will be upvoted doesn't have any vote before. This is happening because of this check on the library.

How to reproduce

Here is a little python script to reproduce the issue:

from beem.comment import Comment
from beem.steem import Steem

ACCOUNT = "<upvoter_account_username>"


def reproduce(s):
    main_comment = Comment("@beemtutorials/test-case-for-beem-upvote", steem_instance=s)
    reply = main_comment.reply("test-comment", author=ACCOUNT)
    reply_comment = Comment(reply["operations"][0][1])
    reply_comment.upvote(+50, voter=ACCOUNT)


def main():
    s = Steem(
        node=["https://rpc.buildteam.io"],
        keys=["<posting_wif>"]
    )
    reproduce(s)


if __name__ == '__main__':
    main()

Stacktrace:

/Users/emre/Environments/beemtutorials/bin/python /Users/emre/Projects/beem_tutorials/repro_bug.py
Traceback (most recent call last):
  File "/Users/emre/Projects/beem_tutorials/repro_bug.py", line 23, in <module>
    main()
  File "/Users/emre/Projects/beem_tutorials/repro_bug.py", line 19, in main
    reproduce(s)
  File "/Users/emre/Projects/beem_tutorials/repro_bug.py", line 11, in reproduce
    reply_comment.upvote(+50, voter=ACCOUNT)
  File "/Users/emre/Environments/beemtutorials/lib/python3.6/site-packages/beem/comment.py", line 555, in upvote
    raise VotingInvalidOnArchivedPost
beem.exceptions.VotingInvalidOnArchivedPost
  • Browser/App version: N/A, beem-0.19.47

  • Operating system: N/A

Connections errors with threaded Blockchain.stream()

Expected behavior

b.stream(start=start, stop=stop, threading=True, thread_num=8) should return all ops from the given block range and fetch the data with 8 threads in the background.

Actual behavior

The script throws lots of connection errors from various nodes and is comparably slow. Running the same call with threading=False works without any error and is typically even faster.

How to reproduce

#!/usr/bin/python
from beem.blockchain import Blockchain
import sys
b = Blockchain()
opcount = 0
for op in b.stream(start=23483000, stop=23483200, threading=True, thread_num=8,
                   opNames=['vote']):
    sys.stdout.write("\r%s" % op['block_num'])
    opcount += 1
print("\n", opcount)

Output:

# time python bug_threading.py 
23483103Error: Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.pevo.science (1/-1) 

Error: rsv is not implemented, yet
Lost connection or internal error on node: wss://steemd.pevo.science (2/-1) 

Error: [Errno 9] Bad file descriptor
Error: Invalid WebSocket Header
Lost connection or internal error on node: wss://steemd.pevo.science (4/-1) 

Lost connection or internal error on node: wss://steemd.pevo.science (4/-1) 

Retrying in 5 seconds

Error: Handshake status 503 Service Temporarily Unavailable
Lost connection or internal error on node: wss://steemd.pevo.science (5/-1) 

Retrying in 6 seconds

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.pevo.science (6/-1) 

Error: Connection is already closed.
Lost connection or internal error on node: wss://steemd.pevo.science (7/-1) 

Retrying in 9 seconds

Error: Handshake status 503 Service Temporarily Unavailable
Lost connection or internal error on node: wss://steemd.pevo.science (8/-1) 

Retrying in 11 seconds

Error: Handshake status 503 Service Temporarily Unavailable
Lost connection or internal error on node: wss://steemd.pevo.science (9/-1) 

Retrying in 12 seconds

Error: Handshake status 503 Service Temporarily Unavailable
Lost connection or internal error on node: wss://steemd.pevo.science (10/-1) 

Retrying in 10 seconds

Error: rsv is not implemented, yet
Lost connection or internal error on node: wss://steemd.pevo.science (11/-1) 

Error: Connection is already closed.
Lost connection or internal error on node: wss://steemd.pevo.science (12/-1) 

Retrying in 10 seconds

23483255Error: Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://rpc.steemviz.com (1/-1) 

Error: [Errno 11] Resource temporarily unavailable
Lost connection or internal error on node: wss://rpc.steemviz.com (2/-1) 

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://rpc.steemviz.com (4/-1) 

Retrying in 5 seconds

Lost connection or internal error on node: wss://rpc.steemviz.com (4/-1) 

Error: [Errno 9] Bad file descriptor
Lost connection or internal error on node: wss://rpc.steemviz.com (5/-1) 

Retrying in 6 seconds

Error: [Errno 9] Bad file descriptor
Lost connection or internal error on node: wss://rpc.steemviz.com (6/-1) 

Retrying in 8 seconds

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://rpc.steemviz.com (8/-1) 

Lost connection or internal error on node: wss://rpc.steemviz.com (8/-1) 

Retrying in 11 seconds

Error: rsv is not implemented, yet
Error: rsv is not implemented, yet
Lost connection or internal error on node: wss://rpc.steemviz.com (10/-1) 

Lost connection or internal error on node: wss://rpc.steemviz.com (10/-1) 

Error: rsv is not implemented, yet
Lost connection or internal error on node: wss://rpc.steemviz.com (11/-1) 

Error: Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://rpc.steemviz.com (12/-1) 

Retrying in 10 seconds

Error: rsv is not implemented, yet
Lost connection or internal error on node: wss://rpc.steemviz.com (13/-1) 

Error: [SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC] decryption failed or bad record mac (_ssl.c:2273)
Lost connection or internal error on node: wss://rpc.steemviz.com (14/-1) 

Retrying in 10 seconds

Error: Connection is already closed.
Lost connection or internal error on node: wss://rpc.steemviz.com (15/-1) 

Retrying in 10 seconds

23483415Error: Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (1/-1) 

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (3/-1) 

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (3/-1) 

Retrying in 3 seconds

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (4/-1) 

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (5/-1) 

Retrying in 6 seconds

Error: rsv is not implemented, yet
Error: Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (7/-1) 

Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (7/-1) 

Retrying in 9 seconds

Error: Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (8/-1) 

Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (9/-1) 

Error: [Errno 9] Bad file descriptor
Error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (11/-1) 

Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (11/-1) 

Retrying in 10 seconds

Error: [Errno 9] Bad file descriptor
Error: 'utf-8' codec can't decode byte 0xf8 in position 0: invalid start byte
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (13/-1) 

Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (13/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (14/-1) 

Retrying in 10 seconds

Error: rsv is not implemented, yet
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (15/-1) 

Error: [SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC] Invalid error code (_ssl.c:2273)
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (16/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (17/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (18/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (19/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (20/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (21/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (22/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (23/-1) 

Retrying in 10 seconds

Error: The read operation timed out
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (24/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (25/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (26/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (27/-1) 

Retrying in 10 seconds

Error: [Errno 111] Connection refused
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (28/-1) 

Retrying in 10 seconds

23483500
 12230

real	4m40.085s
user	0m32.147s
sys	0m1.010s

The script takes considerably long to run and errors are shown from various nodes. The log (across several runs of the script above) contains errors I haven't seen before from typical node/connection issues:

Error: socket is already closed.
Error: rsv is not implemented, yet
Error: Handshake status 400 Bad Reest
Error: invalid literal for int() with base 10: '07:16:40'  # <- this was utcnow() at that time
Error: invalid literal for int() with base 10: 'Tm7e05+XYwFFwwm+UDClM9rFIfo='
Error: invalid literal for int() with base 10: '(Ubuntu)'
Error: Illegal frame
Error: ('Invalid opcode %r', 6)
Error: ('Underlying socket has been closed.',)

The same without threading:

#!/usr/bin/python
from beem.blockchain import Blockchain
import sys
b = Blockchain()
opcount = 0
for op in b.stream(start=23483000, stop=23483500, threading=False, thread_num=8,
                   opNames=['vote']):
    sys.stdout.write("\r%s" % op['block_num'])
    opcount += 1
print("\n", opcount)

Output:

# time python bug_threading.py 
23483500
 12230

real	0m52.549s
user	0m15.767s
sys	0m0.527s

No connection error, and the single-threaded version is faster than the multi-threaded version.

Environment

# beempy --version
beempy, version 0.19.40
# python --version
Python 3.6.5

vests_to_rshares calculation error

Expected behavior

The vests_to_rshares function of the beem.steem module should return the number of rshares a vote by an account dependent on the vests and the voting power the account has, and the vote percentage that account uses for voting.

Actual behavior

Instead, that function returns the rshares that it should return, but 1e6 times smaller. This issue happens because the vests would need to be multiplied with 1e6 in order to be in the right scope for the calculation (relevant tutorial) This would need to be added here.

How to reproduce

  1. from beem.steem import Steem
  2. Get a Steem() instance. (e.g. stm = Steem())
  3. Run the vests_to_rshares function on any number of vests. (e.g. stm.vests_to_rshares(10000000))
  4. Transform the value point 2. returned to SBD using the rshares_to_sbd function. (e.g. stm.rshares_to_sbd(200000))
  5. Run the vests_to_sbd function on the same number of vests as before. (e.g. stm.vests_to_sbd(10000000))
  6. Compare the two values you got in point 3. and 4., and see that the one you got in point 3 is 1e6 times smaller than the other one.

It looks like this in a REPL:

>>> from beem.steem import Steem
>>> stm = Steem()
>>> stm.vests_to_rshares(10000000)
200000

^This is where the issue is. That should be 200000000000 instead

>>> stm.rshares_to_sbd(200000)
3.3005542087518333e-07
>>> stm.vests_to_sbd(10000000)
0.33005542087518336

After applying a fix, it would look like that:

>>> from beem.steem import Steem
>>> stm = Steem()
>>> stm.vests_to_rshares(10000000)
200000000000
>>> stm.rshares_to_sbd(200000000000)
0.33005542087518336
>>> stm.vests_to_sbd(10000000)
0.33005542087518336

Key already in storage

I am getting key already in storage when adding a key to the wallet on the Vit network.
When trying to use the key, it says

beem.exceptions.MissingKeyError

I have tried removing the key, and adding again. No luck.
beempy --node https://jussi.vit.tube listaccounts

Does not show the key.
Key was added (and removed) with --node https://jussi.vit.tube parameter.

It only happens to specific accounts, not all and on specific machines, where other keys work fine, but not some.

Discussions.get_discussions("blog", ...) returns the same two comments over and over

Expected behavior

Discussions.get_discussions('blog', query) should return a number of blog posts from a steem account based on the query parameter.

Actual behavior

Discussions.get_discussions('blog', query) may return the same two posts over and over

How to reproduce

from beem.discussions import Query, Discussions
start_author = "crokkon"
start_permlink = "how-to-find-out-which-of-your-steem-apps-just-acted-in-your-name"
query_limit = 20
query = Query(start_author=start_author,
              start_permlink=start_permlink, limit=query_limit,
              tag=start_author)
dis = Discussions()
count = 0
for d in dis.get_discussions("blog", query):
    print(("%d. " % (count + 1)) + str(d))
    count += 1

Output:

1. <Comment @crokkon/how-to-find-out-which-of-your-steem-apps-just-acted-in-your-name>
2. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
3. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
4. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
5. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
6. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
7. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
8. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
9. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
10. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
11. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
12. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
13. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
14. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
15. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
16. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
17. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
18. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
19. <Comment @crokkon/cashout-chains-steem-from-7400-accounts-leaves-steem-via-only-a-few-accounts>
20. <Comment @paulag/business-intelligence-steemit-weekly-contest-11-and-winner-10>
...

Environment

  • beem at rev. e9ee462
  • python 3.6.5

beempy power gives divide by zero error for accounts with 0 SP

Hello,

In playing around with beempy this morning I found that since accounts can be created with 0 SP, using beempy to look up account power can lead to division by zero:

$ beempy power scms-sc

@scms-sc
Traceback (most recent call last):
  File "/Environments/alpha/bin/beempy", line 11, in <module>
    sys.exit(cli())
  File "/Environments/alpha/lib/python3.6/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/Environments/alpha/lib/python3.6/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/Environments/alpha/lib/python3.6/site-packages/click/core.py", line 1163, in invoke
    rv.append(sub_ctx.command.invoke(sub_ctx))
  File "/Environments/alpha/lib/python3.6/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Environments/alpha/lib/python3.6/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/Environments/alpha/lib/python3.6/site-packages/beem/cli.py", line 974, in power
    a.print_info(use_table=True)
  File "/Environments/alpha/lib/python3.6/site-packages/beem/account.py", line 320, in print_info
    vote_mana = self.get_manabar()
  File "/Environments/alpha/lib/python3.6/site-packages/beem/account.py", line 403, in get_manabar
    estimated_pct = estimated_mana / estimated_max * 100
ZeroDivisionError: division by zero

I'm sorry I don't know the fix (adding some prettier error handling code somewhere?), I don't know much python.

discussions may fail to handle empty responses correctly

Expected behavior

discussions.Discussions_by_feed() should return an account's feed entries. If the account doesn't follow any other account, the result should be empty.

Actual behavior

discussions.Discussions_by_feed() returns an account's feed entries if there are entries available. If there are no entries available, beem iterates over all nodes and fails to return an empty result.

How to reproduce

from beem.discussions import Discussions_by_feed, Query
from beem.account import Account
account = Account('stmdev')
query = Query(limit=20, tag=account['name'])
for entry in Discussions_by_feed(query):
    print(entry)

Result:

Error: Empty Reply
Lost connection or internal error on node: wss://steemd.minnowsupportproject.org (1/-1) 

Error: Empty Reply
Lost connection or internal error on node: wss://rpc.steemviz.com (1/-1) 

Error: Empty Reply
Lost connection or internal error on node: wss://rpc.buildteam.io (1/-1) 

Error: Empty Reply
Lost connection or internal error on node: wss://steemd.privex.io (1/-1) 

Error: Empty Reply
Lost connection or internal error on node: https://api.steemit.com (1/-1) 

Error: Empty Reply
Lost connection or internal error on node: https://rpc.buildteam.io (1/-1) 

Error: Empty Reply
Lost connection or internal error on node: https://rpc.steemviz.com (1/-1) 
...

The reason is that beem by default switches to the next node if an RPC reply is empty. However, an empty reply is the correct reply in this case. Some classes in beem.discussions are missing the corresponding code to handle this situation:

        self.steem.rpc.set_next_node_on_empty_reply(self.steem.rpc.get_use_appbase())

Environment

  • beem master at rev. aa74d03
  • python 3.6.5

blockchain.get_all_accounts() fails for limit > steps on appbase

Expected behavior

blockchain.get_all_accounts(limit=2000, steps=1000) returns 2000 account names while internally doing two batch calls of 1000 accounts each. This should work on both appbase and non-appbase nodes

Actual behavior

blockchain.get_all_accounts(limit=2000, steps=1000) fails on appbase nodes when limit > steps

How to reproduce

>>> from beem import Steem
>>> from beem.blockchain import Blockchain
>>> s = Steem(node='https://api.steemit.com')
>>> s.rpc.get_use_appbase()
True
>>> len(list(b.get_all_accounts(limit=1000, steps=1000)))
1000
>>> len(list(b.get_all_accounts(limit=2000, steps=1000)))
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/beemapi/steemnoderpc.py", line 65, in rpcexec
    reply = super(SteemNodeRPC, self).rpcexec(payload)
  File "/usr/local/lib/python3.6/site-packages/beemapi/graphenerpc.py", line 381, in rpcexec
    raise RPCError(ret['error']['message'])
beemapi.exceptions.RPCError: Bad Cast:Invalid cast from object_type to string

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/beem/blockchain.py", line 562, in get_all_accounts
    ret = self.steem.rpc.list_accounts({'start': lastname, 'limit': steps, 'order': 'by_name'}, api="database")["accounts"]
  File "/usr/local/lib/python3.6/site-packages/beemapi/graphenerpc.py", line 430, in method
    r = self.rpcexec(query)
  File "/usr/local/lib/python3.6/site-packages/beemapi/steemnoderpc.py", line 87, in rpcexec
    doRetry = self._check_error_message(e, self.error_cnt_call)
  File "/usr/local/lib/python3.6/site-packages/beemapi/steemnoderpc.py", line 146, in _check_error_message
    raise exceptions.UnhandledRPCError(msg)
beemapi.exceptions.UnhandledRPCError: Bad Cast:Invalid cast from object_type to string

It works on non-appbase nodes:

>>> s = Steem("wss://steemd.pevo.science")
>>> s.rpc.get_use_appbase()
False
>>> b = Blockchain(steem_instance=s)
>>> len(list(b.get_all_accounts(limit=2000, steps=1000)))
2000

Environment

# beempy --version
beempy, version 0.19.37
# python --version
Python 3.6.5

DivisionByZero Error in Account.get_rc_manabar()

Expected Behavior

Account.get_rc_manabar() should return the current RC mana state of an Account

Actual Behavior

Account.get_rc_manabar() may raise a ZeroDivisionError exception if the corresponding account has a max_rc bandwidth of 0.

How to reproduce

from beem.account import Account
a = Account('a-pile-of-steem')
print(a.get_rc_manabar())
Traceback (most recent call last):
  File "bug_rc.py", line 3, in <module>
    print(a.get_rc_manabar())
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 241, in get_rc_manabar
    current_pct = current_mana / max_mana * 100
ZeroDivisionError: division by zero

Environment

# beempy --version
beempy, version 0.20.6
# python --version
Python 3.6.6

unable to get only the first op via account.history() and account.get_account_history()

Expected behavior

account.history() and account.get_account_history() should return only the first blockchain operation of an account when called with start=0, stop=0, use_block_num=False.

Actual behavior

account.history() returns the full history and account.get_account_history() returns limit+1 operations when called with start=0, stop=0, use_block_num=False.

How to reproduce

from beem.account import Account
import sys
opnum = int(sys.argv[1])
a = Account("stmdev")
ops = list(a.history(opnum, opnum, use_block_num=False))
print("a.history() returned %d ops" % (len(ops)))

ops = list(a.history_reverse(opnum, opnum, use_block_num=False))
print("a.history_reverse() returned %d ops" % (len(ops)))

ops = list(a.get_account_history(index=opnum+1, limit=opnum+1,
                                 start=opnum, stop=opnum,
                                 use_block_num=False))
print("a.get_account_history() returned %d ops" % (len(ops)))

Output:

# python getop.pyy 0
a.history() returned 1756 ops
a.history_reverse() returned 1 ops
a.get_account_history() returned 2 ops

The same for operation number 1 works:

# python getop.py 1
a.history() returned 1 ops
a.history_reverse() returned 1 ops
a.get_account_history() returned 1 ops

Environment

# beempy --version
beempy, version 0.19.34
# python --version
Python 3.6.5

Possible fix

history(), history_reverse(), and get_account_history() check for if start / if stop at several stages, however this check is False for both None and 0. Changing those checks to if start is not None / if stop is not None could solve this:

# python getop.py.py 0
a.history() returned 1 ops
a.history_reverse() returned 1 ops
a.get_account_history() returned 1 ops

# python getop.py.py 1
a.history() returned 1 ops
a.history_reverse() returned 1 ops
a.get_account_history() returned 1 ops

Unable to set beneficiaries via steem.post()

Expected behavior

steem.post() brings two options to set beneficiaries:

  • via a parameter comment_options in the form of:
            comment_options = {
                'max_accepted_payout': '1000000.000 SBD',
                'percent_steem_dollars': 10000,
                'allow_votes': True,
                'allow_curation_rewards': True,
                'extensions': [[0, {
                    'beneficiaries': [
                        {'account': 'account1', 'weight': 5000},
                        {'account': 'account2', 'weight': 5000},
                    ]}
                ]]
            }
  • via a parameter beneficiaries in the form of:
            beneficiaries = [
                {'account': 'account1', 'weight': 5000},
                {'account': 'account2', 'weight': 5000}
            ]

The list in beneficiaries is supposed to override the settings in the comment_options if both parameters are present.

Actual behavior

It is not possible to set beneficiaries using either method.

  1. via comment_options, dry run, creating an unsigned transaction that is not broadcasted:
from beem import Steem
import json

s = Steem(nobroadcast=True, unsigned=True)

comment_options = {
    'max_accepted_payout': '1000000.000 SBD',
    'percent_steem_dollars': 10000,
    'allow_votes': True,
    'allow_curation_rewards': True,
    'extensions': [[0, {
        'beneficiaries': [
            {'account': 'account1', 'weight': 5000},
            {'account': 'account2', 'weight': 5000},
        ]}
    ]]
}

tx = s.post(title="title", body="body", permlink="permlink",
            author="author", comment_options=comment_options,
            beneficiaries=None)

print(json.dumps(tx, indent=2))

Result:

[...]
    [
      "comment_options",
      {
        "author": "author",
        "permlink": "permlink",
        "max_accepted_payout": "1000000.000 SBD",
        "percent_steem_dollars": 10000,
        "allow_votes": true,
        "allow_curation_rewards": true,
        "extensions": []
      }
    ]

The resulting extensions field is empty, the post will be created but without beneficiaries.

  1. via the beneficiary parameter:
from beem import Steem
import cfg_stmdev as cfg
import time
import json

s = Steem(keys=[cfg.POSTING_WIF], nobroadcast=False)

comment_options = {
    'max_accepted_payout': '1000000.000 SBD',
    'percent_steem_dollars': 10000,
    'allow_votes': True,
    'allow_curation_rewards': True,
}

beneficiaries = [{'account': 'stmdev', 'weight': 1000}]

reply_identifier = '@stmdev/pwdtest'
timestamp = int(time.time())

permlink = 'reply-case-1-%s' % timestamp
body = "%s %s" % (comment_options, beneficiaries)
tx = s.post(title=permlink, body=body, permlink=permlink,
            author=cfg.ACCOUNT, reply_identifier=reply_identifier,
            comment_options=comment_options,
            beneficiaries=beneficiaries)

print(json.dumps(tx, indent=2))

The list of beneficiaries is now part of the transaction, but the operation fails with a missing required posting authority exception:

[...]
{"ops":[["comment",{"parent_author":"stmdev","parent_permlink":"pwdtest","author":"stmdev","permlink":"reply-case-1-1528013878","title":"reply-case-1-1528013878","body":"{'max_accepted_payout': '1000000.000 SBD', 'percent_steem_dollars': 10000, 'allow_votes': True, 'allow_curation_rewards': True} [{'account': 'stmdev', 'weight': 1000}]","json_metadata":"{\"app\": \"beem/0.19.35\"}"}],["comment_options",{"author":"stmdev","permlink":"reply-case-1-1528013878","max_accepted_payout":"1000000.000 SBD","percent_steem_dollars":10000,"allow_votes":true,"allow_curation_rewards":true,"extensions":[[0,{"beneficiaries":[{"account":"stmdev","weight":1000}]}]]}]],"sigs":["STM6x286end3rLZj9ornAaxBaVzovxjHtXzBQppSFXCe67gCMu3xq"]}
[...]
beemapi.exceptions.UnhandledRPCError: missing required posting authority

The used posting key is correct, the same script creates a post with beneficiaries=None.

Possibly related: steemit/steem-python#9

Environment

# beempy --version
beempy, version 0.19.35
# python --version
Python 3.6.5

used power calculation may treat downvotes incorrectly

Expected behavior

The used power calculation via steem._calc_resulting_vote() should handle both up- and downvotes in the same way and both should consume the same amount of voting power.

Actual behavior

Upvotes are handled correctly, but downvotes may give incorrect/different results in some cases.

How to reproduce

  • Plotting the voting power over time using the example script provided with beem:
cd examples
python plot_vp_over_time.py crokkon

Output:
voting-power-crokkon

The voting power is partly shown with values above 100.

Another effect is that rshares_to_vote_pct() may give different absolute vote percentages for up- and downvotes for the same absolute amount of rshares:

>>> s.rshares_to_vote_pct(1e12, vests=412125123351512)
1250
>>> s.rshares_to_vote_pct(-1e12, vests=412125123351512)
-1200

The reason is that steem._calc_resulting_vote() treats the voting percentage as a signed value. A negative voting percentage (=flag/downvote) gives a negative used_power, while this number has to be positive in any case. This value is subtracted from the previous voting power for plotting, eventually giving VP values > 100%.

Environment

  • Python 3.6.5
  • beem master at rev. 8d0e364

Can't install beem due to Scrypt installation error (Windows): 'openssl/aes.h': No such file or directory

I was trying to do pip install beem in order to run your steemmonsters app, but beem depends on Scrypt, and Scrypt doesn't seem to be able to run on Windows. I tried to install the OpenSSL package that it requires, but I failed. I don't exactly know what else it needs. I installed this and added it to my path.

The following is the error that I got.

    crypto_aes.c
    scrypt-1.2.1/libcperciva/crypto/crypto_aes.c(6): fatal error C1083: No se puede abrir el archivo incluir: 'openssl/aes.h': No such file or directory
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.15.26726\\bin\\HostX86\\x64\\cl.exe' failed with exit status 2

    ----------------------------------------
Command "c:\python37\python.exe -u -c "import setuptools, tokenize;
__file__='C:\\Users\\pc\\AppData\\Local\\Temp\\pip-install-6w9w987_\\scrypt\\setup.py';
f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();
exec(compile(code, __file__, 'exec'))
"install --record C:\Users\pc\AppData\Local\Temp\pip-record-eu_c56pk\install-record.txt
--single-version-externally-managed --compile" failed with error code 1 in
C:\Users\pc\AppData\Local\Temp\pip-install-6w9w987_\scrypt\

Threaded `blockchain.stream()` fetches blocks without ops twice

Expected behavior

Blockchain.stream(threading=True) should use threads to fetch several blocks in parallel. Each block should be fetched once from the RPC node.

Actual behavior

Blockchain.stream(threading=True) requests blocks twice from the RPC node, if those block don't contain operations or only virtual operations. This limits the benefits from the parallel threads.

How to reproduce

from beem.blockchain import Blockchain
b = Blockchain()
for op in b.stream(start=2500000, stop=2500010, threading=True):
    continue

Plus printf-debugging:

index 5cb196c..2e19545 100644
--- a/beemapi/steemnoderpc.py
+++ b/beemapi/steemnoderpc.py
@@ -53,6 +53,7 @@ class SteemNodeRPC(GrapheneRPC):
             :raises ValueError: if the server does not respond in proper JSON format
             :raises RPCError: if the server returns an error
         """
+        print(payload)
         if self.url is None:
             raise except

Output:

{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_dynamic_global_properties', []], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': ['database_api', 'get_feed_history', []], 'jsonrpc': '2.0', 'id': 3}
{'method': 'call', 'params': ['database_api', 'get_feed_history', []], 'jsonrpc': '2.0', 'id': 4}
{'method': 'call', 'params': ['database_api', 'get_next_scheduled_hardfork', []], 'jsonrpc': '2.0', 'id': 5}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 6}
{'method': 'call', 'params': ['database_api', 'get_witness_schedule', []], 'jsonrpc': '2.0', 'id': 7}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 8}
{'method': 'call', 'params': ['database_api', 'get_reward_fund', ['post']], 'jsonrpc': '2.0', 'id': 9}
{'method': 'call', 'params': ['database_api', 'get_dynamic_global_properties', []], 'jsonrpc': '2.0', 'id': 10}
{'method': 'call', 'params': [None, 'get_block', [25031061]], 'jsonrpc': '2.0', 'id': 11}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': ['database_api', 'get_config', []], 'jsonrpc': '2.0', 'id': 1}
{'method': 'call', 'params': [None, 'get_block', [2500000]], 'jsonrpc': '2.0', 'id': 12}
{'method': 'call', 'params': [None, 'get_block', [2500001]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500002]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500003]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500004]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500005]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500006]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500007]], 'jsonrpc': '2.0', 'id': 2}
{'method': 'call', 'params': [None, 'get_block', [2500000]], 'jsonrpc': '2.0', 'id': 13}
{'method': 'call', 'params': [None, 'get_block', [2500003]], 'jsonrpc': '2.0', 'id': 14}
{'method': 'call', 'params': [None, 'get_block', [2500004]], 'jsonrpc': '2.0', 'id': 15}
{'method': 'call', 'params': [None, 'get_block', [2500005]], 'jsonrpc': '2.0', 'id': 16}
{'method': 'call', 'params': [None, 'get_block', [2500007]], 'jsonrpc': '2.0', 'id': 17}
{'method': 'call', 'params': [None, 'get_block', [2500008]], 'jsonrpc': '2.0', 'id': 18}
{'method': 'call', 'params': [None, 'get_block', [2500009]], 'jsonrpc': '2.0', 'id': 3}
{'method': 'call', 'params': [None, 'get_block', [2500010]], 'jsonrpc': '2.0', 'id': 3}
{'method': 'call', 'params': [None, 'get_block', [2500008]], 'jsonrpc': '2.0', 'id': 19}
{'method': 'call', 'params': [None, 'get_block', [2500009]], 'jsonrpc': '2.0', 'id': 20}
{'method': 'call', 'params': [None, 'get_block', [2500010]], 'jsonrpc': '2.0', 'id': 21}

8 of the 11 blocks are fetched twice: 2500000, 2500003, 2500004, 2500005, 2500007, 2500008, 2500009, 2500010. Those blocks contain no operations.


The reason seems to be here:

if len(b.operations) > 0:

with len(b.operations) == 0, the block is treated as if it was never fetched from the chain.

Environment

# beempy --version
beempy, version 0.19.53
# python --version
Python 3.6.6

Initial Update

The bot created this issue to inform you that pyup.io has been set up on this repo.
Once you have closed it, the bot will open pull requests for updates as soon as they are available.

How about merging your graphene improvements upstream?

Hey Holger,

as the original author of pysteem/piston-lib and python-graphene, I am looking to cooperate with you.
How about we put our efforts with respect to python-graphene (*graphene* modules) together and merge our improvements our improvements? I think we can both benefit from reduced code duplications and better code maintainability by moving low-level stuff to python-graphene.
What are your thoughts?

Discussions_by_comments fails on Vit

Using the following sample code

from beem.discussions import Query, Discussions_by_comments
q = Query(limit=10, start_author="jat", start_permlink="firstpost")
for h in Discussions_by_comments(q):
    print(h)

I get an error UnhandledRPCError: Comment is not in account's comments when used on Vit. I tried to give it a steem_instance=stm even though I am using a shared instance, it still does not work.

account.history_reverse() may fail with TypeError

Expected behavior

account.history_reverse(start=start, stop=stop, only_ops=['comment']) with start and stop being datetime objects should return the all comment operations of an account in the given time range.

Actual behavior

account.history_reverse(start=start, stop=stop, only_ops=['comment']) may fail with a TypeError exception:

Traceback (most recent call last):
  File "account_history_reverse.py", line 10, in <module>
    for op in a.history_reverse(start=start, stop=stop, only_ops=['comment']):
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 1335, in history_reverse
    while(op_est + est_diff + batch_size < first and block_date < start):
TypeError: '<' not supported between instances of 'str' and 'datetime.datetime'

block_date is a string in this case and is compared to start as a datetime object.

How to reproduce

#!/usr/bin/python
from beem.account import Account
from datetime import datetime, timedelta
from beem.utils import addTzInfo

a = Account("steemcleaners")
start = addTzInfo(datetime.utcnow()) - timedelta(days=1)
stop = addTzInfo(datetime.utcnow()) - timedelta(days=7)
for op in a.history_reverse(start=start, stop=stop, only_ops=['comment']):
    print(op)

Possible fix

Suspicion: block_date is converted to datetime objects in other places with formatTimeString(). This is not the case for the failing location, h["timestamp"] is used directly as a string.

Possible Fix:

diff --git a/beem/account.py b/beem/account.py
index b41cb58..b4ca42f 100644
--- a/beem/account.py
+++ b/beem/account.py
@@ -1331,13 +1331,13 @@ class Account(BlockchainObject):
             est_diff = 0
             if isinstance(start, (datetime, date, time)):
                 for h in self.get_account_history(op_est, 0):
-                    block_date = h["timestamp"]
+                    block_date = formatTimeString(h["timestamp"])
                 while(op_est + est_diff + batch_size < first and block_date < start):
                     est_diff += batch_size
                     if op_est + est_diff > first:
                         est_diff = first - op_est
                     for h in self.get_account_history(op_est + est_diff, 0):
-                        block_date = h["timestamp"]
+                        block_date = formatTimeString(h["timestamp"])
             else:
                 for h in self.get_account_history(op_est, 0):
                     block_num = h["block"]

Environment

# beempy --version
beempy, version 0.19.32
# python --version
Python 3.6.5

Cannot fetch account history of early created accounts, block number estimation gives negative values

Expected behavior

blockchain.history() and blockchain.history_reverse() are expected to accept block numbers, transaction numbers or dates for the start and stop parameters and only return account operations that happend within this range for any existing Steem account:

            :param int/datetime start: start number/date of transactions to
                return (*optional*)
            :param int/datetime stop: stop number/date of transactions to
                return (*optional*)
            :param bool use_block_num: if true, start and stop are block numbers,
                otherwise virtual operation count numbers.

Actual behavior

account.history() and account.history_reverse() with block numbers as start and stop parameters tries to fetch blocks with a negative block number if the account was created in the first days of Steem. The call fails with a beem.exceptions.BlockDoesNotExistsException. Using the corresponding time stamps for start and stop as datetime instances in the history()/history_reverse() calls give the correct results.

How to reproduce

Picking an early created account (e.g. berniesanders: created on '2016-03-26 08:26:21+00:00') and a random transaction (e.g. in Block 22487722):

#!/usr/bin/python
from beem.account import Account

a = Account("berniesanders")
start = 22487721
stop = 22487723

for op in a.history(start=start, stop=stop, use_block_num=True):
    print(op)

or

#!/usr/bin/python
from beem.account import Account

a = Account("berniesanders")
start = 22487723
stop = 22487721

for op in a.history_reverse(start=start, stop=stop, use_block_num=True):
    print(op)

Result:

Traceback (most recent call last):
  File "bug_neg_blocknum.py", line 8, in <module>
    for op in a.history(start=start, stop=stop, use_block_num=True):
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 1170, in history
    op_est = self.estimate_virtual_op_num(start, stop_diff=1)
  File "/usr/local/lib/python3.6/site-packages/beem/account.py", line 888, in estimate_virtual_op_num
    created_blocknum = b.get_estimated_block_num(created, accurate=True)
  File "/usr/local/lib/python3.6/site-packages/beem/blockchain.py", line 163, in get_estimated_block_num
    block = Block(block_number, steem_instance=self.steem)
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 68, in __init__
    steem_instance=steem_instance
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 114, in __init__
    self.refresh()
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 96, in refresh
    raise BlockDoesNotExistsException(str(self.identifier))
beem.exceptions.BlockDoesNotExistsException: -17607

The cause of the error is that blockchain.get_estimated_block_num() returns a negative block number. This function is used to look up the block number of the account creation date.

>>> b.block_time(1)
datetime.datetime(2016, 3, 24, 16, 5, tzinfo=<UTC>)
>>> b.get_estimated_block_num(addTzInfo(datetime(2016, 3, 26, 8, 26, 21)))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/beem/blockchain.py", line 163, in get_estimated_block_num
    block = Block(block_number, steem_instance=self.steem)
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 68, in __init__
    steem_instance=steem_instance
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 114, in __init__
    self.refresh()
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 96, in refresh
    raise BlockDoesNotExistsException(str(self.identifier))
beem.exceptions.BlockDoesNotExistsException: -17607

The smallest timestamp that returns a positive block number is 2016-03-26T23:06:42, any earlier timestamp raises an exception:

>>> b.get_estimated_block_num(addTzInfo(datetime(2016, 3, 26, 23, 6, 42)))
65330
>>> b.get_estimated_block_num(addTzInfo(datetime(2016, 3, 26, 23, 6, 41)))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/beem/blockchain.py", line 163, in get_estimated_block_num
    block = Block(block_number, steem_instance=self.steem)
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 68, in __init__
    steem_instance=steem_instance
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 114, in __init__
    self.refresh()
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 96, in refresh
    raise BlockDoesNotExistsException(str(self.identifier))
beem.exceptions.BlockDoesNotExistsException: 0

Environment

# beempy --version
beempy, version 0.19.33
# python --version
Python 3.6.5

Account.history is missing operations due to wrongly estimated op numbers

Expected behavior

Account.history(start, stop) with start and stop being datetime instances should return all blockchain operations from an account for the given start/stop timestamps.

Actual behavior

Account.history(start, stop) may be missing operations from the given time range

How to reproduce

I know I've created a post on 2018-02-05 14:06:54, so the account history should contain at least one comment operation on that day:

from beem.account import Account
from datetime import datetime, timedelta
from beem.utils import parse_time, addTzInfo

a = Account("stmdev")
start = addTzInfo(datetime(2018, 2, 5))
stop = addTzInfo(datetime(2018, 2, 6))
for op in a.history(start=start, stop=stop, only_ops=['comment']):
    print(op['timestamp'], op['author'], op['permlink'])

The result is empty even though there were blockchain operations from this account in the given time range.

Deeper analysis

The virtual op number estimation gives wrong results in this case. I know that this comment operation has index=2:

for op in a.get_account_history(2, 0):
    print(op['timestamp'], op['author'], op['permlink'])
2018-02-05T14:06:54 stmdev test

So a.estimate_virtual_op_num(datetime(2018, 2, 5, 14, 6, 54)) should return 2, but it actually returns 282:

from beem.account import Account
from datetime import datetime, timedelta
from beem.utils import parse_time, addTzInfo

a = Account("stmdev")
print(a.estimate_virtual_op_num(datetime(2018, 2, 5, 14, 6, 54)))

estimate_virtual_op_num has a max_count parameter that defines how many attempts beem should make before giving up. The default is 100. The limit can be disabled via max_count=-1, so beem should do as many attempts as necessary to find the according virtual op number:

a.estimate_virtual_op_num(datetime(2018, 2, 5, 14, 6, 54), max_count=-1)

This runs in an endless loop and never returns. The virtual op number estimation does not converge. The result 282 from above is just by coincidence the result after the 100th iteration for the default max_count until beem gives up. Printing out the current op num from the while loop shows that this number is oscillating and not converging towards the target value.

This behavior is the same across beem-0.19.37 up to 0.19.41, so it's not introduced from the latest changes to this function.

Environment

beempy, version 0.19.41
# python --version
Python 3.6.5

Discussions keyword errors

Expected behavior

Discussions.get_discussions(type, query) can be used to retrieve any kind of discussion types
with a given query

Actual behavior

Discussions.get_discussions(type, query) fails with a TypeError.

How to reproduce

Using the provided example

from beem.discussions import Query, Discussions
query = Query(limit=51, tag="steemit")
discussions = Discussions()
count = 0
for d in discussions.get_discussions("tags", query, limit=200):
    print(("%d. " % (count + 1)) + str(d))
    count += 1

Result:

Traceback (most recent call last):
  File "testcode.py", line 5, in <module>
    for d in discussions.get_discussions("tags", query, limit=200):
  File "/usr/local/lib/python3.6/site-packages/beem/discussions.py", line 121, in get_discussions
    dd = Trending_tags(discussion_query, self.steem, lazy=self.lazy)
TypeError: __init__() got multiple values for argument 'lazy'

The reason is that self.steem is a keyword argument but provided as a non-keyword argument at the position of lazy.

Environment

  • beem at rev. 083d199
  • python 3.6.5

Blockchain.get_transaction / get_transaction_hex issues on appbase

Expected behavior

Blockchain.get_transaction should return the transaction for a given transaction id
Blockchain.get_transaction_hex should return a hexdump of the serialized binary form of a transaction

Actual behavior

Blockchain.get_transaction and Blockchain.get_transaction_hex fail on appbase nodes with Could not find method get_transaction

How to reproduce

from beem import Steem
from beem.blockchain import Blockchain
trx_id = '6fde0190a97835ea6d9e651293e90c89911f933c'
s = Steem(node=['https://api.steemit.com'])
b = Blockchain(steem_instance=s)
print(b.get_transaction(trx_id))
from beem import Steem
from beem.blockchain import Blockchain
trx = {"ref_block_num":1097,"ref_block_prefix":2181793527,"expiration":"2016-03-24T18:00:21","operations":[{"type":"pow_operation","value":{"worker_account":"cloop3","block_id":"00000449f7860b82b4fbe2f317c670e9f01d6d9a","nonce":3899,"work":{"worker":"STM7P5TDnA87Pj9T4mf6YHrhzjC1KbPZpNxLWCcVcHxNYXakpoT4F","input":"ae8e7c677119d22385f8c48026fee7aad7bba693bf788d7f27047f40b47738c0","signature":"1f38fe9a3f9989f84bd94aa5bbc88beaf09b67f825aa4450cf5105d111149ba6db560b582c7dbb026c7fc9c2eb5051815a72b17f6896ed59d3851d9a0f9883ca7a","work":"000e7b209d58f2e64b36e9bf12b999c6c7af168cc3fc41eb7f8a4bf796c174c3"},"props":{"account_creation_fee":{"amount":"100000","precision":3,"nai":"@@000000021"},"maximum_block_size":131072,"sbd_interest_rate":1000}}}],"extensions":[],"signatures":[]}
s = Steem(node=['https://api.steemit.com'])
b = Blockchain(steem_instance=s)
print(b.get_transaction_hex(trx))

The problem with get_transaction_hex() is a typo, the function internally calls get_transaction() instead of get_transaction_hex().

get_transaction() tries to use database_api. However, this method is not part of database_api. According to the documentation, it's only part of condenser_api. Changing the API to "condenser" results in a account_history_api_plugin not enabled Exception. This exception is also thrown with the example in the official documentation. I have no idea how to fix get_transaction() for appbase nodes.

Environment

# python --version
Python 3.6.6
# beempy --version
beempy, version 0.19.50

blockchain.get_all_accounts() returns duplicate entries

Expected behavior

blockchain.get_all_accounts(limit=5000) should return the first 5000 Steem accounts

Actual behavior

blockchain.get_all_accounts(limit=5000) returns 5000 account names, however 4 of them are contained twice in the list, leaving 4996 unique account names

How to reproduce

>>> from beem import blockchain
>>> b = Blockchain()
>>> len(list(b.get_all_accounts(limit=5000)))
5000
>>> len(set(b.get_all_accounts(limit=5000)))
4996

The reason is that the accounts are fetched in batches (default: 1000 accounts per RPC call) where the last result of the previous batch is also the first result of the next batch.

`get_discussions()` does not finish if discussions are empty

Expected behaviour

Using the testing code (see below), the program finishes and returns no results.

Actual behaviour

Using the testing code (see below), the program does not finish.

Steps to reproduce

  1. Testing code (use select_authors such that the author is not included in the selected author's blog)
q = Query(tag='utopian-io', select_authors=["actifit"])
dd = Discussions(steem_instance=Steem(node="https://api.steemit.com")).get_discussions(discussion_type="blog", discussion_query=q, limit=10)
for d in dd:
        print(d["url"])
  • version: Beem 0.20.6

Additional note

If dd is empty in https://github.com/holgern/beem/blob/master/beem/discussions.py#L154 , then the while cycle will never end.

upvote weight not accurate

Running something like this gives me a weight of -100%
print(comment.upvote(weight=99.9))
If I changed the weight to 100 or above it votes 100%.

And if I set the default with beempy it has no impact. It defaults to 100%.
default_vote_weight | 99.9

I'm running beem 0.19.23

unable to use Blockchain.stream()/blocks() with only_ops=True and threads

Expected result

Blockchain.stream/blocks(start, stop, only_ops=True) should return all ops in the given block range. Additionally using threading=True should eventually speed things up.

Actual result

Blockchain.stream/blocks(start, stop, only_ops=True, threading=True) prints errors

int() argument must be a string, a bytes-like object or a number, not 'NoneType'

and never completes.

How to reproduce

from beem.blockchain import Blockchain
b = Blockchain()
for op in b.blocks(start=25000000, stop=25000010, only_ops=True,
                   threading=True):
    continue

Output:

int() argument must be a string, a bytes-like object or a number, not 'NoneType'
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
...

Environment

# beempy --version
beempy, version 0.20.12
# python --version
Python 3.6.6

BEEM APP FAIL TO UPLOAD AVATAR

Project Information

  • Repository
    https://github.com/holgern/beem

  • Project Name - BEEM APP

  • Expected Behavior
    SUPPORT OF USER AVATAR (User should be able to Upload AVATAR when Updating Status).

  • Actual Behavior
    NOT SUPPORTING USERS AVATAR (Application fail to Upload Avatar, thereby denying user of providing an Image for other users to see).

  • How To Reproduce;

  1. Download and Install Beem-Chat App from Google play store

  2. Open the application to create an account or use an existing account.

  3. Click the three dots on the right upper part and choose Change status from the listed menu.

  4. Click on the avatar icon to upload an image, then it fails to upload the avatar.

  • Device - Infinix Hot X521
  • Operating System - Android 6.0
    Application Version - v0.1.8

Recording of the Bug
https://www.youtube.com/watch?v=P4r4AZaJvfk

Wrong first Tag on Post

Whenever i use the Postmethod of beem it sets the first tag wrong. The post always hast the first letter of the first tag as the first tag. Then it goes an as expected.

For example if i use tags="steem beem foo bar" the tags will be: s steem beem foo bar
if i use tags = "foo bar" it will be: f foo bar and so on
Haven't found any info about that issue so far, is the problem on my side?
I had the issue with 20.3 and also after i updated to 20.5

Edit: Also my posts dont show up in any category on steem.

Invalid cast from array_type to string in GetWitnesses

Thanks for the GetWitnesses() function.
It works great on Steem, but on Vit I noticed it throws the following error.

Invalid cast from array_type to string
    {"type":"array_type"}
    th_a  variant.cpp:478 as_string

I tried just using one witness (in a list) and a list of them, both fail with a similar error.

Wrong input parameters for `Discussions_by_author_before_date` in Docstring and `get_discussions`

Expected behaviour

As per the steem documentation of the API method (see https://developers.steem.io/apidefinitions/#tags_api.get_discussions_by_author_before_date, the input parameters should be:

  • author
  • start_permlink
  • before_date
  • limit

The correct parameters should be described in the docstring of the method and passed in the get_discussions method of Discussions class.

Actual behaviour

Although the method definition has the correct parameters, the docstring describes the parameters as instance of Query class. https://github.com/holgern/beem/blob/master/beem/discussions.py#L205

Furthermore, incorrect query parameter is passed in get_discussions method. https://github.com/holgern/beem/blob/master/beem/discussions.py#L113

Additional notes

The Discussions_by_author_before_date method can't get parameters from the instance of Query because the class does not have all needed parameters such as before_date and author.

steemconnect: TransactionBuilder example gives empty output string

Expected Behavior

SteemConnect TransactionBuilder example from

from beem import Steem

should give the output as shown in the example:

'https://v2.steemconnect.com/sign/transfer?from=test&to=test1&amount=1.000+STEEM&memo=test'

Actual behavior

Apart from minor syntax errors in the example, the output string is empty:

Output:

''

How to reproduce

Applying syntax error fixes to the example code:

--- a/beem/steemconnect.py
+++ b/beem/steemconnect.py
@@ -60,13 +60,14 @@ class SteemConnect(object):
             from beem.steemconnect import SteemConnect
             from pprint import pprint
             stm = Steem()
+            sc2 = SteemConnect(steem_instance=stm)
             tx = TransactionBuilder(steem_instance=stm)
             op = operations.Transfer(**{"from": 'test',
                                         "to": 'test1',
                                         "amount": '1.000 STEEM',
                                         "memo": 'test'})
             tx.appendOps(op)
-            pprint(sc2.url_from_tx(tx)
+            pprint(sc2.url_from_tx(tx))
 
         .. testcode::
 

This gives the following sample script:

from beem import Steem
from beem.transactionbuilder import TransactionBuilder
from beembase import operations
from beem.steemconnect import SteemConnect
from pprint import pprint
stm = Steem()
sc2 = SteemConnect(steem_instance=stm)
tx = TransactionBuilder(steem_instance=stm)
op = operations.Transfer(**{"from": 'test',
                            "to": 'test1',
                            "amount": '1.000 STEEM',
                            "memo": 'test'})
tx.appendOps(op)
pprint(sc2.url_from_tx(tx))

with output:

''

Adding a print(tx) before the pprint makes it work?!

from beem import Steem
from beem.transactionbuilder import TransactionBuilder
from beembase import operations
from beem.steemconnect import SteemConnect
from pprint import pprint
stm = Steem()
sc2 = SteemConnect(steem_instance=stm)
tx = TransactionBuilder(steem_instance=stm)
op = operations.Transfer(**{"from": 'test',
                            "to": 'test1',
                            "amount": '1.000 STEEM',
                            "memo": 'test'})
tx.appendOps(op)
print(tx)
pprint(sc2.url_from_tx(tx))

Output:

{'expiration': '2018-07-08T08:49:12', 'ref_block_num': 5087, 'ref_block_prefix': 2415621679, 'operations': [['transfer', {'from': 'test', 'to': 'test1', 'amount': '1.000 STEEM', 'memo': 'test'}]], 'extensions': [], 'signatures': []}
'https://v2.steemconnect.com/sign/transfer?from=test&to=test1&amount=1.000+STEEM&memo=test'

Environment

# beempy --version
beempy, version 0.19.46
# python --version
Python 3.6.5

Race condition in blockchain.blocks() when using threads

Expected behavior

blockchain.blocks(start=start, stop=stop, threading=True) should return all requested blocks.

Actual behavior

blockchain.blocks(start=start, stop=stop, threading=True) may raise a RuntimeError due to a race condition when a dictionary is changed while being iterated on. The streaming of the blocks stops at non-deterministic block numbers.

Traceback (most recent call last):
  File "block_race_condition.py", line 9, in <module>
    for block in b.blocks(start=10000, stop=20000, threading=True, thread_num=8):
  File "/usr/local/lib/python3.6/site-packages/beem/blockchain.py", line 241, in blocks
    results = [r.result() for r in as_completed(futures)]
  File "/usr/local/lib/python3.6/site-packages/beem/blockchain.py", line 241, in <listcomp>
    results = [r.result() for r in as_completed(futures)]
  File "/usr/local/lib/python3.6/concurrent/futures/_base.py", line 425, in result
    return self.__get_result()
  File "/usr/local/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
    raise self._exception
  File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 68, in __init__
    steem_instance=steem_instance
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 138, in __init__
    self.cache()
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 163, in cache
    BlockchainObject._cache[self.get(self.id_item)] = self
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 33, in __setitem__
    self.clear_expired_items()
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 48, in clear_expired_items
    for key in self.keys():
RuntimeError: dictionary changed size during iteration

The corresponding code part is in

for key in self.keys():

self.keys() changes while being iterated on.

How to reproduce

from beem.blockchain import Blockchain
from beem import Steem
import sys

b = Blockchain()

for block in b.blocks(start=10000, stop=20000, threading=True, thread_num=8):
    sys.stdout.write("%s (%s)\r" % (block['id'], block['timestamp']))

This code sometimes results in the RuntimeError above. The block number at which the error occurs changes and it may need dozens of runs until it actually fails. However, the problem can be articifially amplified by adding a time.sleep(1) into the corresponding for key in self.keys(): loop:

diff --git a/beem/blockchainobject.py b/beem/blockchainobject.py
index 03d22de..09d56ca 100644
--- a/beem/blockchainobject.py
+++ b/beem/blockchainobject.py
@@ -9,6 +9,7 @@ from beemgraphenebase.py23 import bytes_types, integer_types, string_types, text
 from beem.instance import shared_steem_instance
 from datetime import datetime, timedelta
 import json
+import time


 @python_2_unicode_compatible
@@ -46,6 +47,7 @@ class ObjectCache(dict):
         keys = []
         for key in self.keys():
             keys.append(key)
+            time.sleep(1)
         for key in keys:
             value = dict.__getitem__(self, key)
             if datetime.utcnow() >= value["expires"]:

With this change, the library spends significant amounts of time in the iteration loop on self.keys(). Technically it does not make a difference apart from being terribly slow now. With this in place, the above exception can be triggered with the given code sample within seconds.

The exception is not raised when multi-threading is disabled via threading=False. To my understanding, multiple threads are accessing the same ObjectCache() instance. Disabling the cache via the use_cache=False flag in the BlockchainObject constructor defaults for testing purposes did not work:

Traceback (most recent call last):
  File "block_race_condition.py", line 10, in <module>
    sys.stdout.write("%s (%s)\r" % (block['id'], block['timestamp']))
  File "/usr/local/lib/python3.6/site-packages/beem/blockchainobject.py", line 173, in __getitem__
    self.refresh()
  File "/usr/local/lib/python3.6/site-packages/beem/block.py", line 76, in refresh
    self.identifier = int(self.identifier)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

Using a copy of self.keys() via for key in self.keys()[:]: will only shift the problem, because two instances will still try to access/delete the same cache entries independently.

Environment

# beempy --version
beempy, version 0.19.32
# python --version
Python 3.6.5

Account.get_tags_used_by_author fails on appbase

Expected behavior

Account.get_tags_used_by_author should return a list of tags or an empty list

Actual behavior

Account.get_tags_used_by_author fails with an RPC error on appbase nodes:

>>> a.get_tags_used_by_author()
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/beemapi/steemnoderpc.py", line 64, in rpcexec
    reply = super(SteemNodeRPC, self).rpcexec(payload)
  File "/usr/local/lib/python3.6/site-packages/beemapi/graphenerpc.py", line 409, in rpcexec
    raise RPCError(ret['error']['message'])
beemapi.exceptions.RPCError: Assert Exception:acnt != nullptr: Author not found

How to reproduce

from beem.account import Account
from beem import Steem
s = Steem(node=['https://api.steemit.com'])
a = Account('crokkon', steem_instance=s)
print(a.get_tags_used_by_author())

get_tags_used_by_author requires an argument author, but currently gets the argument account:

return self.steem.rpc.get_tags_used_by_author({'account': account}, api="tags")['tags']

Environment

# beempy --version
beempy, version 0.19.50
# python --version
Python 3.6.6

Unable to get replies to an account via discussions.Replies_by_last_update

Expected behavior

discussions.Replies_by_last_update() should return a list of the last replies to posts/comments from a given author

Actual behavior

discussions.Replies_by_last_update() cannot be used to get a list of the last replies to posts/comments from a given author. The list of Comment instances returned are not replies to the given author.

How to reproduce

from beem.discussions import Replies_by_last_update, Query
query = {'limit': 10, 'start_parent_author': 'stmdev',
         'start_permlink': None, 'start_author': None}
replies = Replies_by_last_update(query)
for reply in replies:
    print(reply)

Output:

<Comment @bonanza-kreep/agrotechfarm-presents-a-cutting-edge-smart-farming-solution>
<Comment @pizzaboy77/song-challenge-tag-1-30>
<Comment @w6lk3r/k-2018-6-2-11-21-57>
<Comment @ram2144/3wfp2n-punch>
<Comment @statsexpert/daily-top-posts-in-category-nature-on-2018-07-17>
<Comment @carlsmart303/9y5xb-travel>
<Comment @sahelmakrani/saud-binmazi>
<Comment @revia/kisah-seorang-petani-6851709cbae9b>
<Comment @fingersik/decentralizationtotherescuedecenternetthevisionpt1of6-qbd77zigc6>
<Comment @gaiablock/an-appetizer-of-cpos-consensus-algorithm-by-gaiaworld-gamechain>

The reason is that the start_parent_author parameter is not propagated to the RPC call:
https://developers.steem.io/apidefinitions/#tags_api.get_replies_by_last_update

Environment

  • beem at rev. e522373
  • python 3.6.5

ImportError: cannot import name 'Account' from 'beem'

I have been using Beem for a little while. I installed Steemmonsters and use it regularly, and I also have a tool to crosspost from Steem to Whaleshares using Beem, but today I tried to use the Account module to do some tests and it just refused with an error:

Traceback (most recent call last):
  File ".\beemtest.py", line 1, in <module>
    from beem import Account
ImportError: cannot import name 'Account' from 'beem' (C:\ProgramData\Miniconda3\lib\site-packages\beem\__init__.py)

Did I do something wrong? My code is simply

from beem import Account
account = Account("cryptosharon")
print(account.balances)

I assume it was an installation error at some point. Maybe Miniconda3 cannot handle certain modules, or maybe it was a corrupted or incomplete installation (or maybe it was an update on Beem that removed Account or changed its name?)

Querying posts on blockchain with permlink and author?

I have an interesting problem which should be solvable with Beem, but which I can't quite seem to figure out how to put into the context of the module UI.

Here's my problem:

I have a list of permlinks and authors, and I want to walk this list and accumulate certain post attributes which they have.

I've been using SteamData to acquire slices of voting data and account names, and that works just fine โ€“ but once I have a list of specifics to investigate further, it's very difficult to get a MongoDB query that runs in a reasonable time which is efficient for pulling back a long list of specific items.

This seems like something that is tailor-made for Beem.

Unfortunately, I can't figure out from the documentation as it stands how one would go about simply formulating that function or method call. It's fairly easy to watch the blockchain for specific changes in a streaming way, but it is nontrivial to query the blockchain for specific information.

Am I just missing something obvious, or is that functionality not implemented yet, or am I trying to use the wrong tool for the wrong job?

Proposal For Copywriting

Hello i went through your project and i want to say it is very nice. However i noticed you are missing out some important details like gaq, about us and privacy policy which users will be looking forward too. If you dont mind i can write that for you

contact me
email [email protected]

steemit.com/@ewuoso

Conda installed 'beem' on Debian but only "beempy" is in conda's /bin - "ImportError: No module named 'beem'"

I'm setting up beem in a new server and wanted to install it, so I tried with pip, but the same error as on Windows appears (scrypt is not very good at being installed from pip). I installed conda then did conda install -c conda-forge beem, and it went alright. But now if I try to import it into my script, I get the error "ImportError: No module named 'beem'" even though it's in the /bin as "beempy".

beem encrypted memos are not decryptable

If providing a memo key through steem instance and transferring money with a memo beginning with '#' the transfer is sent and every seems fine. But decrypting the message is not possible. Steemit.com would show 'invalid memo' and beem throws an exeption like this:

 print(m.decrypt(memo=memo))
  File "E:\ProgramData\Anaconda3\lib\site-packages\beem\memo.py", line 260, in decrypt
    message
  File "E:\ProgramData\Anaconda3\lib\site-packages\beembase\memo.py", line 228, in decode_memo
    message = aes.decrypt(unhexlify(py23_bytes(message, 'ascii')))
  File "E:\ProgramData\Anaconda3\lib\site-packages\Cryptodome\Cipher\_mode_cbc.py", line 210, in decrypt
    raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size)
ValueError: Data must be padded to 16 byte boundary in CBC mode

SteemConnect expects double quotes in JSON

Expected behavior

The URL created from a transaction via steemconnect.url_from_tx() should be able to create the according transaction via SteemConnect.

Actual behavior

Parts of the JSON values are wrapped in single quotes (e.g. 'value') instead of double quotes (e.g. "value"), leading to JSON parsing errors with the created steemconnect link

How to reproduce

from beem import Steem
from beem.steemconnect import SteemConnect
s = Steem(nobroadcast=True, unsigned=True)
sc = SteemConnect(steem_instance=s)
tx = s.custom_json("123", {'field1': 'data1', 'field2': 'data2'}, required_posting_auths=["stmdev"])
print(sc.url_from_tx(tx))

Result:

https://v2.steemconnect.com/sign/custom_json?required_auths=%5B%5D&required_posting_auths=%5B%27stmdev%27%5D&id=123&json=%7B%22field1%22%3A+%22data1%22%2C+%22field2%22%3A+%22data2%22%7D

Note the %27=' around stmdev, but %22=" around the actual payload.

screenshot_2018-07-18_16-53-14

By modifying the URL to replace all %27 with %22 the URL works:

https://steemconnect.com/sign/custom_json?required_auths=%5B%5D&required_posting_auths=%5B%22stmdev%22%5D&id=123&json=%7B%22field1%22%3A+%22data1%22%2C+%22field2%22%3A+%22data2%22%7D

screenshot_2018-07-18_16-54-41

gregory-f from steemconnect confirmed that the "pure JSON" / SteemConnect expects double quotes.

Environment

  • beem 0.19.49
  • python 3.6.5

Signed_Transaction cannot handle appbase transactions with beneficiaries

Expected behavior

The Signed_Transaction class should accept existing blockchain transactions, for example to determine the original signer.

Actual behavior

Signed_Transaction gets along with blockchain transaction from non-appbase nodes, but fails with appbase transactions if those contain a comment_options operation with beneficiaries. The constructor fails with Exception: Unknown CommentOptionExtension

How to reproduce

from beem import Steem
from beem.nodelist import NodeList
from beem.blockchain import Blockchain
from beembase.signedtransactions import Signed_Transaction

s = Steem(node=NodeList().get_nodes(appbase=True, normal=False))
b = Blockchain(steem_instance=s)
for block in b.blocks(start=25304468, stop=25304468):
    for trx in block.transactions:
        try:
            st = Signed_Transaction(trx.copy())
        except Exception:
            print(trx)
            raise

Output:

{'transaction_id': '4c1d57de6cfeb0966c2e08da85822483c4af37d7', 'ref_block_num': 7551, 'ref_block_prefix': 107790536, 'expiration': '2018-08-23T00:11:06', 'operations': [{'type': 'comment_operation', 'value': {'parent_author': '', 'parent_permlink': 'ifttt', 'author': 'buffalo-goku', 'permlink': 'toincreaseamericasproductivitybanthishttpstcoivgi8aul1n-efyvj7avgx', 'title': "To Increase America's Productivity Ban This... https://t.co/ivgi8aUL1N", 'body': '<blockquote class="twitter-tweet"><p lang="en" dir="ltr">To Increase America&rsquo;s Productivity Ban This&hellip; <a href="https://t.co/ivgi8aUL1N" target="_blank">https://t.co/ivgi8aUL1N</a></p>โ€” Buffalo_Goku๐Ÿ–• (@F_C_J_R) <a href="https://twitter.com/F_C_J_R/status/914347700178518016?ref_src=twsrc%5Etfw" target="_blank">October 1, 2017</a>\n</blockquote>\n<br />\nfrom Twitter <a href="https://twitter.com/F_C_J_R" target="_blank">https://twitter.com/F_C_J_R</a><br /><br />\nOctober 01, 2017 at 12:34AM<br />\nvia <a href="http://ift.tt/18ufGjY" target="_blank">IFTTT</a><br /><center><hr/><em>Posted from my blog with <a href=\'https://wordpress.org/plugins/steempress/\'>SteemPress</a> : https://nopoliticalcorrectnesshere.com/wp/2017/10/01/to-increase-americas-productivity-ban-this-13/</em><hr/></center>', 'json_metadata': '{"community":"steempress","app":"steempress/1.4","image":[""],"tags":["ifttt","news","nwo","politics","twitter"],"original_link":"https://nopoliticalcorrectnesshere.com/wp/2017/10/01/to-increase-americas-productivity-ban-this-13/"}'}}, {'type': 'comment_options_operation', 'value': {'author': 'buffalo-goku', 'permlink': 'toincreaseamericasproductivitybanthishttpstcoivgi8aul1n-efyvj7avgx', 'max_accepted_payout': {'amount': '1000000000', 'precision': 3, 'nai': '@@000000013'}, 'percent_steem_dollars': 10000, 'allow_votes': True, 'allow_curation_rewards': True, 'extensions': [{'type': 'comment_payout_beneficiaries', 'value': {'beneficiaries': [{'account': 'steempress', 'weight': 1500}]}}]}}, {'type': 'vote_operation', 'value': {'voter': 'buffalo-goku', 'author': 'buffalo-goku', 'permlink': 'toincreaseamericasproductivitybanthishttpstcoivgi8aul1n-efyvj7avgx', 'weight': 10000}}], 'extensions': [], 'signatures': ['203a68c042cddd1b93dd4792893b66f31880c8d410643b46ce43fa4d674012a32b4e670185dcb9c1c5db90ceddb74ecd0046d9bfdf5c0ebde962a6e267f35c6a04'], 'block_num': 25304468, 'transaction_num': 3}
Traceback (most recent call last):
  File "bug_benef.py", line 12, in <module>
    st = Signed_Transaction(trx.copy())
  File "/usr/local/lib/python3.6/site-packages/beembase/signedtransactions.py", line 30, in __init__
    super(Signed_Transaction, self).__init__(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/beemgraphenebase/signedtransactions.py", line 66, in __init__
    kwargs['operations'] = Array([opklass(a) for a in kwargs["operations"]])
  File "/usr/local/lib/python3.6/site-packages/beemgraphenebase/signedtransactions.py", line 66, in <listcomp>
    kwargs['operations'] = Array([opklass(a) for a in kwargs["operations"]])
  File "/usr/local/lib/python3.6/site-packages/beembase/objects.py", line 79, in __init__
    super(Operation, self).__init__(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/beemgraphenebase/objects.py", line 54, in __init__
    self.op = klass(op["value"])
  File "/usr/local/lib/python3.6/site-packages/beembase/operations.py", line 364, in __init__
    extensions = Array([CommentOptionExtensions(o) for o in kwargs["extensions"]])
  File "/usr/local/lib/python3.6/site-packages/beembase/operations.py", line 364, in <listcomp>
    extensions = Array([CommentOptionExtensions(o) for o in kwargs["extensions"]])
  File "/usr/local/lib/python3.6/site-packages/beembase/objects.py", line 268, in __init__
    raise Exception("Unknown CommentOptionExtension")
Exception: Unknown CommentOptionExtension

Changing the nodelist to non-appbase (appbase=False, normal=True) gives no output as expected. Changing the block number to 25304469, containing a comment_options operation without beneficiaries, works for both appbase and non-appbase.

It seems Signed_Transaction doesn't get along with the additional appbase type/value pair in extensions:

'extensions': [{
  'type': 'comment_payout_beneficiaries', 
  'value': {
    'beneficiaries': [
      {'account': 'steempress', 'weight': 1500}
    ]
}]

Environment

# python --version
Python 3.6.6
# beempy --version
beempy, version 0.19.54

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.