Some minor things to consolidate and some guidelines for Development.md (#63)

* Some minor things to consolidate and some guidelines for Development.md
* Add a SpecterError derived from Exception
* Adding vue.js, see #63
* bugfix introduced in #66 missing import pyserial and serial
This commit is contained in:
Kim Neunert 2020-01-30 21:52:28 +01:00 committed by GitHub
parent 8539b8ac44
commit d9b9b2bc69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 94 additions and 4 deletions

View file

@ -8,6 +8,14 @@ pytest --docker # needs a working docker-setup (but not bitcoind)
pytest tests/test_specter -k Manager # Run all tests in a specific file matching "Manager"
```
# Developing on tests
There are some things worth taking a note here, especially if you rely on a specific state on the blockchain for your tests. Bitcoind is started only once for all the tests. Each time it's starting with the genesis-block. This has some implications:
* The [halving-interval for regtest](https://github.com/bitcoin/bitcoin/blob/99813a9745fe10a58bedd7a4cb721faf14f907a4/src/chainparams.cpp#L258) is only 150-blocks
* At the same time, still 100 blocks need to be minded in order to make the coins spendable.
* This combination results in that you can't rely on how many coins get mined if you want some testcoin on your address
* This also means that it makes a huge difference whether you run a test standalone or together with all other tests
* Depending on whether you do one or the other, you cannot rely on transactionIDs. So if you run a test standalone twice, you can assert txids but you can't any longer when you run all the tests
# More on the bitcoind requirements
Developing against a bitcoind-API makes most sense with the [Regtest Mode](https://bitcoin.org/en/developer-examples#regtest-mode). Depending on preferences and usecases, there are three major ways on how this dependency can be fullfilled:
* Easiest way via Docker
@ -46,6 +54,8 @@ In order to enable that, you need to activate pytest support by placing a settin
"python.testing.pytestArgs": ["--docker"]
}
```
**WARNING**: Make sure to never stop a unittest in between. Simply continue with the test and let it run through. Otherwise the docker-container used for the test won't get cleaned up and your subsequent test-runs will fail with strange issues. If you did that, simply kill the container (```docker ps; docker kill ...```)
More information on python-unit-tests on VS-Code can be found at the [VS-python-documentation](https://code.visualstudio.com/docs/python/testing).
## Debugging in VS-Code
@ -83,8 +93,28 @@ You can easily create a .vscode/launch.json file via the debug-window. However t
More information on debugging can be found at the [python-tutorial](https://code.visualstudio.com/docs/python/python-tutorial#_configure-and-run-the-debugger).
# General File Layout
# Guidelines and (for now) "best practices"
## General File Layout
Python/flask is not very opinionated and everything is possible. After reading (this)[https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure] and (this)[https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure] we decided for the "src-approach", at least the most obvious parts of it.
setup.py is not (yet) as complex as listed there and setup.cfg is not even (yet?!) existing.
If you see this to need some improvements, please make it in small steps and explain what the benefits of all of that.
## Some words about dependencies
As a quite young project, we don't have many dependencies yet and as a quite secure-aware use-case, we don't even want to have too many dependencies. That's sometimes the reason that we decide to roll our own rather then taking in new dependencies.
## Some words specific to the frontend
Also for that reason, we're avoiding npm and manage javascript dependencies by hand or do stuff manually. Feel free to use plain javascript in pages.
However, we're planning (or even have started) to use vue.js without using vue.js-components (that would require a build). So feel free to use vue.js but either make a thoughtfull proposal on how to manage the vue.js build or don't use vue.js-components. Also, specter-desktop is not a one-page-app and also doesn't want to become one.
This [security-link](https://vuejs.org/v2/guide/security.html) might be interesting when developing vue.js.
We're aware that currently the app is not very compatible on different browsers and there is no clear strategy yet on how (and whether at all) to fix that. High level consultancy help on that would be appreciated even so (or especially when) you take the above security/dependency requirements into account.
## Some word about style
* The icons are coming from https://material.io/resources/icons/?style=baseline
* Colorizing the icons make them much more expressive. Current favorite colors are:
* nice orange #F5A623
* nice blue #4A90E2
* A designer would probably rant about all these bad choices. Professional help, especially in the frontend, is very much appreciated.

View file

@ -23,6 +23,8 @@ stem==1.7.1
typing-extensions==3.7.4
urllib3==1.25.6
Werkzeug==0.16.0
serial==0.0.97
pyserial==3.4
# only for testing currently
docker==4.1.0
pytest==5.2.2

View file

@ -50,6 +50,10 @@ def get_cli(conf):
host=conf["host"], port=conf["port"], protocol=conf["protocol"])
return cli
class SpecterError(Exception):
''' A SpecterError contains meaningfull messages which can be passed directly to the user '''
pass
class Specter:
def __init__(self, data_folder="./data", config={}):
if data_folder.startswith("~"):
@ -689,7 +693,7 @@ class Wallet(dict):
return None
return self.balance["trusted"]+self.balance["untrusted_pending"]
def createpsbt(self, address:str, amount:float, subtract:bool=False, fee_rate:float=0.0, fee_unit="SAT_B", coinselects=[]):
def createpsbt(self, address:str, amount:float, subtract:bool=False, fee_rate:float=0.0, fee_unit="SAT_B"):
"""
fee_rate: in sat/B or BTC/kB. Default (None) bitcoin core sets feeRate automatically.
"""

6
src/specter/static/vue.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -134,6 +134,7 @@ function hideLoader(){
// e.addEventListener("click", showLoader);
// });
</script>
<script src="/static/vue.min.js"></script>
{% block scripts %}
{% endblock %}
</body>

View file

@ -122,6 +122,50 @@ def devices_filled_data_folder(empty_data_folder):
]
}
''')
with open(empty_data_folder+"/devices/specter.json", "w") as text_file:
text_file.write('''
{
"name": "Specter",
"type": "specter",
"keys": [
{
"derivation": "m/48h/1h/0h/2h",
"original": "Vpub5n9kKePTPPGtw3RddeJWJe29epEyBBcoHbbPi5HhpoG2kTVsSCUzsad33RJUt3LktEUUPPofcZczuudnwR7ZgkAkT6N2K2Z7wdyjYrVAkXM",
"fingerprint": "08686ac6",
"type": "wsh",
"xpub": "tpubDFHpKypXq4kwUrqLotPs6fCic5bFqTRGMBaTi9s5YwwGymE8FLGwB2kDXALxqvNwFxB1dLWYBmmeFVjmUSdt2AsaQuPmkyPLBKRZW8BGCiL"
},
{
"derivation": "m/84h/1h/0h",
"original": "vpub5ZSem3mLXiSJzgDX6pJb2N9L6sJ8m6ejaksLPLSuB53LBzCi2mMsBg19eEUSDkHtyYp75GATjLgt5p3S43WjaVCXAWU9q9H5GhkwJBrMiAb",
"fingerprint": "08686ac6",
"type": "wpkh",
"xpub": "tpubDDUotcvrYMUiy4ncDirveTfhmvggdj8nxcW5JgHpGzYz3UVscJY5aEzFvgUPk4YyajadBnsTBmE2YZmAtJC14Q21xncJgVaHQ7UdqMRVRbU"
},
{
"derivation": "m/84h/1h/1h",
"original": "vpub5ZSem3mLXiSK55jPzfLVhbHbTEwGzEFZv3xrGFCw1vGHSNw7WcVuJXysJLWcgENQd3iXSNQaeSXUBW55Hy4GAjSTjrWP4vpKKkUN9jiU1Tc",
"fingerprint": "08686ac6",
"type": "wpkh",
"xpub": "tpubDDUotcvrYMUj3UJV7ZtqKgoy8JKprrjdHubbBb3r7qmwHsEH69g7h6xyanWaCYdVEEV3Yu7a6s4ceFnp8DjXeeFxY8eXvH7XTAC4gxfDNEW"
},
{
"derivation": "m/84h/1h/2h",
"original": "vpub5ZSem3mLXiSK64v64deytnDCoYqbUSYHvmVurUGVMEnXMyEybtF3FEnNuiFDDC6J18a81fv5ptQXaQaaRiYx8MRxahipgxPLdxubpYt1dkD",
"fingerprint": "08686ac6",
"type": "wpkh",
"xpub": "tpubDDUotcvrYMUj4TVBBYDKWsjaUcE9M52MJd8emp7QTAJBDTY9BRRFdomVCAFAjWMNcKLe8Cd5HJwg3AJKFyEDcGFTNyryYJgYmNdJMhwB2RG"
},
{
"derivation": "m/84h/1h/3h",
"original": "vpub5ZSem3mLXiSK8cKzh4sHxTvN7mgYQA29HfoAZeCDtX1M2zdejN5XVAtVyqhk8eui18JTtZ9M3VD3AiWCz8VwrybhBUh3HxzS8js3mLVybDT",
"fingerprint": "08686ac6",
"type": "wpkh",
"xpub": "tpubDDUotcvrYMUj6zu5oyRdaZSjnq56GnWCfXRuUz38zSWztUvpJuFjsjscGHhheyAncK4z15rLVukBdUDwpPBDLtRBykqC9KHeG9akJWRipKK"
}
]
}
''')
return empty_data_folder # no longer empty, though

View file

@ -7,6 +7,7 @@ def test_BitcoinCli(bitcoin_regtest):
cli = BitcoinCLI(brt.rpcconn.rpcuser, brt.rpcconn.rpcpassword, host=brt.rpcconn.ipaddress, port=brt.rpcconn.rpcport)
cli.getblockchaininfo()
# To investigate the Bitcoin API, here are some great resources:
# https://bitcoin.org/en/developer-reference#bitcoin-core-apis
# https://chainquery.com/bitcoin-cli
# https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line

View file

@ -104,6 +104,7 @@ def test_WalletManager(bitcoin_regtest, devices_filled_data_folder, device_manag
psbt = wallet.createpsbt(random_address,10, True, 10)
# the most relevant stuff of the above object:
assert len(psbt['tx']['vin']) == 1 # 1 input
assert psbt['tx']['vin'][0]['txid'] == "730b41bd1e77b65770bfec73304da5c34cc1bad100394e6f5cc020bb5dbe65fd"
assert len(psbt['tx']['vout']) == 2 # 2 outputs
# Now let's send some money to this wallet (creating 10 more potential inputs)
for i in range(0,4): # 40 coins as a whole
@ -125,6 +126,7 @@ def test_WalletManager(bitcoin_regtest, devices_filled_data_folder, device_manag
assert rpce.error_msg == "Insufficient funds"
pass
# But wallet.createpsbt supports it (by explicitely specifying inputs)!
wallet.createpsbt(random_address, 60, True, 10)
bitcoin_regtest.mine()
psbt = wallet.createpsbt(random_address, 60, True, 10)
assert len(psbt['tx']['vin']) == 3
assert psbt['tx']['vin'][2]['txid'] == '730b41bd1e77b65770bfec73304da5c34cc1bad100394e6f5cc020bb5dbe65fd'