Git Product home page Git Product logo

satoshiportal / cyphernode Goto Github PK

View Code? Open in Web Editor NEW
364.0 13.0 68.0 14.31 MB

Modular Bitcoin full-node microservices API server architecture and utilities toolkit to build scalable, secure and featureful apps and services without trusted third parties

License: MIT License

Dockerfile 1.05% Shell 73.09% JavaScript 24.46% Python 0.04% Go 0.91% PLpgSQL 0.44%
cyphernode bitcoin bitcoin-services docker-containers architecture lightning-network

cyphernode's Introduction

cyphernode

Modular Bitcoin full-node microservices API server architecture and utilities toolkit to build scalable, secure and featureful apps and services without trusted third parties.

What is cyphernode?

Cyphernode is a Free open-source alternative to hosted services and commercial Bitcoin APIs such as Blockchain.info, Bitpay, Coinbase, BlockCypher, Bitgo, etc. You can use it to build Bitcoin services and applications using your own Bitcoin and Lightning Network full nodes. It is a substitute for the Bitcore and Insight software projects.

It implements a self-hosted API which allows you to spawn and call your encrypted overlay network of dockerized Bitcoin and crypto software projects (virtual machines). The Docker containers used in this project are hosted at www.bitcoindockers.com.

It aims to offer all advanced features and utilities necessary to operate entreprise-grade Bitcoin services. It includes a curated list of functions using multiple software, but you can build your own private ones or add yours as a default option in the project.

It is currently in production by Bylls.com, Canada's first and largest Bitcoin payment processor, as well as Bitcoin Outlet, a fixed-rate Bitcoin exchange service alternative to Coinbase which allows Canadians to purchase bitcoins sent directly to their own Bitcoin wallet.

The project is in heavy development - we are currently looking for reviews, new features, user feedback and contributors to our roadmap.

image

Low requirements, efficient use of resources

Cyphernode is designed to be deployed on virtual machines with launch scripts, but with efficiency and minimalism in mind so that it can also run on multiple Rasberry Pi with very low computing ressources (and extremely low if installing pre-synchronized blockchain and pruned). Because of the modular architecture, heavier modules like blockchain indexers are optional (and not needed for most commercial use-cases).

  • For a full-node and all modules:
    • 350 GB of storage, 2GB of RAM.
  • Hardware wallets (ColdCard, Trezor) for key generation and signing (using PSBT BIP174), as well as for connecting to self-hosted web user interfaces.

Cyphernode Architecture

Cyphernode is an assembly of Docker containers being called by a request dispatcher.

The request dispatcher (requesthandler.sh) is the HTTP entry point. The request dispatcher is stateful: it keeps some data to be more effective on next calls. The request dispatcher is where Cyphernode scales with new features: add your switch, dispatch requests to your stuff. We are trying to construct each container so that it can be used separately, as a standalone reusable component.

Important to us:

Be as optimized as possible, using Alpine when possible and having the smallest Docker image size possible Reuse existing software: built-in shell commands, well-established pieces of software, etc. Use open-source software Don't reinvent the wheel Expose the less possible surface Center element: proxy_docker The proxy_docker is the container receiving and dispatching calls from clients. When adding a feature to Cyphernode, it is the first part to be modified to integrate the new feature.

proxy_docker/app/script/requesthandler.sh You will find in there the switch statement used to dispatch the requests. Just add a case block with your command, using other cases as examples for POST or GET requests.

proxy_docker/app/config You will find there config files. config.properties should be used to centralize configs. spender and watcher properties are used to obfuscate credentials on curl calls.

proxy_docker/app/data watching.sql contains the data model. Called "watching" because in the beginning of the project, it was only used for watching addresses. Now could be used to index the blockchain (build an explorer) and add more features.

cron_docker If you have jobs to be scheduled, use this container. Just add an executable and add it to the crontab.

Currently used to make sure callbacks have been called for missed transactions.

About this project

  • Created and maintained by www.satoshiportal.com
  • Dedicated full-time developer @kexkey
  • Project manager @FrancisPouliot
  • Contributor: @__escapee__
  • Disclaimer: as of release on Sept. 23 2018 the project is still it its early stages (Alpha) and many of the features have yet to be implemented. The core architecture and basic wallet operations and blockchain query functions are fully functional.

How to use cyphernode?

The core component of cyphernode is a request handler which exposes HTTP endpoints via REST API, acting as an abstraction layer between your apps and the open-source Bitcoin sofware you want to interact with.

Documentation

When calling a cyphernode endpoint, you are either

  • making a delegated request (call) to the functions of the P2P network nodes part of your overlay network (e.g. calling Bitcoin RPC)
  • directly using scripts and functions with your data, parameters and configs (e.g. derive segwit addresses from Master Public Key, interacting with C-Lightning command line to create and pay a Bolt11 invoice, stamp and verify a file using OpenTimestamps, etc.)
  • executing one of the custom script (function) which will make multiple requests to multiple docker containers based on the desired outcome (e.g. add transctions to a batch, sign and broadcast according to your custom schedule).
  • changing the configurations and parameters of the underlying sofware or the request dispatcher (e.g. choose derivation path, decide which docker containers you will be using).
  • deploying and activating components like the cron container which schedules certain tasks/calls.
  • create webhooks with active watch so that your app receives notifications via asynchronous callback

Make a custom backend for your app by adding your own modules and functions

  • Make your own cyphernode by adding any compatible docker container (e.g. Bitcoin-js, electrum personal server, block explorer index)
  • Creating custom scripts based on the features of the docerkized software
  • Create and add web-interface applications to your docker swarm. Your own web wallet (remote control with GUI over your nodes), graphana stats dashboard, reporting, notifications.

