Git Product home page Git Product logo

bitcoin-python-async-rpc's People

Contributors

bibajz avatar joxerx 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

Watchers

 avatar  avatar  avatar  avatar

bitcoin-python-async-rpc's Issues

getnetworkhashps() throws error

Hello, I'm having an issue collecting the network hash rate. I've used this repo to collect transaction and network information before, but I'm having issues with the getnetworkhashps() function.

It's throwing this error:

decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

SCRIPT:

# needed to connect to btc node
btc_rpc_connection = AuthServiceProxy("http://%s:%s@%s"%(RPC_BTC_USER, RPC_BTC_PASS, BTC_NODE))
x = btc_rpc_connection.getnetworkhashps()
print(x)

Any help would be great. Thanks

python scriptpubkey OP_CHECKMULTISIG to address

HI,I am new to Bitcoin, I have a problem and need help, first of all, thank you, the following is my question:
I tried to use the following code to convert the scriptPubKey in the Bitcoin transaction to an address, but why p2sh cannot be converted? Is there a similar python package that can be converted to an address by drinking it directly

I got no address from the rpc interface

{'txid': 'ca0cae6cd13e9150757612b1a3ea2e0e2d990d31098252892d032ffa73fc4f83', 'hash': 'ca0cae6cd13e9150757612b1a3ea2e0e2d990d31098252892d032ffa73fc4f83', 'version': 1, 'size': 205, 'vsize': 205, 'weight': 820, 'locktime': 0, 'vin': [{'txid': '05a9f3f1ed8099af7f37f818ce92442a1dccf9b471375bcb7dd4771db8080361', 'vout': 0, 'scriptSig': {'asm': '0 3045022041a325a85809d9b0c14b7858d8a7169f6dd847d41dbf342bfb745d76d15699c1022100cd6e77a8c3ffb95372d5ea716e0522efe121f253cf2381fd1d004204a8feeee7[ALL]', 'hex': '00483045022041a325a85809d9b0c14b7858d8a7169f6dd847d41dbf342bfb745d76d15699c1022100cd6e77a8c3ffb95372d5ea716e0522efe121f253cf2381fd1d004204a8feeee701'}, 'sequence': 4294967295}], 'vout': [{'value': 1.999, 'n': 0, 'scriptPubKey': {'asm': '1 037953dbf08030f67352134992643d033417eaa6fcfb770c038f364ff40d761588 0002d4a196263b56e24c40a87f4f5adc89b74a17712cc540c20135fc50a2403937 2 OP_CHECKMULTISIG', 'hex': '5121037953dbf08030f67352134992643d033417eaa6fcfb770c038f364ff40d761588210002d4a196263b56e24c40a87f4f5adc89b74a17712cc540c20135fc50a240393752ae', 'type': 'nonstandard'}}], 'hex': '0100000001610308b81d77d47dcb5b3771b4f9cc1d2a4492ce18f8377faf9980edf1f3a905000000004a00483045022041a325a85809d9b0c14b7858d8a7169f6dd847d41dbf342bfb745d76d15699c1022100cd6e77a8c3ffb95372d5ea716e0522efe121f253cf2381fd1d004204a8feeee701ffffffff01603bea0b00000000475121037953dbf08030f67352134992643d033417eaa6fcfb770c038f364ff40d761588210002d4a196263b56e24c40a87f4f5adc89b74a17712cc540c20135fc50a240393752ae00000000', 'blockhash': '00000000000002b211876fa753c8bf5c3b4f43198c6a20d91b26cd1ed5b71918', 'confirmations': 471187, 'time': 1355895514, 'blocktime': 1355895514}

I tried to convert the address myself, but it still doesn't work? Is there any way? thank you

def cover_address(script_pub_key):
    script_pub_key_str=hashStr(script_pub_key)
    if script_pub_key_str[0:4]==b'76a9':
        #This is a pubkeyhash
        bytes=script_pub_key[2]  #number of bytes in the pub_key
        try:
            assert bytes==20
        except:
            return None
        public_key = script_pub_key[3:3+bytes] #20 bytes
        z=b'\00'+public_key
        #checksum=sha256(sha256(z))[:4]
        #address1=base58.b58encode(z + checksum)
        address2=base58.b58encode_check(z)   # adds checksum for you
        return format(address2.decode())
    elif script_pub_key_str[0:2]==b'a9':
        #this is a scripthash (pay-to-script address)
        bytes=script_pub_key[1]  #number of bytes in the pub_key
        try:
            assert bytes==20
        except:
            return None
        public_key = script_pub_key[2:2+bytes] #20 bytes
        z=b'\05'+public_key  #used for mainnet
        address2=base58.b58encode_check(z)
        return address2.decode()
    elif script_pub_key_str[0:2]==b'00':
        spk = binascii.unhexlify(script_pub_key_str.decode())
        version = spk[0] - 0x50 if spk[0] else 0
        program = spk[2:]
        return bech32.encode('bc', version, program)
    else:
        #print(script_pub_key_str)
        return None

