Giter Club home page Giter Club logo

spectrum's Introduction

Spectrum - Specter Desktop + Electrum

This is a electrum-adapter. It exposes a Bitcoin-Core style API while using an electron API in the backend. It might be useful in specific usecases, e.g. having better performance when connecting to a electrum-server via Tor. In order to do that, it needs a Database. Quite easily you can use a kind of builtin SQLite. Depending on your usecase, you might want to use an external DB.

Modes of usage

This can be used either in standalone mode or as a specter-extension. The second option is probably the main use-case.

Standalone

Get this to work with something like that:

python3 --version # Make sure you have at least 3.8. Might also work with lower versions though
virtualenv --python=python3 .env
. ./.env/bin/activate
pip3 install -e .

# If you have a electrum server running on localhost:
python3 -m cryptoadvance.spectrum server --config cryptoadvance.spectrum.config.NigiriLocalElectrumLiteConfig

# If you want to run on mainnet and use emzy's Server
python3 -m cryptoadvance.spectrum server --config cryptoadvance.spectrum.config.EmzyElectrumLiteConfig

# Using Emzy's server but with a postgres
export DB_USERNAME=bla
export DB_PASSWORD=blub
python3 -m cryptoadvance.spectrum server --config cryptoadvance.spectrum.config.EmzyElectrumPostgresConfig

Check the config.py for the env-vars which need to be exported in order to connect to something different than localhost.

Specter Extension

In order to get a development environment:

virtualenv --python=python3 .env
. ./.env/bin/activate
pip3 install -e .
pip3 install cryptoadvance.specter
python3 -m cryptoadvance.specter server --config DevelopmentConfig --debug

TODO:

  • refill keypool when address is used or new address is requested
  • flask debug=True flag creates two electrum sockets that notify twice - this causes duplications in the database
  • reconnect with electrum on disconnect
  • add support for credentials / cookie file for RPC calls

Run the Tests

pip3 install -e ".[test]"
pytest

Development

Before your create a PR, make sure to blackify all your changes. In order to automate that, there is a git pre-commit hook which you can simply install like this:

pre-commit install

spectrum's People

Contributors

k9ert avatar moneymanolis avatar paarthagarwal avatar relativisticelectron avatar stepansnigirev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

spectrum's Issues

Error handling not yet good enough

Describe the bug

Traceback (most recent call last):
  File "cryptoadvance/specterext/spectrum/bridge_rpc.py", line 86, in multi
  File "cryptoadvance/specterext/spectrum/bridge_rpc.py", line 86, in <listcomp>
  File "cryptoadvance/spectrum/spectrum.py", line 348, in jsonrpc
  File "cryptoadvance/spectrum/spectrum.py", line 343, in jsonrpc
  File "cryptoadvance/spectrum/spectrum.py", line 57, in wrapper
  File "cryptoadvance/spectrum/spectrum.py", line 1025, in walletcreatefundedpsbt
cryptoadvance.spectrum.spectrum.RPCError: ('Insufficient funds', -4)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "flask/app.py", line 1523, in full_dispatch_request
  File "flask/app.py", line 1509, in dispatch_request
  File "flask_login/utils.py", line 272, in decorated_view
  File "cryptoadvance/specter/server_endpoints/wallets/wallets.py", line 531, in send_new
  File "cryptoadvance/specter/commands/psbt_creator.py", line 115, in create_psbt
  File "cryptoadvance/specter/wallet.py", line 1714, in createpsbt
  File "cryptoadvance/specter/rpc.py", line 459, in fn
  File "cryptoadvance/specterext/spectrum/bridge_rpc.py", line 98, in multi
AttributeError: 'object' object has no attribute 'status_code'

To Reproduce
Steps to reproduce the behavior:

  1. Create a PSBT with a VERY low fee
  2. Sign PSBT
  3. Send Transaction

Expected behavior
The error message needs to bubble up in the UI to the user

Desktop (please complete the following information):

  • v1.14.0-pre5

Wallet might use wrong rpc-instance when switching nodes with same network

Currently, in the wallet constructor we have:

        self.rpc = self.manager.rpc.wallet(
            os.path.join(self.manager.rpc_path, self.alias)
        )

This means that if the walletManager changes its rpc-instance, this will not change the rpc-class of the wallet. As this rpc-instance is used down by a lot more objects (addresses/TxList/TxItem/...) this has quite some large impact.

Fixing that is possible in these ways:

  • Creating a property out of the rpc attribute and then checking for changes in the WalletManager rpc instance before returning the old instance or creating a new one
  • all the other options sound unreasonable