Roadmap/TODO

Utilities and API endpoints

  1. Add opentimestamps endpoints to stamp data, verify, upgrade, get information of OTS files
  2. Lightning network callbacks for payment notifications
  3. Address identification and validation scripts
  • Be able to detect if a given data is a Bitcoin address, P2SH address, Bech32 address, Bolt11 invoice
  • Validate according to the type
  1. Add blockchain indexer to enable bitcoin block explorer features
  2. Add Electrum Personal Server and Electrum Server dockers
  • By default, Electrum Personal Server is added to the container network 6.Create endpoints for all delegated tasks
  • Add all Bitcoin RPC endpoints
  1. Add PGP library docker and endpoints for various signatures
  • Cleartext signatures
  1. Add "deriveandwatch" script which derives a set of addresses and sends payment notifications
  • custom gap limit with 100 as default
  1. Add PayNyms library and endpoint
  2. Create launch scripts.

Related tools

  1. Open-source (white-label) web interface (self-hosted as part of the default Docker network)
  • Allow users to connect using Trezor
  • Send PSBT files to ColdCard wallet for remote signing
  • Change Bitcoin and C-Lighning configs.
  • Manually call all API endpoints (with parameters) in web-interface to empower non-technical users to perform advanced functions
  • Complete web-interface over Bitcoin Core RPC
  • View transactions, balances, etc.
  • suggestions welcome!
  1. Lunanode launcher web app

Security Roadmap

You can find it here: #13 (comment)

Example use-case for cyphernode

When building cyphernode, we had specific use-cases in mind that we built for ourselves. Use this as inspiration, and innovate on our procedures.

See one of Satoshi Portal's use case flow

Contributions

See contributing document

cyphernode's People

Contributors

aitorjs avatar bhodl avatar cryptoskillz avatar dependabot[bot] avatar dooglus avatar erjanmx avatar francispouliot avatar gabidi avatar kexkey avatar leon-do avatar magicfab avatar matt-auckland avatar mayankchhabra avatar phillamy avatar schulterklopfer avatar tiero avatar tomtibo 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

cyphernode's Issues

Automatic deploy on Lunaode VM

This is depending on issue #3 (http://github.com/SatoshiPortal/cyphernode/issues/3)

Lunanode is our cloud hosting provider for the past 3 years. They are reliable and accept payment via Bitcoin. They also have an API which allows us to execute the launch scripts and deploy the virtual machines and volumes on behalf of the user.

This requires the user to already have a LunaNode account

I believe that new LunaNode users would get some free credits from our referral link, but this assumes that the lunanode account is already funded with money.

We would host a LunaNode launcher page where the user will input his configurations.

The code to do this is already open source here for BTCPAY server https://github.com/LunaNode/launchbtcpay which has been done for BTCPay server. We'll be working on this fork here: https://github.com/SatoshiPortal/launchbtcpay

Force non-prune with LN

C-lightning is having a really bad time when using a prune Bitcoin Core node.

It calls getblock 30 times per second on pruned blocks and finally crashes. Even if docker restarts it, the instability of LN is such it's almost impossible to use.

Problem making a request through the gatekeeper

I'm having problems making requests through the gatekeeper.

I try this command:

"id="003";h64=$(echo -n "{"alg":"HS256","typ":"JWT"}" | base64);p64=$(echo -n "{"id":"$id","exp":$((date +"%s"+10))}" | base64);k="b9b8d527a1a27af2ad1697db3521f883760c342fc386dbc42c4efbb1a4d5e0af";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1/v0/getbestblockinfo"

but I get "404 page not found" error. All the log here [0].

If I make the call direcly on the proxy (echo "GET /getbestblockinfo" | docker run --rm -i --network=cyphernodenet alpine nc proxy:8888 -) I get results.

On https://localhost/welcome is all green except bitcoin feature but the node is update and syncing ok. If I use https://cyphernode on a request call on the machine cyphernode is running I get: "Could not resolve host: cyphernode" error.

¿Why could I get "404 page not found" making a request through the gatekeeper?

Thanks! :-D

[0] * Trying 127.0.0.1...

  • TCP_NODELAY set
  • Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
  • ALPN, offering h2
  • ALPN, offering http/1.1
  • successfully set certificate verify locations:
  • CAfile: /etc/ssl/certs/ca-certificates.crt
    CApath: /etc/ssl/certs
  • TLSv1.2 (OUT), TLS handshake, Client hello (1):
  • TLSv1.2 (IN), TLS handshake, Server hello (2):
  • TLSv1.2 (IN), TLS handshake, Certificate (11):
  • TLSv1.2 (IN), TLS handshake, Server key exchange (12):
  • TLSv1.2 (IN), TLS handshake, Server finished (14):
  • TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
  • TLSv1.2 (OUT), TLS change cipher, Client hello (1):
  • TLSv1.2 (OUT), TLS handshake, Finished (20):
  • TLSv1.2 (IN), TLS handshake, Finished (20):
  • SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
  • ALPN, server accepted to use h2
  • Server certificate:
  • subject: CN=TRAEFIK DEFAULT CERT
  • start date: May 29 13:22:40 2019 GMT
  • expire date: May 28 13:22:40 2020 GMT
  • issuer: CN=TRAEFIK DEFAULT CERT
  • SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
  • Using HTTP2, server supports multi-use
  • Connection state changed (HTTP/2 confirmed)
  • Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
  • Using Stream ID: 1 (easy handle 0x55a776d6d900)

