11th Feb 2022
Status: DRAFT
Synopsis
This document specifies a light-mode for cardano-wallet
. This mode aims to make synchronisation to the blockchain faster by trusting an off-chain source of aggregated blockchain data.
Light wallets often employ this strategy of using a less trusted data source; for example the Nami wallet uses Blockfrost as data source. The purpose of the light-mode of cardano-wallet
is to make this “trust vs speed” trade-off readily available to downstream software such as Daedalus with minimal changes to its downstream API.
In addition, the “trust versus speed” trade-off will be partially obsoleted by Mithril technology, which aims to give us “trust and speed” by providing verified ledger state data as opposed to block data. The act of implementing light-mode in cardano-wallet
does not only offer immediate benefits, but will, in fact, partially prepare the codebase for Mithril technology.
Motivation
Background
As the Cardano blockchain grows in size, retrieving and verifying blocks from the consensus network becomes increasingly time consuming. By making a “trust versus speed” trade-off, we can significantly decrease synchronization times.
User-visible benefits
- Allow users to operate their wallet without needing to wait for the node to download and validate the entire blockchain.
- Allow users to run cardano-wallet and Daedalus on systems with significantly less than 8GB of memory and less than 10GB of disk space.
- Allow users to control where they sit on the trust vs convenience spectrum, depending upon their current circumstances.
Technical benefits
- Speed. With light-mode, we expect synchronisation times of < 1 minute for a wallet with 1’000 transactions. In contrast, synchronisation of an empty wallet currently takes ~ 50 minutes by connecting to a node — assuming that the node has already synced to the chain tip and built its ledger state, which itself takes hours.
- Compatibility. Light-mode is intended to preserve the API presented to downstream software such as Daedalus, only minimal changes are expected.
- Optionality. A wallet that was started in light-mode can be restarted in full mode without resynchronization, and vice versa. (MVP: no support yet for changing the mode dynamically while the wallet is running.)
Limitations
- Trust. The external data source does not provide the same level of protection against omission of transactions as the Proof-of-Stake consensus protocol.
- Privacy. In addition to the reduction of trust in the blockchain data, we now also reveal private information about addresses belonging to a single wallet.
- Address schemes. Only Shelley wallets with sequential address discovery can be supported.
However, these limitations are shared by all existing light wallets. In fact, some light wallets only provide single-address wallets, which is an additional reduction of privacy.
Specification
Overview
The implementation of light-mode is based on an efficient query Address -> Transactions
which the blockchain data source provides. This query is useful to wallets that use sequential address discovery (Shelley wallets). These wallets work with a sequence of potential addresses addr_0
, addr_1
, addr_2
, …. For each integer n
, there is a deterministic procedure for generating the corresponding address addr_n
. The wallet generates the first few addresses in this sequence and uses the above query to retrieve the corresponding transactions. When no transactions are found for g
(“address gap”) many consecutive addresses, the procedure stops — as the wallet never puts addresses with higher indices on the chain. In other words, this iterative loop yields all transactions that belong to the wallet.
This procedure can be visualized in a flow chart:
flowchart TB
start([begin]) --> init[j := 0\ng := 0\ngap := 20]
init --> query[query addr_j]
query --> tx{transactions?}
tx -- no --> gapAdd[g := g+1]
gapAdd --> g{g > gap?}
tx -- yes --> gapReset[g := 0]
gapReset --> add[j := j+1]
g -- yes ----> e([end])
g -- no --> add
add --> query
This procedure is implemented and demonstrated in the light-mode-test
prototype.
Functionality
Network topology
In full-node mode, cardano-wallet
connects to a local cardano-node
:
flowchart TB
subgraph local system
cardano-launcher -. spawns .-> cardano-wallet
cardano-launcher -. spawns .-> cardano-node
cardano-wallet -- ChainSync --> cardano-node
cardano-wallet -- LocalTxSubmission --> cardano-node
cardano-wallet -- LocalStateQuery --> cardano-node
end
cardano-node -- syncs --> blockchain
subgraph internet
blockchain
end
In light-mode, cardano-wallet
instead connects to the data source (e.g. cardano-graphql
or Blockfrost) and a transaction submission service through the internet
flowchart TB
cardano-launcher -. spawns .-> cardano-wallet
cardano-wallet -- query\nAddressTransactions --> cardano-graphql
cardano-wallet -- TxSubmission --> cardano-submit-api
subgraph local system
cardano-launcher
cardano-wallet
end
subgraph internet
cardano-graphql --> n1[cardano-node]
cardano-submit-api --> n2[cardano-node]
n1 -- syncs --> blockchain
n2 -- syncs --> blockchain
end
Command line
The cardano-wallet
executable will feature a new flag --light
which indicates that the executable is to be started in light-mode:
$ cardano-wallet serve --light CRED
-
CRED
specifies how to connect to the less trusted blockchain data source. (MVP: Use Blockfrost;CRED
is a filepath to the secret token.) -
The
--light
argument and the--node-socket
arguments are mutually exclusive with each other.
REST API
When the executable was started in light-mode:
-
The endpoints in the hierarchy
/v2/byron-wallets/*
MUST return an error. Because byron wallets use random derivation indices to generate addresses, they are significantly more challenging to make a light wallet for. -
(MVP: The endpoints in the hierarchy
/v2/shared-wallets/*
MAY return an error.) -
The
GET /v2/network/information
endpoint MAY not returnsync_progress
as a percentage quantity from [0..100].
Internal
See also the light-mode-test
prototype!
-
Collect required queries on data source in a data type
LightLayer
. In this way, we can replace the data source with a mock data source and run property tests on the chain following logic. (MVP: Use Blockfrost for demonstration purposes.) -
Provide second implementation of
NetworkLayer
using aLightLayer
.- See prototype for details! Important changes:
-
watchTip
requires polling (2 seconds interval) -
currentNodeEra
may require hard-coding known eras. -
performanceEstimate
requires copying from ledger code. -
syncProgress
should be ignored for MVP. -
The node-mode
NetworkLayer
does a lot of caching, we should avoid that for now and instead add a more uniform caching system later through a functionaddCaches :: NetworkLayer -> IO NetworkLayer
. -
postTx
submits a transaction to a web service instead of using theLocalTxSubmission
protocol with cardano-node. This web service can be different from the blockchain data source. An example of such a service iscardano-submit-api
.
-
New data type
data BlockSummary m = BlockSummary { from :: ChainPoint , to :: ChainPoint , query :: Address -> m [Transaction] }
-
consumed by
applyBlocks
. AdaptdiscoverTransactions
from the prototype. -
produced by
NetworkLayer
. AdaptlightSync
from the prototype. -
Idea: Use an additional GADT wrapper to specialize
applyBlocks
to sequential address states:data BlockData m s where List :: NonEmpty Block -> BlockData m s Summary :: BlockSummary m -> BlockData m (SeqState n k)
By using this type as argument to
applyBlocks
, we are guaranteed thatBlockSummary
is only used in conjunction with sequential state. Caveat: It would be better if we could avoid parametrizing theNetworkLayer
type with the address discovery states
.
-
Quality assurance
Benchmarks
- Compare restoration times for an empty wallet in node-mode and in light-mode. The existing nightly wallet restoration benchmark can be updated for this purpose.
- Number of requests that we make to the data source needs to be monitored / kept in check. The number of requests should scale linearly with the number of transactions and the number of addresses belonging to the wallet. If the data source supports aggregated queries, we can make a single request with a larger body.
Testing
-
Mock implementation of
LightLayer
.-
We probably won’t get good value / work out of implementing a
LightLayer
that interacts with the local cluster. One could look into implementing the light-modeNetworkLayer
in terms of the node-modeNetworkLayer
, though.
-
We probably won’t get good value / work out of implementing a
-
Property tests for
applyBlocks
usingBlockSummary
-
Implement a conversion function
summarize :: NonEmpty Block -> BlockSummary Identity
-
Create a list of blocks, apply
applyBlocks
to both the list directly, and to the result ofsummarize
— the results should be equal.
-
Implement a conversion function
External
-
Cardano-launcher will have to be modified to not launch the
cardano-node
process when the cardano-wallet is launched in light-mode. -
Provision of the data source and of the transaction submission service is outside the scope of light-mode; we assume these services will be operated and paid for by someone. (Any light wallet assumes this.) In the MVP, we use Blockfrost for demonstration purposes.
Design alternatives
Byron wallets
Byron wallets cannot be supported by the light-mode as described above, as it is based on an efficient query Address -> Transactions
which Byron wallets cannot take advantage of. For these wallets, alternative designs would have to be explored. Possibilities include:
- A third-party byron address discovery service which takes a byron root XPub and sends back a list of addresses belonging to that wallet. However, that involve an additional reduction in trust.
- Existing Byron wallets can be partially supported in light-mode as long as the database of addresses generated/discovered so far is intact, as we can still retrieve the balance and all transactions. However, in light-mode, these wallets cannot be restored and cannot receive funds from newly generated addresses. Conversion to Shelly wallets is recommended.