Implement wallet deletion in the database

Currently, Spectrum is not deleting the wallets on the database side.

Implementation approach:

Create a rpc call in Spectrum (sth. like "delete_wallet") that can be called from the Spectrum node on the Specter Core side.

Forget node functionality is missing

Could be integrated here on this screen. "Forget node" button only if there is a Spectrum node already configured.
With sth. like:
app.specter.node_manager.delete_node(node, app.specter)

image

Needs this issue to be done first:
#13

Implement RBF in Spectrum

The current error is:
cryptoadvance.spectrum.spectrum.RPCError: ('Method not found (utxoupdatepsbt)', -32601)

since the RPC call utxoupdatepsbt doesn't exist / isn't handled in Spectrum.

BDK could be used here.

More background in this issue:
cryptoadvance/specter-desktop#2173

Failed to load UTXOs

Apparently, the check_utox method is not working properly in Spectrum, resulting in such errors:

grafik

This results in not being able to view the Transactions tab or the Addresses tab.

Chore: Replacing the hand-made elsock implementation

Connecting to a Websocket Server is quite a standard thing and done all over the place. There are good libraries doing that job and doing that job well (error handling/performance/testing/maintenance/security fixes). We're using a custom implementation in elsock.py and i pledge for replacing it with an external library.

Lately i looked into https://github.com/jeffthibault/python-nostr (which has a very nice and clean codebase btw) and it's using https://github.com/websocket-client/websocket-client which seem to be a quite mature thing.

Update: The idea is stupid as the ElectrumConnection is not a websocket connection but a custom socket-protocol.

Hot wallet not implemented (correctly)

Created a hot wallet but in the wallet table in the database it shows for the wallet private keys enabled 0 and there is no seed.
When trying to sign a tx with the hot wallet, I get:

grafik

TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float'

spectrum
[2022-07-14 09:37:21,427] INFO in spectrum: RPC called getbalances wallet_name: specterbd9330750bc34d3b/myhot
spectrum
[2022-07-14 09:37:21,435] ERROR in spectrum: FAIL method getbalances wallet specterbd9330750bc34d3b/myhot exc unsupported operand type(s) for *: 'decimal.Decimal' and 'float'
spectrum
Traceback (most recent call last):
spectrum
File "/usr/src/app/src/cryptoadvance/spectrum/spectrum.py", line 323, in jsonrpc
spectrum
res = m(wallet, *args, **kwargs)
spectrum
File "/usr/src/app/src/cryptoadvance/spectrum/spectrum.py", line 57, in wrapper
spectrum
return f(*args, **kwargs)
spectrum
File "/usr/src/app/src/cryptoadvance/spectrum/spectrum.py", line 760, in getbalances
spectrum
"trusted": round(confirmed * 1e-8, 8),
spectrum
TypeError: unsupported operand type(s) for *: 'decimal.Decimal' and 'float'
spectrum
[2022-07-14 09:37:21,441] INFO in _internal: 10.244.0.122 - - [14/Jul/2022 09:37:21] "POST /wallet/specterbd9330750bc34d3b/myhot HTTP/1.1" 200 -
spectrum
[2022-07-14 09:37:28,839] INFO in healthz: ready?

Wallet manager needs to be refactored to use Spectrum node alongside Core node

Gathering some problems / errors of the status quo in this issue:

1) Loadwallet error

  • Creating a wallet while using Spectrum generates a JSON file but doesn't save the wallet file on the Core node (obviously) since it uses the database to store the wallet data.
  • Therefore, when you switch back to using the Core node you get this error:

grafik

Feature: User Feedback for not synced nodes and DBs

One of the main reasons specter doesn't show the correct amounts is a not-synced node. For Spectrum, this might also be the case but there is another reason on top: Spectrum just booted up and connected to the electrum server but have not yet sunscribed to all the scripthashes it needs to. A scripthash is basically an address and this looks like this in the log:

[2023-01-23 12:07:39,618] INFO in spectrum: Now subscribed to 2900 scripthashes
[2023-01-23 12:07:44,015] INFO in spectrum: Now subscribed to 3000 scripthashes
[2023-01-23 12:07:49,189] INFO in spectrum: Now subscribed to 3100 scripthashes
[2023-01-23 12:07:53,949] INFO in spectrum: Now subscribed to 3200 scripthashes
...

