Skip to content

Commit 4c162c4

Browse files
committed
Fix compatibility with latest development dcrd
dcrd's JSON-RPC version received a major version bump for the removal of several RPCs related to querying expired and missed tickets. With the activation of DCP0009 and the revocations of all older unspent tickets, these methods are no longer needed by the wallet. The "revoked" status for getstakeinfo is no longer used, and instead, a status of "expired" or "missed" is used (which also implies that the ticket has been revoked). For this subtle breaking change, dcrwallet's JSON-RPC API version also receives a major bump.
1 parent 081e25d commit 4c162c4

File tree

6 files changed

+37
-151
lines changed

6 files changed

+37
-151
lines changed

chain/sync.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
"golang.org/x/sync/errgroup"
2626
)
2727

28-
var requiredAPIVersion = semver{Major: 7, Minor: 0, Patch: 0}
28+
var requiredAPIVersion = semver{Major: 8, Minor: 0, Patch: 0}
2929

3030
// Syncer implements wallet synchronization services by processing
3131
// notifications from a dcrd JSON-RPC server.
@@ -533,10 +533,6 @@ func (s *Syncer) Run(ctx context.Context) (err error) {
533533
if err != nil {
534534
return err
535535
}
536-
err = s.rpc.Call(ctx, "rebroadcastmissed", nil)
537-
if err != nil {
538-
return err
539-
}
540536

541537
log.Infof("Blockchain sync completed, wallet ready for general usage.")
542538

internal/rpc/jsonrpc/methods.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ import (
5454

5555
// API version constants
5656
const (
57-
jsonrpcSemverString = "8.9.0"
58-
jsonrpcSemverMajor = 8
59-
jsonrpcSemverMinor = 9
57+
jsonrpcSemverString = "9.0.0"
58+
jsonrpcSemverMajor = 9
59+
jsonrpcSemverMinor = 0
6060
jsonrpcSemverPatch = 0
6161
)
6262

rpc/client/dcrd/calls.go

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,17 @@ func (r *RPC) ExistsLiveTicket(ctx context.Context, ticket *chainhash.Hash) (boo
8888
return exists, err
8989
}
9090

91-
// ExistsLiveExpiredTickets returns bitsets identifying whether each ticket
92-
// is currently live or expired.
93-
func (r *RPC) ExistsLiveExpiredTickets(ctx context.Context, tickets []*chainhash.Hash) (live, expired bitset.Bytes, err error) {
91+
// ExistsLiveExpiredTickets returns bitsets identifying whether each ticket is
92+
// currently live or expired. Following the activation of DCP0009, this method
93+
// will never return any expired tickets.
94+
//
95+
// Deprecated: Use ExistsLiveTickets instead.
96+
func (r *RPC) ExistsLiveExpiredTickets(ctx context.Context, tickets []*chainhash.Hash) (live, _ bitset.Bytes, err error) {
9497
const op errors.Op = "dcrd.ExistsLiveExpiredTickets"
9598
// Reuse the single json.RawMessage for both calls
9699
ticketArray, _ := json.Marshal(hashSliceToStrings(tickets))
97-
errs := make(chan error, 2)
100+
errs := make(chan error, 1)
98101
go func() { errs <- exists(ctx, r, "existslivetickets", &live, ticketArray) }()
99-
go func() { errs <- exists(ctx, r, "existsexpiredtickets", &expired, ticketArray) }()
100102
for i := 0; i < cap(errs); i++ {
101103
if e := <-errs; err == nil && e != nil {
102104
// Must only return after all exists calls are
@@ -109,19 +111,11 @@ func (r *RPC) ExistsLiveExpiredTickets(ctx context.Context, tickets []*chainhash
109111
return
110112
}
111113

112-
// ExistsExpiredMissedTickets returns bitsets identifying whether each ticket
113-
// is currently expired or missed.
114-
func (r *RPC) ExistsExpiredMissedTickets(ctx context.Context, tickets []*chainhash.Hash) (expired, missed bitset.Bytes, err error) {
115-
const op errors.Op = "dcrd.ExistsExpiredMissedTickets"
116-
ticketArray, _ := json.Marshal(hashSliceToStrings(tickets))
117-
errs := make(chan error, 2)
118-
go func() { errs <- exists(ctx, r, "existsexpiredtickets", &expired, ticketArray) }()
119-
go func() { errs <- exists(ctx, r, "existsmissedtickets", &missed, ticketArray) }()
120-
for i := 0; i < cap(errs); i++ {
121-
if e := <-errs; err == nil && e != nil {
122-
err = errors.E(op, e)
123-
}
124-
}
114+
// ExistsExpiredMissedTckets no longer performs any RPC as there should never be
115+
// unspent expired or missed tickets after the activation of DCP0009.
116+
//
117+
// Deprecated: this method will be removed in the next major version.
118+
func (r *RPC) ExistsExpiredMissedTickets(ctx context.Context, tickets []*chainhash.Hash) (_, _ bitset.Bytes, _ error) {
125119
return
126120
}
127121

rpc/client/dcrd/notifications.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ func RelevantTxAccepted(params json.RawMessage) (tx *wire.MsgTx, err error) {
6767

6868
// MissedTickets extracts the missed ticket hashes from the parameters of a
6969
// spentandmissedtickets JSON-RPC notification.
70+
//
71+
// Deprecated: The missedtickets notification was removed from dcrd and this
72+
// function will be removed in the next major version.
7073
func MissedTickets(params json.RawMessage) (missed []*chainhash.Hash, err error) {
7174
// Parameters (array):
7275
// 0: Block hash (reversed hex)

wallet/tickets.go

Lines changed: 4 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ package wallet
66

77
import (
88
"context"
9-
"time"
109

1110
"decred.org/dcrwallet/v2/errors"
1211
"decred.org/dcrwallet/v2/rpc/client/dcrd"
13-
"decred.org/dcrwallet/v2/wallet/udb"
1412
"decred.org/dcrwallet/v2/wallet/walletdb"
1513
"github.com/decred/dcrd/blockchain/stake/v4"
1614
"github.com/decred/dcrd/chaincfg/chainhash"
@@ -226,105 +224,11 @@ func (w *Wallet) TicketHashesForVotingAddress(ctx context.Context, votingAddr st
226224
return ticketHashes, nil
227225
}
228226

229-
// RevokeTickets creates and sends revocation transactions for any unrevoked
230-
// missed and expired tickets. The wallet must be unlocked to generate any
231-
// revocations.
227+
// RevokeTickets no longer revokes any tickets since revocations are now
228+
// automatically created per DCP0009.
229+
//
230+
// Deprecated: this method will be removed in the next major version.
232231
func (w *Wallet) RevokeTickets(ctx context.Context, rpcCaller Caller) error {
233-
const op errors.Op = "wallet.RevokeTickets"
234-
235-
var ticketHashes []chainhash.Hash
236-
err := walletdb.View(ctx, w.db, func(dbtx walletdb.ReadTx) error {
237-
var err error
238-
_, tipHeight := w.txStore.MainChainTip(dbtx)
239-
ticketHashes, err = w.txStore.UnspentTickets(dbtx, tipHeight, false)
240-
return err
241-
})
242-
if err != nil {
243-
return errors.E(op, err)
244-
}
245-
246-
ticketHashPtrs := make([]*chainhash.Hash, len(ticketHashes))
247-
for i := range ticketHashes {
248-
ticketHashPtrs[i] = &ticketHashes[i]
249-
}
250-
rpc := dcrd.New(rpcCaller)
251-
expired, missed, err := rpc.ExistsExpiredMissedTickets(ctx, ticketHashPtrs)
252-
if err != nil {
253-
return errors.E(op, err)
254-
}
255-
revokableTickets := make([]*chainhash.Hash, 0, len(ticketHashes))
256-
for i, p := range ticketHashPtrs {
257-
if !(expired.Get(i) || missed.Get(i)) {
258-
continue
259-
}
260-
revokableTickets = append(revokableTickets, p)
261-
}
262-
feePerKb := w.RelayFee()
263-
revocations := make([]*wire.MsgTx, 0, len(revokableTickets))
264-
err = walletdb.View(ctx, w.db, func(dbtx walletdb.ReadTx) error {
265-
for _, ticketHash := range revokableTickets {
266-
addrmgrNs := dbtx.ReadBucket(waddrmgrNamespaceKey)
267-
txmgrNs := dbtx.ReadBucket(wtxmgrNamespaceKey)
268-
ticketPurchase, err := w.txStore.Tx(txmgrNs, ticketHash)
269-
if err != nil {
270-
return err
271-
}
272-
273-
// Don't create revocations when this wallet doesn't have voting
274-
// authority or the private key to revoke.
275-
owned, haveKey, err := w.hasVotingAuthority(addrmgrNs, ticketPurchase)
276-
if err != nil {
277-
return err
278-
}
279-
if !(owned && haveKey) {
280-
continue
281-
}
282-
283-
revocation, err := createUnsignedRevocation(ticketHash,
284-
ticketPurchase, feePerKb, w.chainParams)
285-
if err != nil {
286-
return err
287-
}
288-
err = w.signRevocation(addrmgrNs, ticketPurchase, revocation)
289-
if err != nil {
290-
return err
291-
}
292-
revocations = append(revocations, revocation)
293-
}
294-
return nil
295-
})
296-
if err != nil {
297-
return errors.E(op, err)
298-
}
299-
300-
for i, revocation := range revocations {
301-
rec, err := udb.NewTxRecordFromMsgTx(revocation, time.Now())
302-
if err != nil {
303-
return errors.E(op, err)
304-
}
305-
var watch []wire.OutPoint
306-
//w.lockedOutpointMu intentionally not locked.
307-
err = walletdb.Update(ctx, w.db, func(dbtx walletdb.ReadWriteTx) error {
308-
// Could be more efficient by avoiding processTransaction, as we
309-
// know it is a revocation.
310-
watch, err = w.processTransactionRecord(ctx, dbtx, rec, nil, nil)
311-
if err != nil {
312-
return errors.E(op, err)
313-
}
314-
return rpc.PublishTransaction(ctx, revocation)
315-
})
316-
if err != nil {
317-
return errors.E(op, err)
318-
}
319-
320-
log.Infof("Revoked ticket %v with revocation %v", revokableTickets[i],
321-
&rec.Hash)
322-
err = rpc.LoadTxFilter(ctx, false, nil, watch)
323-
if err != nil {
324-
log.Errorf("Failed to watch outpoints: %v", err)
325-
}
326-
}
327-
328232
return nil
329233
}
330234

wallet/wallet.go

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2923,6 +2923,9 @@ const (
29232923
TicketStatusUnspent // unspent
29242924

29252925
// TicketStatusRevoked any ticket that has been previously revoked.
2926+
//
2927+
// Deprecated: The ticket status will be either missed or expired
2928+
// instead. There are no more unrevoked missed/expired tickets.
29262929
TicketStatusRevoked // revoked
29272930
)
29282931

@@ -2956,31 +2959,17 @@ func makeTicketSummary(ctx context.Context, rpc *dcrd.RPC, dbtx walletdb.ReadTx,
29562959
case stake.TxTypeSSGen:
29572960
summary.Status = TicketStatusVoted
29582961
case stake.TxTypeSSRtx:
2959-
summary.Status = TicketStatusRevoked
2960-
}
2961-
return summary
2962-
}
2963-
2964-
if rpc != nil && summary.Status == TicketStatusLive {
2965-
// In RPC mode, find if unspent ticket was expired or missed.
2966-
hashes := []*chainhash.Hash{&details.Ticket.Hash}
2967-
live, expired, err := rpc.ExistsLiveExpiredTickets(ctx, hashes)
2968-
switch {
2969-
case err != nil:
2970-
log.Errorf("Unable to check if ticket was live "+
2971-
"for ticket status: %v", &details.Ticket.Hash)
2972-
summary.Status = TicketStatusUnknown
2973-
case expired.Get(0):
2974-
summary.Status = TicketStatusExpired
2975-
case !live.Get(0):
2976-
summary.Status = TicketStatusMissed
2977-
}
2978-
} else if rpc == nil {
2979-
// In SPV mode, use expired status when the ticket is certainly
2980-
// past the expiry period (even though it is possible that the
2981-
// ticket was missed rather than expiring).
2982-
if ticketExpired(w.chainParams, ticketHeight, tipHeight) {
2983-
summary.Status = TicketStatusExpired
2962+
params := w.chainParams
2963+
ticketHeight := details.Ticket.Block.Height
2964+
revocationHeight := details.Spender.Block.Height
2965+
expired := revocationHeight-ticketHeight >=
2966+
int32(params.TicketExpiryBlocks())+
2967+
int32(params.TicketMaturity)
2968+
if expired {
2969+
summary.Status = TicketStatusExpired
2970+
} else {
2971+
summary.Status = TicketStatusMissed
2972+
}
29842973
}
29852974
}
29862975

0 commit comments

Comments
 (0)