Git Product home page Git Product logo

bitcart-sdk's Introduction

Bitcart SDK

CircleCI Codecov PyPI version Read the Docs

This is a client library(wrapper) around Bitcart daemon. It is used to simplify common commands. Coins support(⚡ means lightning is supported):

  • Bitcoin (⚡)
  • Bitcoin Cash
  • Monero
  • Ethereum
  • Binance coin (BNB)
  • SmartBCH
  • Polygon (MATIC)
  • Tron (TRX)
  • Ergon
  • Litecoin (⚡)
  • Globalboost (⚡)
  • Groestlcoin (⚡)

Main focus is Bitcoin.

This library supports both asynchronous and synchronous usages.

You can call it's methods synchronously, like so:

print(btc.help())

Or you can await it's methods when using from async functions:

async def main():
    print(await btc.help())

Async callback functions for @btc.on are supported.

For more information Read the Docs

Release versioning

We follow a custom variant of semver:

major.minor.feature.bugfix

Where major is changed not frequently, and means significant changes to the SDK

minor means breaking changes

feature means adding new features without breaking existing APIs

bugfix means fixing bugs without breaking existing APIs

Contributing

See CONTRIBUTING.md.

Copyright and License

Copyright (C) 2019 MrNaif2018

Licensed under the MIT license

bitcart-sdk's People

Stargazers

 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

bitcart-sdk's Issues

Shadowing of bitcart.coin

The variable used in the for loop in bitcart/__init__.py shadows bitcart/coin.py.

>>> import bitcart.coin
>>> bitcart.coin # this isn't the module, this is the last coin in COINS.values()
<class 'bitcart.coins.grs.GRS'>
>>>

[BUG] `start_websocket` does not cleanup it's resources on ctrl+c

If running start_websocket in a python shell, stopping it and starting again (or it might be some script calling start_websocket multiple times somehow):

coin.start_websocket()
...
KeyboardInterrupt^C
coin.start_websocket()

The websocket connection is not closed, and when running start_websocket again, multiple connections from the same client is opened to the daemon, and if some event is received, event handlers are called multiple times. Theoretically this should not affect most use cases, but fixing this should improve overall UX in python shell

Helper links:
https://github.com/bitcartcc/bitcart-sdk/blob/4420bf3124ca3ed28a9312a09df51e76ce0021fb/bitcart/event_delivery.py#L47

Looks like __aexit__ of client session is not called, and connection is not closed
Websockets are created in a similar way in APIManager:
https://github.com/bitcartcc/bitcart-sdk/blob/4420bf3124ca3ed28a9312a09df51e76ce0021fb/bitcart/manager.py#L78

[FEATURE] Improve error handling in start_websocket