Potentially, this could be shown as a percentage in the logs as the potential scripthashes are all in the DB. Simplified code from spectrum.py sync-method:

        for sc in Script.query.all():
            # ignore external scripts (labeled recepients)
            if sc.index is None:
                continue
            subscription_logging_counter += 1
            if subscription_logging_counter % 100 == 0:
                logger.info(
                    f"Now subscribed to {subscription_logging_counter} scripthashes"
                )
            res = self.sock.call("blockchain.scripthash.subscribe", [sc.scripthash])
            if res != sc.state:
                self.sync_script(sc, res)

So unless this loop is finished, specter might be outdated. This should clearly be reflexted in the UI.
The current way of showing that looks like this:
image
If you click on the node, you get some details of that node which currently looks like this:
image
This is not optimal. I think it could be shown how much blocks are still too sync but both of the screenshots don't show that.

Anyway, this is about spectrum. Here, we don't have the warning, but you can only see the blockcount of the electrum-server:
image

So in order to give better feedback:

  • We need a warning if the underlying timechain is not in sync OR spectrum has not yet finished subscribing to all Scripthashes
  • Also some better statistics on that page would be good. E.g. Number of (synced-) scripthashes, wallets, Utxos, Txs and Descriptors

So how should that be implemented? I would suggest the following:

  • Change the loop above to calculate percentages on top of absolute numbers
  • The warning-sign is based on the result of initialblockdownload
  • This is not properly implemented in [spectrum)(https://github.com/cryptoadvance/spectrum/blob/master/src/cryptoadvance/spectrum/spectrum.py#L383). I hope that electrum has a way to figure it out. Can't imagine that this is not obtainable via electrum.
  • As the effect on a spectrum not being DB-synced is the exact same than a Core being in initialblockdownload=True, i'd suggest that we implement it so that spectrum is not giving back false until the DB-sync is completed as well.
  • However, it'd be beneficial to also know the exact sync status. For that, i'd suggest to create an own non-core-rpi-call getscripthashsyncinfo which returns the status (which can be set as an attribute on the spectrum-object while syncing and the rpc-call reads it from there).
  • This change might be a good opportunity to also refactor all the rpc-calls in three files (spectrum.py is way too long), like: core_rpc.py, wallet_rpc.py and spectrum_rpc.py (with getscripthashsyncinfo as the currently only call in there)
  • If this is done, it should be easy to call that info somewhere in the spectrum_info.jinja.

More than one node for a specific network

We know that there are issues with running several nodes on the same network. E.g. a spectrum_node and a Bitcoin core node on mainnet. There might be bugs but there are also conceptual issues. Let's focus on the conceptual issues:

  • A wallet needs to exist on the specter-side as json file in the .specter-folder. (for mainnet e.g. ~/.specter/wallets/main/mywallet.json)
  • However, as we use the core-API for heavy lifting, the wallet also needs to exist behind the core API. There its name would be e.g. spectera8d0c2bcfa1dd45c/mywallet
  • If the wallet exists on the API-side but not on the specter-side, it will never be shown on specter. It practically disappeared
  • If the wallet exits on the specter side but not the API side, you will get something like this:
    image
  • So you will be able to "recreate" the wallet at the core side

So now it's possible to misuse this mechanism having more than one Node on the same network and then simply recreate the wallets on the API-side. There might be bugs:

So the switch_node method might not be working properly. This might be much more severe in this cases as it is in cases where more than one node but on different networks (e.g. liquid).

Should we allow that? I think we should, but we should setup a huge warning sign.

Connecting to a electrum backend via Tor

It'd not yet possible to connect to a electrum via Tor. We basically need something very similiar than specter.requests_session:

    def requests_session(self, force_tor=False):
        requests_session = requests.Session()
        if self.only_tor or force_tor:
            proxy_url = self.proxy_url
            proxy_parsed_url = urlparse(self.proxy_url)
            proxy_url = proxy_parsed_url._replace(
                netloc="{}:{}@{}".format(
                    str(random.randint(10000, 0x7FFFFFFF)),
                    "random",
                    proxy_parsed_url.netloc,
                )
            ).geturl()
            requests_session.proxies["http"] = proxy_url
            requests_session.proxies["https"] = proxy_url
        return requests_session

Extension-generation needs adjustements

The extension-generation process is currently assuming you need encrypted userdata. That should get adjusted like this:

Mind the different templating syntax. Those are "metatemplates" as they are creating templates which themself are later templates.

You can test it via using --tmpl-fs-source and checkout the dummy-project somewhere. Also i've created a small section about https://docs.specter.solutions/desktop/extensions/intro/#virtualenv-management

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.