Split docs into seperate files (#72)

This commit is contained in:
Jamie Holdstock 2020-05-27 15:36:21 +01:00 committed by GitHub
parent d5eb18f557
commit d5c949b9ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 266 additions and 64 deletions

110
README.md
View File

@ -6,82 +6,64 @@
## Overview
User purchases a ticket, doesnt need any special conditions, indistinguishable
from solo ticket. User can then choose to use a VSP on a per-ticket basis. Once
the ticket is mined, and ideally before it has matured, the user sends the
ticket details + fee to a VSP, and the VSP will take the fee and vote in return.
dcrvsp is a from scratch implementation of a Voting Service Provider (VSP) for
the Decred network.
## Advantages
A VSP running dcrvsp can be used to vote on any ticket - tickets do not need to
be purchased with any special conditions such as dedicated outputs for paying
VSP fees. Fees are paid directly to the VSP with an independent on-chain
transaction.
### For Administrators
To use dcrvsp, ticket holders must prove ownership of their ticket with a
cryptographic signature, pay the fee requested by the VSP, and submit a private
key which enables the VSP to vote the ticket. Once this process is complete the
VSP will add the ticket to a pool of always-online voting wallets.
- bbolt db - no database admin required.
- Database is not used outside of dcrvsp server.
- No stakepoold.
- Client accountability.
- No need to use the same wallet seed on each voting wallet.
- Fees can change regularly - previously cached by wallet.
## Features
### For Users
- **API** - Tickets are registered with the VSP using a JSON HTTP API. For more
detail on the API and its usage, read [api.md](./docs/api.md)
- No redeem script to back up.
- No registration required. No email.
- Multiple VSPs on a single ticket.
- Voting preferences per ticket.
- Server accountability.
- No address reuse.
- VSP fees are paid "out of band", rather than being included in the ticket
itself. This makes solo tickets and VSP tickets indistinguishable from
eachother, enabling VSP users to purchase tickets in the same anonymity set
as solo stakers.
- **Web front-end** - A minimal, static, website providing pool stats.
## Design Decisions
- **Two-way accountability** - All dcrvsp requests must be signed with a private
key corresponding to the relevant ticket, and all dcrvsp responses are signed
by with a private key known only by the server. This enables both the client
and the server to prove to outside observers if their counterparty is
misbehaving. For more detail, and examples, read
[two-way-accountability.md](./docs/two-way-accountability.md).
- [gin-gonic](https://github.com/gin-gonic/gin) webserver.
- Success responses use HTTP status 200 and a JSON encoded body.
- Error responses use either HTTP status 500 or 400, and a JSON encoded error
in the body (eg. `{"error":"Description"}')
- [bbolt](https://github.com/etcd-io/bbolt) k/v database.
- Tickets are stored in a single bucket, using ticket hash as the key and a
json encoded representation of the ticket as the value.
- [wsrpc](https://github.com/jrick/wsrpc) for RPC communication between dcrvsp
- **Dynamic fees** - Clients must request a new fee address and amount for every
ticket. When these are given to a client, there is an associated expiry
period. If the fee is not paid in this period, the client must request a new
fee. This enables the VSP admin to change their fee as often as they like.
## Implementation
dcrvsp is built and tested on go 1.13 and 1.14, making use of the following
libraries:
- [gin-gonic/gin](https://github.com/gin-gonic/gin) webserver.
- [etcd-io/bbolt](https://github.com/etcd-io/bbolt) k/v database.
- [jrick/wsrpc](https://github.com/jrick/wsrpc) for RPC communication with dcrd
and dcrwallet.
## Architecture
## Deployment
- Single server running dcrvsp and dcrd. dcrd requires txindex so
`getrawtransaction` can be used.
- Multiple remote voting servers, each running dcrwallet and dcrd. dcrwallet
on these servers should be constantly unlocked and have voting enabled.
- Single server running dcrvsp and dcrd. dcrd on this server is used for fishing
ticket details out of the chain, and for broadcasting and checking the status
of fee transactions. `--txindex` is required so `getrawtransaction` can be
used.
## MVP Features
- A xpub key is provided to dcrvsp via config. dcrvsp will use this key to
derive a new addresses for each fee payments. It is recommended to export an
xpub from a cold wallet which is not a part of the dcrvsp deployment.
- When dcrvsp is started for the first time, it generates a ed25519 keypair and
stores it in the database. This key is used to sign all API responses, and the
signature is included in the response header `VSP-Server-Signature`. Error responses
are not signed.
- Every client request which references a ticket should include a HTTP header
`VSP-Client-Signature`. The value of this header must be a signature of the
request body, signed with the commitment address of the referenced ticket.
- An xpub key is provided to dcrvsp via config. dcrvsp will use this key to
derive addresses for fee payments. A new address is generated for each fee.
- VSP API as described in [dcrstakepool #574](https://github.com/decred/dcrstakepool/issues/574)
- Request fee amount (`GET /fee`)
- Request fee address (`POST /feeaddress`)
- Pay fee (`POST /payFee`)
- Ticket status (`GET /ticketstatus`)
- Set voting preferences (`POST /setvotechoices`)
- A minimal, static, web front-end providing pool stats and basic connection
instructions.
- Fees have an expiry period. If the fee is not paid within this period, the
client must request a new fee. This enables the VSP to alter its fee rate.
## Future Features
- Write database backups to disk periodically.
- Backup over http.
- Status check API call as described in [dcrstakepool #628](https://github.com/decred/dcrstakepool/issues/628).
- Consistency checking across connected wallets.
- Multiple remote voting servers, each running dcrwallet and dcrd. dcrwallet on
these servers should be constantly unlocked and have voting enabled. Three
voting servers in different physical locations are recommended for production.
## Backup

48
docs/ANN.md Normal file
View File

@ -0,0 +1,48 @@
# Announcement
## Advantages vs dcrstakepool
### For VSP Administrators
- An instance of bbolt db on the front-end server is used as the single source
of truth:
- bbolt does not have the sys admin overhead associated with maintaining a
MySQL database. The database will be automatically created and maintained
by dcrvsp.
- The bbolt database is only accessed by dcrvsp. There is no need to open
additional ports on your front-end server for the voting wallets to access
the database.
- Voting wallet servers require only dcrwallet and dcrd. There is no longer a
VSP binary (ie. stakepoold) running on voting servers.
- Voting servers no longer need dcrd to be running with `--txindex`.
- No need to use the same wallet seed on each voting wallet.
- A new fee address and amount are requested for each ticket:
- Fee addresses are never reused.
- Fee amount can be changed freely.
- No emails or personal information are held. No need to worry about GDPR et al.
### For VSP Users
- No redeem script to back up.
- No registration required - no email, no password, no CAPTCHA.
- Voting preferences can be set for each individual ticket.
- No address reuse.
- VSP fees are paid independently of the ticket purchase, rather than being
included in the ticket:
- Multiple VSPs can be used for a single ticket.
- Fees can be paid using funds from a mixed account.
- VSP users can purchase tickets in the same anonymity set at solo stakers.
### For the Decred Ecosystem
- Solo tickets and VSP tickets are indistinguishable on-chain.
- Clients and servers can hold eachother accountable for actions. This enables
users to prove if a VSP is misbehaving, and VSPs to defend themselves if they
are falsely accused.
## Disadvantages
- Front-end is more important than before.
- Front-end requires dcrd with `--txindex`.
- Failure cases
- fee tx doesnt broadcast

155
docs/api.md Normal file
View File

@ -0,0 +1,155 @@
# API
## General notes
- Success responses use HTTP status 200 and a JSON encoded body.
- Error responses use either HTTP status 500 or 400, and a JSON encoded error
in the body. For example `{"error":"Description"}`.
- Requests which reference specific tickets need to be properly signed as
described in [two-way-accountability.md](./two-way-accountability.md).
- Implementation of request and response types can be found in
[webapi/types.go](./webapi/types.go).
## Expected usage
### Get VSP public key
Clients should first retrieve the VSP's public key so they can check the
signature on later API responses. A VSP should never change their public key so
it can be requested once and cached indefinitely.
- `GET /api/pubkey`
No request body.
Response:
```json
{
"timestamp":1590509065,
"pubkey":"bLNwVVcda3LqRLv+m0J5sjd60+twjO/fuhcx8RUErDQ="
}
```
### Register ticket
**Registering a ticket is a two step process. The VSP will not add a ticket to
its voting wallets unless both of these calls have succeeded.**
Request fee amount and address for a ticket. The fee amount is only valid until
the expiration time has passed.
- `POST /feeaddress`
Request:
```json
{
"timestamp":1590509066,
"tickethash":"484a68f7148e55d05f0b64a29fe7b148572cb5272d1ce2438cf15466d347f4f4"
}
```
Response:
```json
{
"timestamp":1590509066,
"feeaddress":"Tsfkn6k9AoYgVZRV6ZzcgmuVSgCdJQt9JY2",
"fee":0.001,
"expiration":1590563759,
"request": {"<Copy of request body>"}
}
```
Provide the voting key for the ticket, voting preference, and a signed
transaction which pays the fee to the specified address. If the fee has expired,
this call will return an error and the client will need to request a new fee by
calling `/feeaddress` again. The VSP will not broadcast the fee transaction
until the ticket purchase has 6 confirmations, and it will not add the ticket to
its voting wallets until the fee transaction has 6 confirmations.
- `POST /payfee`
Request:
```json
{
"timestamp":1590509066,
"tickethash":"484a68f7148e55d05f0b64a29fe7b148572cb5272d1ce2438cf15466d347f4f4",
"feetx":"010000000125...737b266ffb9a93",
"votingkey":"PtWUJWhSXsM9ztPkdtH8REe91z7uoidX8dsMChJUZ2spagm7YvrNm",
"votechoices":{"headercommitments":"yes"}
}
```
Response:
```json
{
"timestamp":1590509066,
"request": {"<Copy of request body>"}
}
```
### Information requests
Clients can check the status of the server at any time.
// TODO
Clients can check the status of a ticket at any time after calling
`/feeaddress`.
- `GET /ticketstatus`
Request:
```json
{
"timestamp":1590509066,
"tickethash":"484a68f7148e55d05f0b64a29fe7b148572cb5272d1ce2438cf15466d347f4f4"
}
```
Response:
```json
{
"timestamp":1590509066,
"status":"active",
"votechoices":{"headercommitments":"no"},
"request": {"<Copy of request body>"}
}
```
### Update vote choices
Clients can update the voting preferences of their ticket at any time after
after calling `/payfee`.
- `POST /setvotechoices`
Request:
```json
{
"timestamp":1590509066,
"tickethash":"484a68f7148e55d05f0b64a29fe7b148572cb5272d1ce2438cf15466d347f4f4",
"votechoices":{"headercommitments":"no"}
}
```
Response:
```json
{
"timestamp":1590509066,
"votechoices":{"headercommitments":"no"},
"request": {"<Copy of request body>"}
}
```

View File

@ -0,0 +1,15 @@
# Two-way Accountability
- When dcrvsp is started for the first time, it generates a ed25519 keypair and
stores it in the database. This key is used to sign all API responses, and the
signature is included in the response header `VSP-Server-Signature`.
- Every client request which references a ticket should include a HTTP header
`VSP-Client-Signature`. The value of this header must be a signature of the
request body, signed with the commitment address of the referenced ticket.
## Examples
### Server does not vote ticket
### Client denies changing their voting preferences

View File

@ -25,6 +25,8 @@ func setVoteChoices(c *gin.Context) {
return
}
// TODO: Return an error if we dont have a FeeTx for this ticket yet.
var setVoteChoicesRequest SetVoteChoicesRequest
if err := binding.JSON.BindBody(rawRequest, &setVoteChoicesRequest); err != nil {
log.Warnf("Bad setvotechoices request from %s: %v", c.ClientIP(), err)