Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: improve handling of low fee tickets #219

Merged
merged 9 commits into from
Nov 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@ vote on their behalf when the ticket is selected.
- The architecture is subject to change in the future to lessen the dependence
on dcrwallet and MySQL.

## Git Tip Release notes

- The handling of tickets considered invalid because they pay too-low-of-a-fee
is now integrated directly into dcrstakepool and stakepoold.
- Users who pass both the adminIPs and the new adminUserIDs checks will see a new link on the
menu to the new administrative add tickets page.
- Tickets are added to the MySQL database and then stakepoold is triggered to pull an update from the
database and reload its config.
- To accommodate changes to the gRPC API, dcrstakepool/stakepoold had
their API versions changed to require/advertize 4.0.0. This requires
performing the upgrade steps outlined below.
- **KNOWN ISSUE** Total tickets count reported by stakepoold may
not be totally accurate until low fee tickets that have been added to
the database can be marked as voted. This will be resolved by future work. ([#201](https://github.com/decred/dcrstakepool/issues/201)).

## Git Tip Upgrade Guide

1) Announce maintenance and shut down dcrstakepool.
2) Upgrade Go to the latest stable version if necessary/possible.
3) Perform an upgrade of each stakepoold instance one at a time.
* Stop stakepoold.
* Build and restart stakepoold.
4) Edit dcrstakepool.conf and set adminIPs/adminUserIDs appropriately to include
the administrative staff for whom you wish give the ability to add low fee
tickets for voting.
5) Upgrade and start dcrstakepool after setting adminUserIDs.
6) Announce maintenance complete after verifying functionality.

## 1.1.1 Release Notes

- dcrd has a new agenda and the vote version in dcrwallet has been
Expand Down Expand Up @@ -249,6 +277,17 @@ If you are modifying templates, sending the USR1 signal to the dcrstakepool proc

## Adding Invalid Tickets

#### For Newer versions / git tip

If a user pays an incorrect fee, login as an account that meets the
adminUserIps and adminUserIds restrictions and click the 'Add Low Fee Tickets'
link in the menu. You will be presented with a list of tickets that are
suitable for adding. Check the appropriate one(s) and click the submit button.
Upon success, you should see the stakepoold logs reflect that the new tickets
were processed.

#### For v1.1.1 and below

If a user pays an incorrect fee you may add their tickets like so (requires dcrd running with txindex=1):

```bash
Expand Down
39 changes: 36 additions & 3 deletions backend/stakepoold/grpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package main

import (
"context"
"crypto/elliptic"
"crypto/tls"
"errors"
Expand All @@ -22,6 +23,7 @@ import (

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/peer"
)

// generateRPCKeyPair generates a new RPC TLS keypair and writes the cert and
Expand Down Expand Up @@ -76,6 +78,37 @@ func generateRPCKeyPair(writeKey bool) (tls.Certificate, error) {
return keyPair, nil
}

func interceptUnary(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
startTime := time.Now()

// parse out method from '/package.service/method'
methodSplit := strings.SplitAfterN(info.FullMethod, "/", 3)
method := methodSplit[2]
peer, peerOk := peer.FromContext(ctx)

// limit the time we take
ctx, cancel := context.WithTimeout(ctx, rpcserver.GRPCCommandTimeout)
// it is good practice to use the cancellation function even with a timeout
defer cancel()

resp, err = handler(ctx, req)
if err != nil && peerOk {
grpcLog.Errorf("%s invoked by %s failed: %v",
method, peer.Addr.String(), err)
}

defer func() {
if peerOk {
grpcLog.Infof("%s invoked by %s processed in %v", method,
peer.Addr.String(), time.Since(startTime))
} else {
grpcLog.Infof("%s processed in %v", method,
time.Since(startTime))
}
}()
return resp, err
}

type listenFunc func(net string, laddr string) (net.Listener, error)

// makeListeners splits the normalized listen addresses into IPv4 and IPv6
Expand Down Expand Up @@ -153,7 +186,7 @@ func openRPCKeyPair() (tls.Certificate, error) {
return tls.LoadX509KeyPair(cfg.RPCCert, cfg.RPCKey)
}

func startGRPCServers(c chan struct{}) (*grpc.Server, error) {
func startGRPCServers(grpcCommandQueueChan chan *rpcserver.GRPCCommandQueue) (*grpc.Server, error) {
var (
server *grpc.Server
keyPair tls.Certificate
Expand All @@ -171,9 +204,9 @@ func startGRPCServers(c chan struct{}) (*grpc.Server, error) {
return nil, err
}
creds := credentials.NewServerTLSFromCert(&keyPair)
server = grpc.NewServer(grpc.Creds(creds))
server = grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(interceptUnary))
rpcserver.StartVersionService(server)
rpcserver.StartStakepooldService(c, server)
rpcserver.StartStakepooldService(grpcCommandQueueChan, server)
for _, lis := range listeners {
lis := lis
go func() {
Expand Down
49 changes: 42 additions & 7 deletions backend/stakepoold/rpc/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,59 @@ syntax = "proto3";
package stakepoolrpc;

service StakepooldService {
// Queries
rpc GetAddedLowFeeTickets (GetAddedLowFeeTicketsRequest) returns (GetAddedLowFeeTicketsResponse);
rpc GetIgnoredLowFeeTickets (GetIgnoredLowFeeTicketsRequest) returns (GetIgnoredLowFeeTicketsResponse);
rpc GetLiveTickets (GetLiveTicketsRequest) returns (GetLiveTicketsResponse);
rpc Ping (PingRequest) returns (PingResponse);

// Control
rpc UpdateVotingPrefs (UpdateVotingPrefsRequest) returns (UpdateVotingPrefsResponse);
rpc SetAddedLowFeeTickets (SetAddedLowFeeTicketsRequest) returns (SetAddedLowFeeTicketsResponse);
rpc SetUserVotingPrefs (SetUserVotingPrefsRequest) returns (SetUserVotingPrefsResponse);
}

service VersionService {
rpc Version (VersionRequest) returns (VersionResponse);
}

message GetAddedLowFeeTicketsRequest {}
message GetAddedLowFeeTicketsResponse {
repeated TicketEntry tickets = 1;
}

message GetIgnoredLowFeeTicketsRequest {}
message GetIgnoredLowFeeTicketsResponse {
repeated TicketEntry tickets = 1;
}

message GetLiveTicketsRequest {}
message GetLiveTicketsResponse {
repeated TicketEntry tickets = 1;
}

message PingRequest {}
message PingResponse {}

message UpdateVotingPrefsRequest {
int64 Userid = 1;
message SetAddedLowFeeTicketsRequest {
repeated TicketEntry tickets = 1;
}
message SetAddedLowFeeTicketsResponse {
}

message SetUserVotingPrefsResponse {
}
message SetUserVotingPrefsRequest {
repeated UserVotingConfigEntry user_voting_config = 1;
}

message TicketEntry {
string TicketAddress = 1;
bytes TicketHash = 2;
}

message UserVotingConfigEntry {
int64 UserId = 1;
string MultiSigAddress = 2;
int64 VoteBits = 3;
int64 VoteBitsVersion = 4;
}
message UpdateVotingPrefsResponse {}

message VersionRequest {}
message VersionResponse {
Expand Down
Loading