Unclosed httpx.AsyncClient warning

Hi - thank you for this great (and light) library!

Upon exiting the script, I often get the following warning:

/lib/python3.9/site-packages/httpx/_client.py:1781: UserWarning: Unclosed <httpx.AsyncClient object at 0x7ac57ff51310>.
See https://www.python-httpx.org/async/#opening-and-closing-clients for details.

I'm not really familiar with the httpx library so not sure what this implies. Should the bitcoinrpc library provide a call to close the httpxAsyncClient?

Tests

Since version v0.3.1 I claim this package is python3.9 compatible. This statement is backed only by the fact I was able to install it on python3.9.0rc1 and call

...
>>> await rpc.getbestblockhash()
... yes, it does return correct hash 

That is weak.

To be confident this package is able to withstand production-level usage and reach v1 status, test suite must be devised.

Execute getrawtransaction report error

class Btc():
    def connect(self):
        self.ConnRpc = BitcoinRPC(RPC_ADDRESS, RPC_PORT, RPC_USER,RPC_PASSWORD)
        self.OldConnRpc=AuthServiceProxy("http://%s:%s@%s"%(RPC_USER, RPC_PASSWORD, OLDRPC_ADDRESS))

    async def async_get_tx(self,tx):
        while True:
            raw_tx = await  self.ConnRpc.getrawtransaction(tx, True)
            break

    async def extract_block_addresses(self, block_hash):
        block = self.OldConnRpc.getblock(block_hash)
        tasks = []
        for tx in block[u'tx']:
            tasks.append(self.async_get_tx(tx))
        await asyncio.gather(*tasks)

    def get_block_address(self,block):
        add_insert = []
        while True:
            try:
                block_hash = self.OldConnRpc.getblockhash(block)
                break
            except:
                self.connect()
                print("get block error")
                sleep(1)
        self.loop.run_until_complete(self.extract_block_addresses(block_hash))


Is the error below caused by the query speed being too fast?

Traceback (most recent call last):
  File "scripthash_address.py", line 147, in <module>
    data.storage_address_scripthash()
  File "scripthash_address.py", line 131, in storage_address_scripthash
    self.get_block_address(block)
  File "scripthash_address.py", line 102, in get_block_address
    self.loop.run_until_complete(self.extract_block_addresses(block_hash))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 587, in run_until_complete
    return future.result()
  File "scripthash_address.py", line 88, in extract_block_addresses
    await asyncio.gather(*tasks)
  File "scripthash_address.py", line 59, in async_get_tx
    raw_tx = await  self.ConnRpc.getrawtransaction(tx, True)
  File "/usr/local/lib/python3.7/dist-packages/bitcoinrpc/bitcoin_rpc.py", line 146, in getrawtransaction
    timeout=httpx.Timeout(timeout),
  File "/usr/local/lib/python3.7/dist-packages/bitcoinrpc/bitcoin_rpc.py", line 63, in acall
    resp = orjson.loads((await req).content)
orjson.JSONDecodeError: expected value at line 1 column 1: line 1 column 1 (char 0)

The error will stop at this txid : 103e90d89a2695f8952b513b12c705850b6b91d6ee1a9040c87d2344a3e38ff9

Add batch support.

The title is pretty self explanatory, I'm not familiar enough with the project to create a pull request, but this is the patch I use to get this functionality:

import orjson
from bitcoinrpc import BitcoinRPC as BaseBitcoinRPC
from bitcoinrpc._exceptions import RPCError
class BitcoinRPC( BaseBitcoinRPC ):
	async def abatch( self, mp_pairs, **kwargs ):
		response = await self.client.post(
			url = self.url,
			content = orjson.dumps([
					{
						"jsonrpc": "2.0",
						"id": self._counter(),
						"method": mp.pop(0),
						"params": mp,
					}
					for mp in mp_pairs
				]
			),
			**kwargs,
		)
		response.raise_for_status()
		return [
			RPCError(content["error"]["code"], content["error"]["message"])
				if content['error'] else
			content['result']
			for content in orjson.loads(response.content)
		]
