Split docs into seperate files (#72)
This commit is contained in:
parent
d5eb18f557
commit
d5c949b9ad
110
README.md
110
README.md
@ -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
48
docs/ANN.md
Normal 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
155
docs/api.md
Normal 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>"}
|
||||
}
|
||||
```
|
||||
15
docs/two-way-accountability.md
Normal file
15
docs/two-way-accountability.md
Normal 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
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user