-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #132 from simelo/olemis_t130_wallet_devdocs
[guides] refs #130 - Describe wallet contracts
- Loading branch information
Showing
7 changed files
with
1,125 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
+++ | ||
title = "FiberCrypto Wallets Guide v2" | ||
weight = 4 | ||
+++ | ||
|
||
### Introduction | ||
|
||
Wallets create public keys to receive coins and use the corresponding private keys to spend them. Wallet files are specific to altcoin plugin implementations. They store private keys and (optionally) other information related to transactions for a given wallet in particular. | ||
|
||
Wallet contracts are addressed below in separate subsections whereas supported wallet files are documented in individual altcoin plugin implementations. This document attempts to always make it clear whether we are talking about wallet contracts or wallet files. | ||
|
||
### Wallet Contracts | ||
|
||
Permitting receiving and spending of coins is the only essential feature of all wallet contracts. Nonetheless a particular wallet imstance does not need to do both things. Two wallet objects can work together, one distributing public keys in order to receive coins and another one signing transactions spending those coins. | ||
|
||
Wallet also need to interact with the peer-to-peer network to get information from the block chain and to broadcast new transactions. However, the objects which distribute public keys or sign transactions don’t need to interact with the peer-to-peer network themselves. Moreover it is possible for a wallet to have access to a local copy of the block chain, thus enabling offline operations. | ||
|
||
This leaves us with four necessary, but separable, parts of a wallet system: a public key distribution subsystem, a set of signing strategies, a blockchain aware visor, and a networked component. In the subsections below, we will describe specific contracts and possible relations between them. | ||
|
||
In most cases, wallet contracts are obliged to implement generic operations like setting and reading a human readable label. All wallets shall have an identifier. The wallet instance should facilitate a way to calculate balances of the addresses it owns or manages. `Wallet` interface defines this generic contract. | ||
|
||
To help protect against theft, the system offers users the option of encrypting the wallet files which contain the private keys. In order to provide support for multiple encryption strategies, this feature is betond wallet contract. | ||
|
||
Note: We speak about distributing public keys generically. In many cases, hashes will be distributed instead of public keys, with the actual public keys only being distributed when the outputs they control are spent. | ||
|
||
#### Peer-to-peer exchange | ||
|
||
Every altcoin plugin must provide a way to broadcast transactions for further confirmation by peers across the network. Abstract types are used to identify peers either by name or by network routing address identifier. This is a top-level plugin entry point that could usually be implemented by a singleton instance. Since this is a global service not bound to any particular address, generic wallet operartions are not part of this contract. | ||
|
||
#### Full-Service Wallets | ||
|
||
This kind of wallets perform three of the four main functions: it generates private keys, derives the corresponding public keys, helps distribute those public keys as necessary, monitors for outputs spent to those public keys, creates and signs transactions spending those outputs. It does not broadcast the signed transactions though. Full-service wallets shall implement `FullWallet` interface contract. | ||
|
||
The main advantage of full-service wallets is that they are easy to implement. A single instance does everything the user needs to receive and spend coins. | ||
|
||
The main disadvantage of full-service wallets is that they store the private keys on a device connected to the Internet. The compromise of such devices is a common occurrence, and an Internet connection makes it easy to transmit private keys from a compromised device to an attacker. Encryption is not enough since that approach protects the private keys when they aren’t being used, but it cannot protect against an attack designed to capture the encryption key or to read the decrypted keys from memory. | ||
|
||
#### Signing-Only Wallets | ||
|
||
To increase security, private keys can be generated and stored by a separate wallet strategy operating in a more secure environment. These signing-only wallets work in conjunction with the PEX subsystem which interacts with the peer-to-peer network. `TxnSigner` establishes the contract these wallets shall satisfy. | ||
|
||
Signing-only wallets programs typically use deterministic key creation (described in a later subsection) to create parent private and public keys which can create child private and public keys. At first, the signing-only wallet creates a parent private key and transfers the corresponding parent public key to the networked wallet. The later does the rest. Often, users are given a chance to review the unsigned transactions’ details (particularly the output details) using the signing-only wallet. After the optional review step, the signing-only wallet uses the parent private key to derive the appropriate child private keys and signs the transactions, giving the signed transactions back to the PEX for subsequent broadcast. | ||
|
||
##### Hardware Wallets | ||
|
||
Hardware wallets are devices dedicated to running a signing-only wallet. Their dedication lets them eliminate many of the vulnerabilities present in operating systems designed for general use, allowing them to safely communicate directly with other devices so users don’t need to transfer data manually. | ||
|
||
The user’s workflow is defined by `HardwareWallet` contract and looks something like: | ||
|
||
1. (Hardware) Create parent private and public keys. Connect hardware wallet to a networked device so it can get the parent public key. | ||
2. (Networked) As you would with a full-service wallet, distribute public keys to receive payment. When ready to spend coins, fill in the transaction details, connect the hardware wallet, and start spending workflow. The networked wallet will automatically send the transaction details to the hardware wallet. | ||
3. (Hardware) Review the transaction details on the hardware wallet’s screen. Some hardware wallets may prompt for a passphrase or PIN number. The hardware wallet signs the transaction and uploads it to the networked wallet. | ||
4. (Networked) The networked wallet receives the signed transaction from the hardware wallet and broadcasts it to the network. | ||
|
||
The primary advantage of hardware wallets is their possibility for greatly improved security over full-service wallets with much less hassle than offline wallets. | ||
|
||
The primary disadvantage of hardware wallets is their hassle. Even though the hassle is less than that of offline wallets, the user must still purchase a hardware wallet device and carry it with them whenever they need to make a transaction using the signing-only wallet. | ||
|
||
#### Distributing-Only Wallets | ||
|
||
Wallet programs which run in difficult-to-secure environments, such as webservers, can be designed to distribute public keys and nothing more. `DistWallet` contract standardizes operations needed in this case. | ||
|
||
There are two common ways to design these minimalist wallets: | ||
|
||
Distributing-Only Wallets | ||
|
||
- `CollectionWallet` contract encloses the instances that pre-populate a database with a number of public keys or addresses, and then distribute on request a pubkey script or address using one of the database entries. To avoid key reuse, webservers should keep track of used keys and never run out of public keys. This can be made easier by using parent public keys as suggested in the next method. | ||
|
||
- `HDAddressGenerator` contract standardizes wallets which use a parent public key to create child public keys. To avoid key reuse, a method must be used to ensure the same public key isn’t distributed twice. This can be a database entry for each key distributed or an incrementing pointer to the key index number. | ||
|
||
Neither method adds a significant amount of overhead, especially if a database is used anyway to associate each incoming payment with a separate public key for payment tracking. | ||
|
||
#### Transactions and blockchain operations | ||
|
||
MAny operations essential to crypto systems rely on transactions. It is necessary to have wallets able to scan the block chain to identify unspent outputs, and use such information to assemble unsigned transactions, calculate account balance, and observe incoming and outcoming transactions, among other things. Such wallets may be bound to one , a set, or an infinite sequence of addresses. They can even be instantiated for the blockchain as a whole. All instances must comply to the `BlockchainTransactionAPI` contract. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
@startuml | ||
|
||
participant "FiberCrypto Bitcoin SPV" as wallet | ||
participant "Bitcoin node" as btcnode | ||
wallet -> btcnode : filterload(nFlags=BLOOM_UPDATE_ALL, ...) | ||
wallet -> btcnode : get(inventory_type=MSG_MERKLEBLOCK, ...) | ||
wallet <-- btcnode : merkleblock(TXID1, TXID2, ...) | ||
wallet -> wallet : validate_merkleblock | ||
|
||
@enduml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
|
||
@startuml | ||
skinparam ClassBorderColor<< CryptoCurrencyToken >> Black | ||
skinparam ClassBackgroundColor<< CryptoCurrencyToken >> White | ||
|
||
|
||
interface CryptoAccount | ||
interface Address | ||
interface Iterator<T> | ||
interface AddressIterator | ||
interface TxnSigner | ||
interface TxnSignerIterator | ||
class Timestamp <<uint64>> | ||
enum TransactionStatus | ||
interface Transaction | ||
interface TransactionIterator | ||
interface TransactionInput | ||
interface TransactionInputIterator | ||
interface TransactionOutput | ||
interface TransactionOutputIterator | ||
interface Block | ||
interface AltcoinPlugin | ||
interface AltcoinManager | ||
enum CoinValueMetric | ||
interface BlockchainStatus | ||
interface PEX | ||
interface PexNodeIterator | ||
interface PexNodeSet | ||
interface PexNode | ||
interface KeyValueStorage | ||
interface WalletSet | ||
interface WalletStorage | ||
interface WalletIterator | ||
enum AddressType | ||
interface Wallet | ||
interface SeedGenerator | ||
interface WalletEnv | ||
|
||
TxnSignerIterator --|> Iterator : bind <ItemType=TxnSigner> | ||
AddressIterator --|> Iterator : bind <ItemType=Address> | ||
TransactionInputIterator --|> Iterator : bind <ItemType=TransactionInput> | ||
TransactionOutputIterator --|> Iterator : bind <ItemType=TransactionOutput> | ||
TransactionIterator --|> Iterator : bind <ItemType=Transaction> | ||
PexNodeIterator --|> Iterator : bind <ItemType=PexNode> | ||
WalletIterator --|> Iterator : bind <ItemType=Wallet> | ||
|
||
class AltcoinMetadata { | ||
Name string | ||
Ticker string | ||
Family string | ||
HasBip44 bool | ||
Bip44CoinType int32 | ||
Accuracy int32 | ||
} | ||
|
||
CryptoAccount : GetBalance(ticker string) (uint64, error) | ||
CryptoAccount : ListAssets() []string | ||
CryptoAccount : ScanUnspentOutputs() TransactionOutputIterator | ||
CryptoAccount : ListTransactions() TransactionIterator | ||
CryptoAccount : ListPendingTransactions() (TransactionIterator, error) | ||
|
||
CryptoAccount --> TransactionOutputIterator | ||
CryptoAccount --> TransactionIterator | ||
|
||
Address --> CryptoAccount | ||
|
||
TxnSigner --> Transaction : sign | ||
TxnSigner ..> PasswordReader | ||
|
||
Iterator : Value() ItemType | ||
Iterator : Next() bool | ||
Iterator : HasNext() bool | ||
Iterator : Count() int | ||
|
||
Transaction : SupportedAssets() []string | ||
Transaction : GetTimestamp() Timestamp | ||
Transaction : GetStatus() TransactionStatus | ||
Transaction : GetInputs() []TransactionInput | ||
Transaction : GetOutputs() []TransactionOutput | ||
Transaction : GetId() string | ||
Transaction : ComputeFee(ticker string) (uint64, error) | ||
Transaction : VerifyUnsigned() error | ||
Transaction : VerifySigned() error | ||
Transaction : IsFullySigned() (bool, error) | ||
|
||
Transaction --> Timestamp | ||
Transaction --> TransactionStatus | ||
Transaction "1" *--> "*" TransactionInput | ||
Transaction "1" *--> "*" TransactionOutput | ||
|
||
TransactionInput --> TransactionOutput : spend | ||
|
||
TransactionOutput "*" --> "1" Address : fund | ||
|
||
Block "*" *--> Transaction | ||
Block --> Timestamp | ||
Block --> TransactionIterator | ||
|
||
AltcoinPlugin : ListSupportedAltcoins() []AltcoinMetadata | ||
AltcoinPlugin : ListSupportedFamilies() []string | ||
AltcoinPlugin : RegisterTo(manager AltcoinManager) | ||
AltcoinPlugin : GetName() string | ||
AltcoinPlugin : GetDescription() string | ||
AltcoinPlugin : LoadWalletEnvs() []WalletEnv | ||
AltcoinPlugin : LoadPEX(netType string) (PEX, error) | ||
|
||
class CryptoCurrencyToken | ||
|
||
AltcoinPlugin "1" -- "*" CryptoCurrencyToken : implements | ||
AltcoinManager "registry" <-- "plugin" AltcoinPlugin : registration | ||
AltcoinPlugin "1" --> "*" WalletEnv | ||
AltcoinPlugin --> PEX | ||
|
||
(AltcoinPlugin, CryptoCurrencyToken) .. AltcoinMetadata | ||
|
||
AltcoinManager : RegisterPlugin(p AltcoinPlugin) | ||
AltcoinManager : RegisterAltcoin(info AltcoinMetadata, plugin AltcoinPlugin) | ||
AltcoinManager : ListRegisteredPlugins() []AltcoinPlugin | ||
AltcoinManager : LookupAltcoinPlugin(ticker string) (AltcoinPlugin, bool) | ||
AltcoinManager : DescribeAltcoin(ticker string) (AltcoinMetadata, bool) | ||
|
||
AltcoinManager "1" o--> "*" AltcoinPlugin | ||
AltcoinManager "cache" --> "record" AltcoinMetadata | ||
|
||
BlockchainStatus --> Block | ||
BlockchainStatus ..> CoinValueMetric | ||
|
||
PEX --> TransactionIterator | ||
PEX --> PexNodeSet | ||
PEX ..> Transaction : P2P broadcast | ||
|
||
PexNodeSet --> PexNodeIterator | ||
PexNodeSet "*" o--> "*" PexNode | ||
|
||
WalletSet --> WalletIterator | ||
WalletSet o--> Wallet | ||
WalletSet ..> PasswordReader | ||
|
||
WalletStorage : Encrypt(walletName string, password PasswordReader) | ||
WalletStorage : Decrypt(walletName string, password PasswordReader) | ||
WalletStorage : IsEncrypted(walletName string) (bool, error) | ||
|
||
WalletStorage ..> PasswordReader | ||
|
||
Wallet : GetId() string | ||
Wallet : GetLabel() string | ||
Wallet : SetLabel(wltName string) | ||
Wallet : Transfer(to TransactionOutput, options KeyValueStorage) (Transaction, error) | ||
Wallet : SendFromAddress(from []Address, to []TransactionOutput, change Address, options KeyValueStorage) (Transaction, error) | ||
Wallet : Spend(unspent, new []TransactionOutput, change Address, options KeyValueStorage) (Transaction, error) | ||
Wallet : GenAddresses(addrType AddressType, startIndex, count uint32, pwd PasswordReader) AddressIterator | ||
Wallet : GetCryptoAccount() CryptoAccount | ||
Wallet : GetLoadedAddresses() (AddressIterator, error) | ||
Wallet : Sign(txn Transaction, source UID, pwd PasswordReader, index []string) (Transaction, error) | ||
Wallet : AttachSignService(TxnSigner) error | ||
Wallet : RemoveSignService(TxnSigner) error | ||
Wallet : EnumerateSignServices() TxnSignerIterator | ||
|
||
Wallet ..> PasswordReader | ||
Wallet ..> KeyValueStorage | ||
Wallet ..> TransactionOutput | ||
Wallet --> Transaction : create | ||
Wallet --> Transaction : sign | ||
Wallet "1" ..> "*" TxnSigner | ||
Wallet ..> Address | ||
Wallet ..> AddressType | ||
Wallet --> AddressIterator | ||
Wallet --> TxnSignerIterator | ||
|
||
Wallet ..> SeedGenerator | ||
|
||
WalletEnv : GetStorage() WalletStorage | ||
WalletEnv : GetWalletSet() WalletSet | ||
|
||
WalletEnv "1" o--> "1" WalletStorage | ||
WalletEnv "1" o--> "1" WalletSet | ||
|
||
@enduml | ||
|
Oops, something went wrong.