GET /v0/getbestblockinfo HTTP/2
Host: 127.0.0.1
User-Agent: curl/7.58.0
Accept: /
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwMyIsImV4cCI6MTU1OTE0NTQ5MH0=.7f9ac409f785bba25c3d493f1ca7eacd151e8f3270b8a905c98519eb224f746c

  • Connection state changed (MAX_CONCURRENT_STREAMS updated)!
    < HTTP/2 404
    < content-type: text/plain; charset=utf-8
    < x-content-type-options: nosniff
    < content-length: 19
    < date: Wed, 29 May 2019 15:58:01 GMT
    <
    404 page not found
  • Connection #0 to host 127.0.0.1 left intact

Validate payment request endpoint

What I imagine is a "Bitcoin payment destination endpoint".

  • The app sends whatever Bitcoin address user enters
  • We check all the possibilities
  • Returns, if valid: type
  • Returns, if we don't find a valid type: invalid

What do look for?

  • is it a valid non-p2sh address
  • Is it a P2SH-wrapped segwit address (can we know this?)
  • Is it a bech32 address?
  • Is it a Bolt 11 invoice?
  • Is it PayNym?
  • Is it a valid BIP21 URI?

We should be able to do this with the existing PyCoin library and C-Lighinthning, otherwise we should look at Bitcoin-JS or other libs.

Auto-bump script idea

An idea for a new script to automatically bump the fee of a transaction based on expected confirmation times vs blocks passed since transaction.

  1. Auto-bump would be a config in cyphernonde using the proxycron
  2. When doing a transaction, we record the fee and expected number of blocks (n)
  3. We keep watch of the transaction in the mempool
  4. We set a threshold after with we will autobump (x %)
  5. Once the transaction has reached (n + x%) we call the estimate smartfee feature to get the new estimate fees required for the same amount of estimated blocks, than we substract the existing fees, and call bumpfee feature and add what is missing.

This would allow us to set lower fees, and offset having a transaction stuck in the mempool because the fee has increased.

This is a very preliminary draft.

Add fiat currency pricing + invoiceID

Abstract

We need to add fiat currency pricing for merchants to be able to generate dynamic invoices that will update Bitcoin amounts in invoices according to a constant fiat amount following a cron schedule.

API endpoints

  • get_price
  • create_invoice
  • list_invoices
  • get_invoice

Get price

Params:

  • time (default: now, optional, if imported archive, an earlier time)
  • currency source (default: Bull Bitcoin $CAD)

Returns:

  • price in fiat

fiat pricing source:

Create_invoice

workflow

  • calls the pricing server with a fiat amount
  • returns a Bitcoin amount
  • fetches a new Bitcoin address from xpub
  • puts watch on that Bitcoin address
  • cyphernode creates an internal InvoiceID which matches a fiat amount to a Bitcoin address
  • that InvoiceID will also have a bitcoin_amount associated to it, but this bitcoin_amount is only valid for a given time-frame (e.g. 15 minutes)
  • a webhook is placed on the invoiceID instead of simply the Bitcoin address

InvoiceID format

At create_invoice

User-input constants:

  • to_amount: fiat
  • label: for BIP21 uri
  • (optional) wallet_name (from where to take the key from)
  • (optional) cron_schedule (default: 15 minutes)
  • (optional) expires_at time

Cyphernode constants:

  • invoiceID: random
  • created at time
  • bitcoin_address

Cyphernode cron variables (updated by time)

  • bitcoin_amount
  • fiat_amount
  • exchange rate
  • bitcoin_uri (address, amount, label)
  • last updated at
  • time_remaining (until new update)

Once created, watch on blockchain

Cyphernode Bitcoin unconfirmed-tx variables

  • Bitcoin transaction ID (if any)
  • First_seen time
  • Transaction fee/kb
  • Is_replaceable flag
  • Amount_received (BTC)
  • sender's inputs and outputs
  • recipient utxo
  • Overpaid: (boolean)
  • Underpaid: (boolean)
  • Overpaid amount
  • Underpaid amount

cyphernode confirmed-tx variables

  • Blockheight
  • Blockhash
  • Blocktime in UTC

invoiceID status

InvoiceID will have a status based on time and Bitcoin transaction. the invoiceID status is added to the API response json

  1. open: is not expired, has not received a payment yet, is active

  2. payment_received: unconfirmed tx with outputs matching bitcoin_amount

  3. payment_confirmed: confirmed tx with outputs matching bitcoin_amount

  4. Overpaid_received: unconfirmed tx with outputs higher than Bitcoin_amount

  5. Underpaid_received: unconfirmed tx with outputs lower than Bitcoin_amount

  6. Overpaid_confirmed: unconfirmed tx with outputs higher than Bitcoin_amount

  7. Underpaid_confirmed: unconfirmed tx with outputs lower than Bitcoin_amount

callback events

  • invoice creation
  • invoice is updated by time
  • invoice is updated by watcher

list_invoices

Filter parameters:

  • by status

Returns all the invoices

  • invoiceID
  • status
  • Bitcoin address
  • label
  • txid

get_invoice

  • returns invoiceID JSON

InvoiceID json fields

  • invoiceID
  • status
  • created_at
  • last_updated
  • time_remaining
  • expiry_time
  • to_amount (fiat)
  • from_amount (Bitcoin)
  • bitcoin_address
  • wallet_name (from where to take the key from)
  • label
  • BIP21_URI
  • exchange_rate
  • Bitcoin transaction ID (if any)
  • Transaction first_seen time
  • Transaction confirmed time
  • Transaction block height
  • Transaction block hash
  • Transaction fee
  • Transaction size
  • Transaction fee/bytes
  • Is_replaceable flag
  • Amount_received (BTC)
  • sender's inputs and outputs
  • recipient utxo
  • Overpaid: (boolean)
  • Underpaid: (boolean)
  • Overpaid amount
  • Underpaid amount