## BitcoinRPC Patch End```

Customization of `httpx.AsyncClient` during `BitcoinRPC` initialization

As noted in #3, httpx.AsyncClient basic settings are fine in most cases.

However, if one needs to a more fine-grained customization due to need of more concurrent connections, proxies, etc., they have no option to do so now.

For now, I have a following solution in mind:

class ImproperlyConfigured(Exception):
    pass


class BitcoinRPC:
    def __init__(self, host: str, port: int, rpc_user: str, rpc_password: str, **kwargs) -> None:
        self._url = self._set_url(host, port)
        self._client = self._configure_client(rpc_user, rpc_password, **kwargs)

    @staticmethod
    def _configure_client(rpc_user: str, rpc_password: str, **options) -> httpx.AsyncClient:
        auth = (rpc_user, rpc_password)
        headers = {"content-type": "application/json"}

        options = dict(options)
        if not options:
            return httpx.AsyncClient(auth=auth, headers=headers)

        if "auth" in options:
            raise ImproperlyConfigured("Authentication cannot be set via options!")

        if "headers" in options:
            _additional_headers = dict(options.pop("headers")) 
            headers.update(_additional_headers)
            # guard against content-type overwrite
            headers["content-type"] = "application/json"

        return httpx.AsyncClient(auth=auth, headers=headers, **options)

All the keyword arguments passed to the initializer of BitcoinRPC will be passed directly to the httpx.AsyncClient, with the exception of auth keyword. Also, headers will need to be tamed a bit with the content-type key since it is supposed to be application/json.

It will then be this library's user's responsibility to conform to the interface exposed by httpx.AsyncClient's initiliazer.

Revisit and add new RPC methods

I do not recall which version of Bitcoin Core was the last released version of this library tested against.

With Bitcoin Core v24.1 being released few days ago - https://github.com/bitcoin/bitcoin/releases/tag/v24.1 - and v25.0 possible being released in few weeks, it's worth taking a look on:

  • what was changed
  • what was added
  • what was removed

#15 should help with testing this.

As for the additional RPC methods, of particular interest are those related to PSBTs, so take a look at them.

Rework instantiation of `BitcoinRPC`

As was already noted here - #10 (comment) - the way to instantiate BitcoinRPC is quite clunky.

It allows a user to instantiate the underlying httpx.AsyncClient with a auth tuple (which is btw mandatory, you cannot create a BitcoinRPC to connect to a server not requiring user/passwd!) and then somewhat awkwardly headers and other options...

To better accomodate for more advanced configurations of the httpx.AsyncClient (proxy support, connection pooling, timeouts - #13 (comment) ), BitcoinRPC should be instantiated with an argument client: httpx.AsyncClient.

However, to preserve the ease of one-shot testing and shield the users from dealing with the underlying httpx library, an option to instantiate the BitcoinRPC with (url, rpc_user, rpc_password) should be preserved.

Sketched roughly:

class BitcoinRPC:
    def __init__(self, url: str, client: httpx.AsyncClient):
        self._url = url
        self._client = client
        ...

    @classmethod
    def from_url(cls, url, rpc_user, rpc_password):
        client = setup_client_with_sane_defaults(rpc_user, rpc_password)
        return cls(url, client)

    ...

NOTE: This will result in a BREAKING change.

Async context manager for BitcoinRPC

As noted in #6 (comment), remembering to call BitcoinRPC.aclose to close the underlying httpx.AsyncClient feels repetitive and one may forget it.

Implement __aenter__ and __aexit__ coroutines which will handle the closing automatically.

Key error at line 135

Probably found a bug here
Try to change line to:

if content.get("error") is not None:
    raise RPCError(content["error"]["code"], content["error"]["message"])

Create a custom image for `regtest`

As noted in #5 , it would be nice to have a way to test this library.

Easiest way is to test it is pointing it to a fresh regtest node.

I have not surveyed the current state of Bitcoin regtest images and how up-to-date they are, but even if they were OK, I believe it's still worth having a knowledge how Bitcoin node is compiled and configured.

Also, having the Docker/Containerfile around means giving other contributors a way to audit against what version the tests are run as well as inspiration for their further experiments.

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.