Skip to content

Commit

Permalink
Merge pull request #132 from simelo/olemis_t130_wallet_devdocs
Browse files Browse the repository at this point in the history
[guides] refs #130 - Describe wallet contracts
  • Loading branch information
olemis authored Dec 9, 2019
2 parents 17d5164 + 2bd5984 commit 26334f6
Show file tree
Hide file tree
Showing 7 changed files with 1,125 additions and 0 deletions.
76 changes: 76 additions & 0 deletions content/dev-docs/guides/v2.wallet.md
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.

10 changes: 10 additions & 0 deletions content/diagrams/plantuml/bitcoin.spv.bloom.uml
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
179 changes: 179 additions & 0 deletions content/diagrams/plantuml/core.v1.simple.uml
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

Loading

0 comments on commit 26334f6

Please sign in to comment.