If crypto contract enabled, using last_updated:

  • cleartext signature
  • cleartext signature hash
  • detached signature
  • detached signature hash
  • OTS files
  • invoice signature block time (last block)
  • invoice timestamp block time (ots block)

Cyphernode's architecture

I have a question about cyphernode's architecture ( https://raw.githubusercontent.com/SatoshiPortal/cyphernode/dev/doc/CN-Arch.jpg )

For example, when we call to the API/gatekeeper (https://127.0.0.1:2009/v0/getbestblockhash) using curl.

Cyphernode goes first to the gatekeeper. If the JWT credentials are valid, the request goes to the proxy. It looks where to send that request and it decide to send to the Bitcoin spender (I'm not sure here). The Bitcoin spender make the RPC request to bitcoin and send to the console the response. ¿Am I correct? Thanks! :-D

Change default address type and add config to setup

We should change the default address type to bech32 because we will need to have this anyway to integrate coinjoin.

This would affect:

  • watches, and watchbyxpub
  • get new address from spender
  • pycoin derive utilities

I think it should be possible to change this config in the cyphernode configs

priority: high

Input/params validation

Validate the provided parameters for each requesthandler's command.

  • Make it generic
  • Standardize error responses/structure/format
  • Use codes instead of textual descriptions of errors -- ref. multilingual support
  • Document the format and the codes
  • Log/trace pertinent msgs instead of Shell errors

Create BIP21 URI endpoint

Even though this is pretty easy to do client-side, we should add an endpoint that creates a BIP21 payment request from given data.

Notarize function and endpoint

Once we have PGP and OTS, we create an additional function which calls both of these.

The endpoint would be called "notarize" and the object would be a string

What it does:

  • Sends string to PGP docker for signing
  • Signature is hashed (do we need another docker for this or PGP JS already has it? Let's see)
  • Hash is sent to the OTS client
  • OTS client sends back OTS file
  • The API returns a callback including the original string, the OTS file, the hash of the OTS file

Another option:

  • We hash the string before signing, so that the PGP signature wouldn't be too big for a large string
  • In this case, we return both the string, the hash of the string, the hash of the signature and the OTS file

Another option: add proof-of-absence

  • When calling the API to notarize, the proxy can also call Bitcoin Core to get the last block hash. Before the signature is done, a small header-type field is added to the string so that both the string and the header are signed together by PGP.
  • This allows us to prove that the signature was not created before the time of the last block hash

Batch management and monitoring

Batches should have a unique ID so that we can do some more advanced operations on them.

Also, there should be a way to add multiple transactions to a batch via a single API call (e.g. import transactions into batch). CSV option could be interesting here.

Then we should have some notification system that tells the app the status of the batch:

  • Get information on a batch: time reamining, amount of bitcoins, list of tx, batch size (kb)
  • List batches (if we allow multiple at once)
  • Set automated threshold for notification (Bitcoin amount? Batch size?)

Get node Uri endpoint

It would be useful to have a "getnodeuri" endpoint so that webapps can add that to their LN invoice page if they people want to open a channel

idea: cyphernode control script

While writing my thoughts about #87 I got few ideas. Please let me share them here.

I would love to see a single more polished tool for managing cyphernode(s) on my host machine.

AFAIK current workflow is to call ./dist/setup.sh and then use ./dist/start.sh. Then user can rely on web interface https://localhost/welcome or inspect mapped data folders or interact directly with docker(-compose).

It would be nice to have one "umbrella" tool, say cn which I could put on path and control my cyphernode from it.

I think cyphernode configuration and installation should be conceptually two separate commands. User should be aware that he first does cn configure which asks questions and gives him a reproducible recipe file (your current config.sh or something like that) and then he calls cn build <config> to reproducibly build docker containers and prime his host machine (what you call INSTALL in setup.sh) to later cn start or cn stop.

While cyphernode is running he should be able to use other commands to inspect it or control it. E.g. he could access logs via cn logs ... or could access cli interfaces (like bitcoin-cli) from bitcoin container and other tools like that. In other words I'd like to see powerful wrapper tool to control cyphernode from host machine via cli. And IMO this should be the primary tool before you focus on building/exposing web interfaces. I'm not against them, but host machine cli tool must come first.

I just did something like this on much smaller scale in my other project. Please look at the source of the ./sv tool (in bash).

If you like the concept, I'd like to volunteer to build something along those lines for cyphernode (This assumes integrating current setup.sh, start.sh, stop.sh and maybe other control scripts I'm not yet aware of.)

E-mail notifications on events

Have a way to send e-mails (to the admin) triggered on events.

For example:

  • Spending hot wallet balance is below a certain amount
  • Error in logs (excluding debug traces)
  • A docker container restarted
  • Etc.

This should be implemented inside its own container that all the other containers can use/call.

Esplora

We want to integrate the Esplora Bitcoin block explorer by Blockstream in cyphernode. This will be selected as an optional module at the cyphernode launch. Once installed, the explorer web interface will be accessible by the user via browser. When installed, Esplora endpoints are made available via the cyphernode API.

Questions

  • Should we expose the Elctrs API in the cyphernode API?

  • When Elctrs is installed, should API calls be done to electrs rather than Bitcoin Core?

  • Integrate the web UI https://github.com/Blockstream/esplora

  • add confifs to cyphernode configs

`All options are optional.

NODE_ENV - set to production to enable js minification, or to development to disable (defaults to production)
BASE_HREF - base href for user interface (defaults to /, change if not served from the root directory)
API_URL - URL for HTTP REST API (defaults to /api, change if the API is available elsewhere)
PORT - port to bind http development server (defaults to 5000, has no effect when building)
BASE_URL - absolute base url for user interface (no default, only required for opensearch functionality)
NATIVE_ASSET_LABEL - the name of the network native asset (defaults to BTC)
SITE_TITLE - website title for <title> (defaults to Block Explorer)
SITE_DESC - meta description (defaults to Esplora Block Explorer)
HOME_TITLE - text for homepage title (defaults to SITE_TITLE)
SITE_FOOTER - text for page footer (defaults to Powered by esplora)
HEAD_HTML - custom html to inject at the end of
FOOT_HTML - custom html to inject at the end of
CUSTOM_ASSETS - space separated list of static assets to add to the build
CUSTOM_CSS - space separated list of css files to append into style.css`

  • add API endpoints to cyphernode API

  • test and review the tradeoffs of using --light and --disableprevout

  • if required, add --light and --disableprevout to cyphernode config options

Endpoint and scripts for PSBT

Once Bitcoin Core 0.17 comes out, we can create PSBT files using the standard in Bitcoin Core.

I think the best way to do this is to get people to add trasnsactions to a batch first via "addtobatch" and then create a PSBT file from a batch, since we already have all the UTXOs and amounts for that batch. This allows us to manage different batches of transactions.

The app would then select which batch it wants to create as a PSBT file, proxy would dispatch to Bitcoin Core to create the PSBT file and return it to the proxy which sends it to the app.

The app then returns a signed PSBT file to the proxy, which sends it to Bitcoin Core for broadcast.

Security Roadmap (architecture change + new features)

Security roadmap

Currently, Cyphernode security is based on the premise that the application connecting to the cyphernode will be part of the docker network. Different components of Cyphernode can run on different machines, but it is important to note that if one of the machines has root access compromised, they can take over all other parts of the network. To provent this, they can be run on a single machine where security is increased.

We did it in this way originally because that was functional for our own apps, but then again this does place constraints on people that may not want to have the same setup.

We realised two problems with this:

  • People don't necessarily want to have to run their entire app through the docker Swarm
  • People managing the application may not want developpers that have access to the application to also have access to the cyphernode instance.

A solution to this is simply to enable a public API with authentification system.

This has two main vulnerabilities:

  • Whoever has access to the API keys can send commands to components of the Cyphernode docker swarm, including to bitcoin core wallets for withdrawals.
  • If a user interface is connected to the API, anybody with access to the user interface (e.g. a web-wallet, an admin panel, etc.) then they can also use the API to get access to the docker network.

There are solutions to this:

  • Leverage hardware wallets for authentification to user interfaces, as well as SSH access to the virtual machines where the Cyphernode is hosted (required for updates and all server access)
  • Enable security policies that delay and mitigate the risks of unwanted access to the docker network, so that human intervention to prevent it is streamlined and almost completely automated.
  • Rely on off-line signing for all outflow of funds from a Cyphernode instance. This means that all or some transactions must be signed remotely, and there are no funds held in the Bitcoin Core wallet. This can be done using the PSBT BIP174 standard. In addition, we can add the Python-Trezor library as a docker component, which act as a wallet interface for the Trezor.
  • IP whitelisting
  • Generate new API keys server side and send them to app only after auth.
  • Remote killswitch to API access

Security policy proposal: have all outbound transactions included in a batch by default. The option to send outside of a batch is disabled, re-enabled only with hardware auth. Set a maximum threshold per batch. All batches exceding a certain size must be approved by admin via offline signing. Under a certain size, they are simply signed withing Bitcoin Core. You can set a batching schedule for office hours, so that an admin is always expected to sign transactions a few times per day. If an attacker gets access to the Cyphernode, he will not be able to exceed the limit without having to wait between batches or forcing the admin to notice as he manually signs.

Infrastructure

  • Create a system for API authentification which allows apps to connect remotely to Cyphernode without becoming part of the swarm. This would be exactly the same user experience as for commerical APIs such as Bitgo

  • Create default configurations for spender node vs. watch node. Spender node doesn't expose ports publicly, while watcher nodes do. Spender nodes would be encryped and connecting to them would require password additional to the API authentification.

  • IP address whitelist for API connections

Features

  • Enable the Trezor Pyton library to allow for Trezor wallet integration

  • Enable ColdCard integration and BIP174 for remote signing

Spending policies

The danger in having an app connect to a secure Cyphernode is that controlling the app would give direct control to the funds in the cyphernode.

We have an idea for spending policies, which is the following (in combination)

  • Add option to force all hot-wallet operations to be done via batch spend an disable instant "Send Bitcoins" API call, giving the cyphernode operator the option to completely remove the "send bitcoins" functions without going through a batching process. This means that an attacker could, at best, add the transactions he is attempting to do to withdraw funds from the wallt to a batch.

  • Add a "maximum batch size" threshold, either in BTC amount of % of funds available.
    If a batch hits the treshhold, the app operator is notified (callback and email). These batches require off-line signing and cannot be sent from the hot wallets

What this prevents

  • If an internal person or attacker takes control of the app, he cannot withdraw bitcoins, he can only send to batches.

  • He will only be able to withdraw the maximum batch size at the frequency of the batching schedules

  • The app operator can manually approve batches, and if he thinks something is off, he can detect it before it's too later.

  • The tradeoff between convenience and security is then lowered, and prevents large frauds/hacks without inhibiting small withdrawals

review dist/setup.sh

While investigating #83 I looked briefly at dist/setup.sh and I think it needs a review.

Issues spotted:

  • paths/arguments are not quoted consistently. For example usage of $current_path is all over the place used without quoting. Imagine someone clones your git repo onto a path with a space character in it, this will fall flat on its face.
  • usage of ansi colors should be abstracted into a function, also it should be optional and be disabled when terminal does not support colors or color support it disabled in non-tty sessions.

Suggestions:

  • current_path seems to be hardcoded to the dist directory, this should be configurable and I should be able to generate multiple independent cyphernodes outside the repo checkout
  • step/try/next is suspicious, I would rather see whole script running with set -e -o pipefail. Then you can always opt-out with set +e explicitly when doing something which is expected to exit with error status code which you want to handle "by hand". If you want to give user a feedback on error, you should trap ... ERR. When done properly this should trap all errors consistently, including those in pipes and outside your try wrapper.
  • the script leaves a bunch of untracked files in the repo checkout, this looks dirty:
git status
On branch dev
Your branch is up to date with 'origin/dev'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	bitcoin/
	client.7z
	config.7z
	docker-compose.yaml
	gatekeeper/
	installer/
	lightning/
	start.sh
	stop.sh
	testfeatures.sh
	traefik/

nothing added to commit but untracked files present (use "git add" to track)
  • instead configuring individual paths to different service data folders, I would ask once for "data" directory and derive all paths from there by default, if user wants to go crazy, they can override those configurations by hand via env variables or tweaking created config.sh, as you will be adding more and more services/containers, this will become tedious...

Improve documentation

English is not my first language, there are better ways to write what's in the doc/ directory. :-)

What is needed:

  • Separate technical from non-technical documentation
  • Complete the technical docs by adding details and forgotten parts
  • Complete the non-technical docs by adding explanations and vulgarizing too technical parts
  • Standardize the docs

Importing and watching an xpub

Purpose: we want to be able to give an xpub to cyphernode so that it can watch it and give notifications when bitcoins are sent to addresses derived from that xpu

Concerns:

  • gap limit: this is designed with merchants in mind. It is possible that merchants generate 20 invoices with 20 addresses that remain unpaid. If this is the case, a wallet with a gap limit of 21 will not detect the payment.
  • overload of Bitcoin Core: we don't want to crash bitcoin core
  • address labelling: we want to have a system that makes it easy to group the keys derived from one xpub together
  • usability: we want to be able to build features which allow people to obtain detailed and useful info on their xpubs

API endpoint:

  • watchhdkey
  • gethdkeyinfo

Parameters:

  • derivation path: custom derivation path overriding default
  • rescan: default set to true, this the is a parameter of importmulti rescan

watchhdkey

The client sends:

  • xpub, ypub, zpub
  • label
  • derivation path
    Cyphernode
  • save that xpub somewhere with the label and the path. No label by default. This will will allow apps to query information about xpubs by labels, so they dont have to manage the xpub-label database on their side.
  • RPC call to Bitcoin Core createwallet with the label set as the the xpub by default and disable_private_keys set to true
  • Call to pycoin to derive 100 addresses : https://github.com/SatoshiPortal/cyphernode/blob/dev/pycoin_docker/script/pycoin.sh
  • Bitcoin Core imports the 100 addresses using importmulti RPC call https://bitcoincore.org/en/doc/0.17.0/rpc/wallet/importmulti/
  • The label of each address is set as the xpub
  • Cyphernode puts a watch on all the 100 addresses

Event: when cyphernode receives bitcoins at one of the addresses

  • we add to the callback response: wallet name (xpub), derivation, label
  • we check to see how many addresses there are left after this one in the derivation path. There should be always 100. So if for example there was a gap of 6, then there should be 93 ahdead and we should derive 7 more and import them into Bitcoin Core. So we are always deriving and adding new addresses as we see bitcoins coming in.

gethdkeyinfo

  • Calls Bitcoin RPC scantxoutset for given derivation path (key info)
    Returns:
    key info:

Result: { "unspents": [ { "txid" : "transactionid", (string) The transaction id "vout": n, (numeric) the vout value "scriptPubKey" : "script", (string) the script key "amount" : x.xxx, (numeric) The total amount in BTC of the unspent output "height" : n, (numeric) Height of the unspent transaction output } ,...], "total_amount" : x.xxx, (numeric) The total amount of all found unspent outputs in BTC ]

  • Get HDKEYINFO since import (all transactions that were processed by cyphernode)
  • Call Bitcoin RPC `listtransactions
  • parse transactions for those whose label matches the `xpub
Result:
[
  {
    "address":"address",    (string) The bitcoin address of the transaction.
    "category":"send|receive", (string) The transaction category.
    "amount": x.xxx,          (numeric) The amount in BTC. This is negative for the 'send' category, and is positive
                                        for the 'receive' category,
    **"label"**: "label",       (string) A comment for the address/transaction, if any
    "vout": n,                (numeric) the vout value
    "fee": x.xxx,             (numeric) The amount of the fee in BTC. This is negative and only available for the 
                                         'send' category of transactions.
    "confirmations": n,       (numeric) The number of confirmations for the transaction. Negative confirmations indicate the
                                         transaction conflicts with the block chain
    "trusted": xxx,           (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.
    "blockhash": "hashvalue", (string) The block hash containing the transaction.
    "blockindex": n,          (numeric) The index of the transaction in the block that includes it.
    "blocktime": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).
    "txid": "transactionid", (string) The transaction id.
    "time": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).
    "timereceived": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT).
    "comment": "...",       (string) If a comment is associated with the transaction.
    "bip125-replaceable": "yes|no|unknown",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);
                                                     may be unknown for unconfirmed transactions not in the mempool
    "abandoned": xxx          (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the 
                                         'send' category of transactions.
  }
]
`

Trying to add getmempoolinfo Bitcoin RPC to cyphernode

Hello @Kexkey !

I tryed to add getmempoolinfo endpoint that call to getmempoolinfo Bitcoin RPC to learn how new endpoints could be added to cyphernode.

This is what I did for that:

  1. Inside api_auth_docker/api-sample.properties add this line : action_getmempoolinfo=stats after action_installation_info=stats.

  2. Inside proxy_docker/app/script/requesthandler.sh:

getmempoolinfo)
  # curl GET http://192.168.111.152:8080/getmempoolinfo
  response=$(get_mempool_info "${line}")
  response_to_client "${response}" ${?}
  break
  ;;

before derivepubpath case.

  1. Inside proxy_docker/app/script/blockchainrpc.sh:
{
  trace "Entering get_mempool_info()..."

  local data='{"method":"getmempoolinfo"}'
  send_to_watcher_node "${data}" | jq ".result"
  return $?
}

at the end of the file.

Calling to the proxy like this: echo "GET /getmempoolinfo" | docker run --rm -i --network=cyphernodenet alpine nc proxy:8888 -, I getresponse but through the gatekeeper/API (d="003";h64=$(echo -n "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" | base64);p64=$(echo -n "{\"id\":\"$id\",\"exp\":$((`date +"%s"`+10))}" | base64);k="TOKEN";s=$(echo -n "$h64.$p64" | openssl dgst -hmac "$k" -sha256 -r | cut -sd ' ' -f1);token="$h64.$p64.$s";curl -v -H "Authorization: Bearer $token" -k https://127.0.0.1:2009/v0/getmempoolinfo no, give me nginx 403 Forbidden error.

I try adding action_getmempoolinfo=stats after action_installation_info=stats inside dist/gatekeeper/api.properties but the call through the gatekeeper/API still response with permission deny.

¿Any ideas of what I'm missing? I think the problem is inside gatekeeper/API and the permissions defined for him.

Thanks! :-D

Bad Request on first install

after fresh install using step by step guide I get a bad request when running this command.
echo "GET /getbalance" | docker run --rm -i --network=cyphernodenet alpine nc cyphernode:8888 -
Respone:HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 0
I have everything running on one linux machine like the step by step suggests.
Thanks for your help.
Jacob Davis

Call bitcoin-cli inside Bitcoin container

Hello @Kexkey !

I'm another time over here with another question :-D

This time I want to implement a new API endpoint that call to getmempoolinfo Bitcoin RPC.

I start trying to make this call inside bitcoin docker where bitcoin-cli is installed with this command:
bitcoin-cli -rpcuser=rpc_username -rpcpassword=rpc_password --testnet getmempoolinfo

I dont change default Bitcoin RPC username and password [0] but I get:

error: Authorization failed: Incorrect rpcuser or rpcpassword

¿Where is bitcoin.conf file located inside Bitcoin docker container?

Thanks! :-D

[0] https://github.com/SatoshiPortal/cyphernode/blob/dev/proxy_docker/env.properties#L4

port 443 already in use

ERROR: for gatekeeper Cannot start service gatekeeper: driver failed programming external connectivity on endpoint dist_gatekeeper_1 (...): Error starting userland proxy: listen tcp 0.0.0.0:443: bind: address already in use

What if there's already a nginx server running? How to use cyphernode along with nginx?

Expose default wallet via an API call

It would be useful to have an API call which returned the default wallet this would allow third parties who are using this/building on top of cyphernode to interface with the full node via RPC (or whatever their preference was). It has lately become essential for anyone using the NPM version of Bitcoin core as it requires a wallet to be defined since 0.17 and the depreciation of accounts.

I know it can be found by checking bitcoin.conf but it would be better if 3rd party developers did not even have to look here.

Example set up here

client = new Client({
host: "127.0.0.1",
port: 18332,
username: process.env.RPCUSERNAME,
password: process.env.RPCPASSWORD
});

dist_lightning_1 cannot start because bitcoin.conf is a folder [macOS host]

Just tried to generate and run my first cyphernode on macOS host from aea6b98 using the wizard.

I have enabled support for lighting and selected docker-compose mode. Generation went ok. When I started it via ./start.sh the docker container dist_lightning_1 had trouble to start with

ERROR: for lightning  Cannot start service lightning: OCI runtime create failed: container_linux.go:344: starting container process caused "process_linux.go:424: container init caused \"rootfs_linux.go:58: mounting \\\"/Users/darwin/.cyphernode/lightning/bitcoin.conf\\\" to rootfs \\\"/var/lib/docker/overlay2/6d60d2d7a9daa316635de1fbdd467c80865c842d8ec01eece38a6c1974dcbc7f/merged\\\" at \\\"/var/lib/docker/overlay2/6d60d2d7a9daa316635de1fbdd467c80865c842d8ec01eece38a6c1974dcbc7f/merged/.bitcoin/bitcoin.conf\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

The problem is that something created /Users/darwin/.cyphernode/lightning/bitcoin.conf/ as a directory prior dist_lightning_1. And when dist_lightning_1 wanted to start it wanted to map the config file via:

    volumes:
      ...
      - "/Users/darwin/.cyphernode/lightning/bitcoin.conf:/.bitcoin/bitcoin.conf"

I'm not able to trouble shoot it right now. But something clearly gets confused creates a directory instead empty file or there are some extra trailing slashes with cp / rsync.


Host machine:

> sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.4
BuildVersion:	18E226

> docker --version
Docker version 18.09.2, build 6247962

> docker-compose --version
docker-compose version 1.23.2, build 1110ad01

Add Blockstream Privacy Analysis Script

We should add this:

  • when we get a response from a txid callback (get transaction, and other notifications)
  • as a standalone api endpoint (privacy) whose object is a txid

New function: Watch balance function and callback

We should have a callback that notifies via API once a certain thresholds on a bitcoin balance are set.

Things to think about:

  • how do we determine what a "balance" is? We need for users to be able to create some kind of labeling system (e.g. this XPUB is a balance, or a balance is this collection of addresses, etc.)
  • have a minimum and maximum threshold

Launch scripts

Working on a launch script to deploy cyphernode on a VM without too many distinct operations.

Add Blockstream Fee Analysis Script

Like issue #75 we should add this when we get a response from a txid we're watching, or coins coming in or out.

The idea is to have the fee analysis included as a field in the "unconfirmed-tx" and "confirmed-tx" callback responses and also a standalone API endpoint

Why not do it agnostic to underlying hardware?

It seems this repo and also SatoshiPortal/dockers are heavily reliant on Raspberry Pi.

This is awesome but for those like me willing to experiment a full Bitcoin and Lightning network it becomes an entry barrier, since I don't have a Raspberry yet.

Do you guys see value in changing it to be agnostic?

Add OTS client and endpoints

We already have the python Open-Timestamps client dockerized, but I think it may actually be better to use the Javascript OTS client for this because AFAIK it already has everything we need to timestamp a hash directly without receiving a file that is hashed by the client.

This should be faily simple, we just need to implement the 4 functions:

  • Stamp
  • Upgrade
  • Verify
  • Info

Note: I don't think we need to add OTS calendars in Cyphernode. Having 3 calendars is enough, and too many calendars would create redundant spam.

This is a great ressource for this:

Lightning Network "PAY" Sanity Check

Problem: when sending bitcoins to users with LN on the Bylls and Bull Bitcoin apps, we must ensure that the end-user is able to sucessfully generate a Bolt11 invoice that is compatible the payment we want to perform. Unlike LN-enable merchants, in this case the recipient does not decide what kind of Bolt 11 invoice he creates. We decide it in advance.

  1. User will create a "payout-request" to cyphernode with the following expected fields:
  • msatoshi
  1. User will send a "bolt 11" string to cyphernode
  2. Cyphernode will call the "decode" function.
  3. Cyphernode will compare the expected msatoshi and check that currency is Bitcoin.
  4. If expected amount is the same and Bitcoin is currency, pay.
  5. If not, return "bad invoice" with error.

Be multilingual/language agnostic

Cyphernode errors should never be "plain english". It should use codes.

The Cyphernode client is going to decide how it will use/display the results to its users depending on the context. For example, it could be in english, in french, graphically or with different colors. An english response is more complex to parse than a code.

In certain cases, the error comes from another client (ie Bitcoin Core). In theses cases, the actual error message should be sent to the client in a plain text message field with an associated error code.

Example: field error in ots_stamp response should be 1, 2 or 3. If an error message comes from the otsclient subsystem, it should be put in the message field with error code 3.

On the client side, we could have a resource file like this:

en.ots_stamp.1=Duplicate stamping request, hash already exists in DB and been OTS requested
en.ots_stamp.2=Stamp request could not be inserted in DB, please retry later
en.ots_stamp.3=See "message" field
fr.ots_stamp.1=Requête de stamp existante, ce hash existe déjà dans la BD et a été demandée à OTS
fr.ots_stamp.2=La requête de stamp n'a pu être persistée dans la BD, svp réessayer ultérieurement
fr.ots_stamp.3=Voir le champ "message"

Please add requirements and recommended resources needed for installation

It would be useful to know what the current hardware requirements are for an ideal vs. minimal setup to the README:

  • Host: Self-hosted VM OK ? Bare-metal (Pi) ? Cloud-hosted VM OK ?
  • Operating system (Debian GNU/Linux), CPU, memory, storage (size, including projected needs)
  • Networking (including bandwidth requirements)
  • Any domain names / SSL certificates if applicable

Add PGP library docker, scripts and endpoint

We don't have a dockerized PGP library so this needs to be added to https://github.com/SatoshiPortal/dockers

The PGP keypairs would be added in the configs of the Proxy. Possibly a good idea to put an additional password on modifying the keypairs since we want this to be resistant to an attacker take control of the app which would call the Cyphernode via API (don't want the attacker to be able to change the PGP key). and this is not a burdgen because you wouldn't be doing this too often anyway.

I think we should use https://github.com/openpgpjs/openpgpjs because it is so widely used and maintained, but other libraries can be used if they are good.

I think cleartext signing and verification + encrypt\decrypt string would be what we need.

TODO:

  • Dockerize OPENPGP.JS

  • Add PGP keypairs to proxy configs.

  • Add "clearsign" endpoint that dispatches data to pgp docker to create a cleartext signature.

  • Add "detachedsign" endpoint that dispatches data to pgp docker to create a detached signature.

  • Add "verify" endpoint for both detached and clearsign

https://github.com/openpgpjs/openpgpjs/blob/1bee091f2acd054b9cd78c6eca5c139061761662/src/cleartext.js

  • In verified response, give smart info: fingerprint, errors

  • Add "encrypt" and "decrypt" endpoint that dispatches data to pgp docker to create a encrypted file or string

  • Add "encrypt" and "decrypt" endpoint that dispatches data to pgp docker to create a encrypted file or string

BONUS

(privacy concerns)

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.