-
Notifications
You must be signed in to change notification settings - Fork 12
Wallet Decoupling
Name | GitHub Handle | Focus |
---|---|---|
Johannes Lund | @anviking | 100% |
Matt Parsons | @parsonsmatt | 100% |
Matthias Benkort | @KtorZ | 50% |
Pawel Jakubas | @paweljakubas | 100% |
The node implements the BListener
interface which boils down to two
actions: apply a block and switch to a fork.
Various pieces required by the node were historically not derived from blocks and from
what it receives via the BListener. Most of them are gathered under the NodeStateAdaptor
.
During recovery, the wallet currently peeks into the node's database to resolve the current UTxO, the initial one and the historical data by applying blocks since the genesis one.
The wallet currently receives Blund
s from the BListener
instead of mere Block
s.
However, Undo
s from Blund
s are only used to retrieve some transaction Metadata which
are otherwise available in the UTxO maintained by the wallet.
Being the only communication channel between Daedalus and the node itself, the wallet
is currently used to convey some specific process supervision commands (e.g. apply-update
).
This is currently done via the "Internal" HTTP API.
The wallet needs to submit transactions to the network. Right now, the wallet is hooked up to the node's inner diffusion layer from which it can push new transactions.
There's an existing working node-to-node communication protocol which is used by nodes and the Rust CLI. This protocol enables us (amongst other things) to:
- Submit new transactions to the network
- Receive blocks from the network, from a given hash
? unknown ?
Node-to-Node protocol interface implemented; Rest being worked on, mostly following the implementation of the existing Haskell backend.
We assume the Wallet fully trusts the node it is connected to such that, validation and verification work is done by the node and acknowledged by the Wallet.
We want the Wallet to be able to receive blocks as they get validated by the underlying node. The Wallet is interested in the blocks for several reasons:
-
It maintains its own UTxO via a set of specified ledger rules (see Formal specification for a Cardano Wallet)
-
It tracks a bunch of Protocol Parameters that are specified in the genesis block and may change via updates. For the Wallet, the relevant parameters are:
- slot length
- epoch length (NOTE: in current version, can't change via update, but will in future versions of Ouroboros).
- fee policy
- transaction max size
The parameters are currently not extracted from the block but queried directly via some IO using the fact that Wallet runs as a node. Knowing how to transition from an initial state via applying a block, it would be possible for the Wallet to keep track of these parameters as it applies blocks (see A Simplified Formal Specification of a UTxO Ledger). There's a major question about rollbacks and how to "un-apply" rules.
Ideally, we want the ability for the Wallet to ask for two things:
-
An initial state (derived from the genesis block by the node) where state can be many things (e.g. protocol parameters, system start, stake pools distribution, utxo)
-
The current state (for fast syncing)
Then, a consumer can apply ledger rules they're interested in as they receive blocks, assuming node has validated pre-conditions for applying those rules. Having the initial state and the transitions is all we need to keep state in sync.
The wallet currently offers some basic monitoring of the node via the /api/v1/node-info
and
/api/v1/node-settings
. Underneath, this piggy-backs once more on the Node State Adaptor
and the fact that the Wallet is ultimately a node. This includes:
-
syncProgress
: Syncing progression, in percentage. -
blockchainHeight
: If known, the current blockchain height, in number of blocks. -
localBlockchainHeight
: Local blockchain height, in number of blocks. -
localTimeInformation
: Information about the clock on this node. -
subscriptionStatus
: Is the node connected to the network and to what peers? -
slotDuration
: Duration of a slot. -
softwareInfo
: Various pieces of information about the current software. -
projectVersion
: Current project's version. -
gitRevision
: Git revision of this deployment.
Strictly considering the wallet, these pieces of information are quite out-of-scope. They should instead be provided by a node itself and queried by clients directly from the underlying node. At the moment, the Wallet is used as a kind of proxy to relay these pieces of information, but in order to properly decouple the Wallet from the node, we should look into moving this API onto the node, with a possible redesign as we do it.
In order to avoid breaking the API versioning contract, we will be required to support the Node API in the V1 of cardano-wallet
.
The V2 of the wallet API will not need to support it.
Additionally, the Wallet also may require the systemStart
to be available in
such API in order to compute a few things from it.
Falls into ths category, actions that are triggered by clients to act upon the node:
-
apply-update
: Make the node shutdown with a special exit code (20
) which gets picked up by the launcher.
As for the node monitoring, this is a bit out-of-scope for the Wallet. This responsibility should be moved outside of the Wallet and, during a transition / compatibility period, may still be supported by the Wallet and forwarded to the node.
With the ability to query any block from a node (as described in Receiving Blocks), a Wallet can avoid reads to a node's database. Note that, in order to perform restoration while the Wallet is still processing blocks for existing wallets, we need to be able to listen to blocks on multiple (possibly different) channels.
Historically, the Wallet attaches a timestamp to transations' metadata. This information isn't actually present in the transaction as they're represented in the block and can't really be derived from it. Our best approximation during restoration is to consider the beginning of a slot as the timestamp of a transaction. To retrieve this slot time, we could still leverage the functions defined by the node, and make sure they don't require any access to the database.
Knowing the slot length(s), epoch length(s), current time, current slot and system start should be enough information to recover any slot start.
Being a node, the Wallet "shortcuts" the transaction submission by directly pushing transactions to the node's queue. In order to fully decouple the wallet, we would need the wallet to use the Node <-> Node protocol in order to submit transactions.
Total Estimate: 100 + ? points
-
- We should extract
wallet-new
fromcardano-sl
into its own repositorycardano-wallet
.
- We should extract
-
- We should define a
stack.yaml
file allowing developers to easily build the project locally.
- We should define a
-
- We may restructure the
.cabal
file to accomodate the new structure.
- We may restructure the
-
- We should understand how to setup Travis-CI for cardano-wallet.
-
- We should have 'regular' CI times under an hour.
-
- We should build
cardano-wallet
sources, and run tests in CI.
- We should build
-
- We should run
hlint
in CI.
- We should run
-
- We may run
weeder
in CI.
- We may run
-
- We may integrate the CI with coveralls.io and have coverage reports available
-
- We may display code coverage on the README and monitor it
-
- We should have a complete pipeline setup and ready for development
-
- We may document the CI steps and setup in the Wiki
-
- We may cache builds of stack LTS
-
- We may cache builds of cardano-sl
-
- We may build the Swagger / Redoc API documentation in CI & publish it to gh-pages.
- There must be a Servant API representing the Node Monitoring & Management API
- The type from
B.1.
must be convertible to Swagger - The type from
B.1.
should be defined outside ofcardano-wallet
, oncardano-sl
.
- Handlers corresponding to the API defined in
B.1.
must be implemented - There mustn't be any dependencies from
cardano-sl
->cardano-wallet
introduced in B.4.
- Nodes must host an HTTP(s) server to serve the API defined in B.1.
- The server started in
B.6.
must be as powerful as the current wallet server (i.e. TLS, client cert validation, HTTP/2.0 support). - Nodes' CLI should be extended to support passing options to the server from
B.6.
. - CLI Options should define a
--tlsca
and--tlscert
to pass TLS certificates to the server. - CLI Options may define a
--no-client-auth
to disable client certificate verification. - CLI Options may define a
--no-tls
to completely disable TLS, in which case, certs aren't required.
-
cardano-wallet
backward-compatible node monitoring API should solely rely on a Node's API and relay requests through HTTP(s) to the node - We may define a Haskell client to easily talk to the Node API from
cardano-wallet
-
- We must understand and document relevant bits of the Node-To-Node Protocol.
-
- We must distinguish clearly what is transmitted "over-the-wire" from what is just plain shared Haskell structures.
-
- We must clearly identify and document how transactions are currently submitted to the node
-
- We must identify the remaining steps for the wallet to achieve full decoupling regarding submission.
-
- Bits related to submission of transaction must be abstracted in a protocol-neutral interface.
-
- The interface from
C.5
mustn't expose any protocol related parameters.
- The interface from
-
- It must be possible to emulate the interface from
C.5
using the existing code.
- It must be possible to emulate the interface from
-
- An implementation of
C.7
may be provided as an illustration.
- An implementation of
-
-
C.5
must be implemented using the Node-to-Node protocol.
-
-
- The implementation from
C.9
may include integration tests.
- The implementation from
-
- Areas identified in
C.3
must make use of the interface inC.5
using the implementation fromC.9
.
- Areas identified in
-
- We must understand and document relevant bits of the Node-To-Node Protocol.
-
- We must distinguish clearly what is transmitted "over-the-wire" from what is just plain shared Haskell structures.
-
- Bits related to receiving blocks must be abstracted in a protocol-neutral interface.
-
- The interface from
D.3
mustn't expose any protocol related parameters.
- The interface from
-
- It must be possible to emulate the interface from
D.3
using the existing BListener.
- It must be possible to emulate the interface from
-
- An implementation of
D.5
may be provided as an illustration.
- An implementation of
-
-
D.3
must be implemented using the Node-to-Node protocol.
-
-
- The implementation from
D.7
may include integration tests.
- The implementation from
Replace Current BListener and NodeStateAdaptor Usage And Query Information From The Network (13 points)
-
- Areas identified in
D.1
must make use of the interface inD.3
using the implementation fromD.7
.
- Areas identified in