>>> a.start_websocket()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/sync.py", line 51, in async_to_sync_wrap
    return run_sync_ctx(coroutine, loop)
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/sync.py", line 19, in run_sync_ctx
    return loop.run_until_complete(coroutine)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/event_delivery.py", line 81, in start_websocket
    await self._websocket_base_loop(
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/event_delivery.py", line 60, in _websocket_base_loop
    await func(reconnect_callback=reconnect_callback)
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/event_delivery.py", line 48, in _start_websocket_inner
    await self._start_websocket_processing(ws, reconnect_callback=reconnect_callback)
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/event_delivery.py", line 40, in _start_websocket_processing
    await self.process_updates(data.get("updates", []), data.get("currency", "BTC"), data.get("wallet"))
  File "/home/alex/envs/bitcart/lib/python3.8/site-packages/bitcart/coins/btc.py", line 185, in process_updates
    raise InvalidEventError(f"Invalid event from server: {event}")
bitcart.errors.InvalidEventError: Invalid event from server: verified_tx

If server returns invalid event, websocket processing is stopped. Theoretically users shouldn't connect to untrusted daemons anyway, and it would show that they need to upgrade their SDK to support latest events. But maybe it shouldn't stop processing but just log and ignore that event. Also, it should be checked how other exceptions are handled, especially in event handlers. Currently if event handler raises, processing would be stopped, hence many with log_errors(): in our merchants api. Instead SDK should log errors by itself, but in a way that would be pluggable into our existing logging system in merchants api

TODO before 1.0

SDK 1.0 is ready to be released!

The SDK should have more features than just a wrapper.

  • More examples
    Currently we have only @bitcart_atomic_tipbot on telegram as an example, it is in examples/atomic_tipbot folder.
    It should be updated to show that bitcart also easily supports lightning network.
    Also if APIManager would be added, it would be a great example of Managers then.
    We should also add more basic examples, something like hello world but in bitcart world (:
    Some things to know should be added to docs too.

  • Possibly, consider switching to httpx instead of aiohttp and requests.
    HTTPX has both sync and async versions, making it easier to use in our use case.
    It does not have server functionality, so webhook functionality would optionally still require aiohttp or a similar library.
    But aiohttp client is hard to deal with because of unclosed session hacks, which shouldn't be a problem (and it isn't in httpx).
    We'll migrate to httpx when version 1.0 it's out.

  • #9 Stop using sync_generator.py

  • #4 Better exceptions

  • Managers
    For example, for each new wallet you have to create a new coin instance and pass xpub to it.
    For other coin, you have to use other coin class.
    It is fine, but we could add a manager, with the following possible API draft:

from bitcart import APIManager
manager = APIManager({"BTC": ["xpub1","xpub2"], "LTC": ["xpub1","xpub2"],"GZRO": ["xpub1","xpub2"], "BCH": ["xpub1","xpub2"]})
print(manager["BTC"]["xpub1"].balance())
print(manager["BTC"]["xpub2"].balance())
print(manager["LTC"]["xpub2"].balance())
# or maybe also
print(manager.BTC.xpub1.balance())
print(manager.BTC.xpub2.balance())
print(manager.LTC.xpub2.balance())
  • Better async support
    Also, in async version of SDK maybe something needs to be done to remove async with Coin():
    As after this block end it will close the session and coin becomes unusable.
    It is because of aiohttp session not closing automatically.
    Also maybe async for support could be added for some methods.

  • New utilities
    Each coin may have new format_satoshis method or whatever called which can conveniently convert coin to satoshi or whatever this coin has.
    Also some other utility functions may be considered.

Websocket connection works strange inside docker

So, my app is fully in docker compose, like this:

volumes:
  tron_data:

networks:
  bitcart-net:
    driver: bridge

services:
  app:
    build: .
    command: python main.py
    volumes:
      - ./:/app
    networks:
      - bitcart-net

  bitcart-trx:
    image: bitcart/bitcart-trx:stable
    environment:
      - TRX_NETWORK=testnet
      - TRX_SERVER=https://nile.trongrid.io
      - TRX_DEBUG=true
    networks:
      - bitcart-net
    volumes:
      - tron_data:/data

And here's the code:

from bitcart.coins.trx import TRX

trx = TRX(xpub="my private key", rpc_url="http://bitcart-trx:5009")

@trx.on("new_transaction")
def handle_new_transaction(event, tx, amount):
    print(event, tx, amount)

if __name__ == "__main__":
    trx.start_websocket()

This code above doesn't print anything at all, even when I transfer funds to the wallet, so I tried the following:

class CustomTRX(TRX):
    async def process_updates(self, updates, *args, **kwargs):
        print(updates)
        return await super().process_updates(updates, *args, **kwargs)

Now it prints the updates, as it should:

[{'event': 'new_block', 'height': 41733568}]
[{'event': 'new_block', 'height': 41733569}]
[{'event': 'new_block', 'height': 41733570}]
[{'event': 'new_block', 'height': 41733571}]

When I transfer funds to my wallet, it doesn't get the transaction at all, no matter how much I wait.

But when I change the last line of main.py to trx.poll_updates() it works ;(

[]
[{'event': 'new_block', 'height': 41733860}, {'event': 'new_block', 'height': 41733861}]
[{'event': 'new_transaction', 'tx': 'a72b4dd259c8da44349ee2de7d382477d4d85c1b1fe9513ecef7b06f0b4123a9', 'from_address': 'TXEVfNEesAvUEyNkxu5tBxhdMUH5B3hCPv', 'to': 'TCkTgU9QGp3YdKChhX4VKHxHjxzK47AvfA', 'amount': '15.000000', 'contract': None}]
new_transaction a72b4dd259c8da44349ee2de7d382477d4d85c1b1fe9513ecef7b06f0b4123a9 15.000000
[]
[]

What's really, really weird to me is that it DID work, but then it just stopped...


Update:

I wrote big a... explanation of the problem, but in the end of it I found the problem 🥲

At first, I tried to separate bitcart-trx from the compose like this:

docker run -p 5009:5009 -v ./.data/:/data -e TRX_NETWORK=testnet -e TRX_SERVER=https://nile.trongrid.io -e TRX_DEBUG=true --restart unless-stopped bitcart/bitcart-trx:stable

rpc_url in this case was http://host.docker.internal:5009, and it still didn't work

But then I ran my code separate from compose too, just with python main.py, rpc_url now was http://localhost:5009.
And it for some reason it works... 🤯

So the problem must be in the docker network or something? I don't understand why exactly "new_transaction" events are not sent...

Refactor to stop using sync_generator.py

Currently, to avoid maintenance burden, only async version is developed and tested in the repo.
Sync version is got by running sync_generator.py. It is not a clever generator using AST, instead it just removes async and await. It is not stable as it is very simple. The main downside is that it overrides source files, so when testing a sync version, all change made will be converted into sync and diff will be huge.
Also, because of constant if ASYNC: checks in the code, it might not be running very fast.
Instead of using runtime checks, jinja2 templates could be used.
Main target is to make python3 setup.py develop still working, but for both versions, and without overriding source files (and in easy-to-debug way for IDE's).
Reference files:
https://github.com/MrNaif2018/bitcart-sdk/blob/master/sync_generator.py
https://github.com/MrNaif2018/bitcart-sdk/blob/master/bitcart/providers/jsonrpcrequests.py#L9
https://github.com/MrNaif2018/bitcart-sdk/blob/master/bitcart/providers/jsonrpcrequests.py#L42

Better exceptions

Currently, upon any error got from server(json data's error key), it is just raised like
raise ValueError(json["data"])
There should be more error classes, maybe autogenerated. Or at least there should be a way to differentiate errors. (instead of doing like if "Error loading wallet" in str(e))
Also, as we have bitcart and bitcart-async, there might be a need in creating special ConnectionError because exceptions in async and sync version differ.

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.