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

rpc: add GetTickets command #957

Merged
merged 35 commits into from
Oct 19, 2017
Merged

rpc: add GetTickets command #957

merged 35 commits into from
Oct 19, 2017

Conversation

alexlyp
Copy link
Member

@alexlyp alexlyp commented Oct 4, 2017

This PR implements a new RPC command for GetTickets.

It uses the same request settings for start/end block as GetTransactions. It then streams GetTicketsResponses back that contain single TicketDetails information in order of the block the ticket was mined.

TicketDetails contains everything that should be needed to collect all the required information about a ticket for the upcoming 'My Tickets' page in decrediton.

Closes #833

@alexlyp alexlyp changed the title rpc: add GetTickets WIP rpc: add GetTickets command Oct 4, 2017
@alexlyp alexlyp removed the WIP label Oct 4, 2017
Copy link
Member

@jrick jrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the documented changes to the API. Since there are some things that need to be changed and clarified I'm holding off on the code review until it's clear what the API needs to be doing.

- `TicketDetails tickets`: A given ticket's details.

The `TicketDetails` message is used by other methods and is documented
[here](#ticketdetails).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't true, it's a new message that's only used here, and can be documented inline.

relevant to the wallet. The message includes details such as which previous
wallet inputs are spent by this transaction, whether each output is controlled
by the wallet or not, the total fee (if calculable), and the earlist time the
transaction was seen.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This description is a copy pasta of TransactionDetails' description and needs to be redone.


- `bytes hash`: The hash of the given ticket.

- `bytes spender_hash`: The hash of the spender (if applicable, otherwise empty).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of empty, say it uses the default value.

- `bytes spender_hash`: The hash of the spender (if applicable, otherwise empty).

- `int64 ticket_age`: If unspent the blocks since being mined. Otherwise,
the number of blocks from when it was mined to when it was spent.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing to me and I'm not sure how it would be useful, even more so since it will take on different values depending on if it was spent.


- `int64 ticket_price`: The value of the first output from the ticket transaction.
Due to the way tickets are constructed, we know that this is always the 'price'
of any given ticket.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an implementation detail that we don't need to discuss here. We should just document that it is the ticket price. If a ticket was purchased with a price greater than required, reporting that value as the ticket price should be considered a bug and fixed.

of any given ticket.

- `int64 ticket_cost`: The total cost of the wallet to purchase the ticket. Typically,
this would just be the ticket fee.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then why not call this field ticket_fee? What else would contribute to the "cost" that isn't the ticket price itself?


- `int64 spender_return`: The total return from the spender transaction. If a vote,
this number should be positive (PoS vote subsidy - poolfee). If a revocation,
this would be negative (minus txfee and poolfee).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear if this is referring to the coins generated by the vote/revocation that this wallet controls, or the total (including fees for split ticket ownership and stakepool tickets).


- `UNMINED`: A ticket that has yet to be mined into a block.

**Stability**: Unstable:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can nuke the trailing colon if there's no explanation afterwards


- `TicketStatus ticket_status`: The observed status of the given ticket.

**Nested enum:** `TicketStatus`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ordering of these seems odd. I would start with unmined, then immature, then live, followed by the rest.

@@ -8,6 +8,8 @@ package udb
import (
"fmt"

"github.com/decred/dcrd/blockchain/stake"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra newline

wallet/wallet.go Outdated
Tickets []*TicketSummary
}

// GetTickets implements the rpc request command for gettickets
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment really needs to be more specific regarding its behavior and what all parameters do, and we shouldn't isolate this API as only for the RPC server.

wallet/wallet.go Outdated
}

// GetTickets implements the rpc request command for gettickets
func (w *Wallet) GetTickets(startBlock, endBlock *BlockIdentifier, cancel <-chan struct{}) (*GetTicketsResult, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this function signature to something more like:

func (w *Wallet) GetTickets(ctx context.Context, startBlock, endBlock *BlockIdentifier, results chan<- *TicketSummary) error

A context should be used for cancellation and should be the first parameter. The channel is used to stream the results back to the caller rather than returning all of the results at once. This will allow the RPC server to actually stream the results to clients as it creates them, instead of loading all of the data up at once into a single slice and then sending messages to the client stream. (This is also a problem with the GetTransactions RPC and should be resolved in a separate commit)

// TicketStatusLive any currently live ticket.
TicketStatusLive TicketStatus = iota
// TicketStatusUnmined any not yet mined ticket.
TicketStatusUnmined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unmined and immature both come before the ticket being live, so those two should be values 0 and 1 respectively.

live, err := w.chainClient.ExistsLiveTicket(&details.Ticket.Hash)
if err != nil {
log.Errorf("Unable to check if ticket was live for ticket status: %v", &details.Ticket.Hash)
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior is not documented at all and will result in a runtime panic later if it occurs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you think it should just set the status to TicketUnknown, log the error and carry on?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

txmgrNs := dbtx.ReadBucket(wtxmgrNamespaceKey)

_, tipHeight := w.TxStore.MainChainTip(txmgrNs)
ticketAge := int64(tipHeight - details.Ticket.Height())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than calculating the age this way to determine if the ticket is immature or expired, do a check on the number of confirmations. This is the way other code in the wallet does this check. There's also an off by one to be aware of. Grep the wallet package for other uses of TicketMaturity and TicketExpiry to find the correct check.

}

// TicketStatus describes the current status a ticket can be observed to be.
type TicketStatus int8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may need an "unknown" value as well. This will allow the ticket results to still be created even if not all info regarding its state can be determined. See the comment about returning nil and the panic above.

wallet/wallet.go Outdated
} else {
err := walletdb.View(w.db, func(dbtx walletdb.ReadTx) error {
ns := dbtx.ReadBucket(wtxmgrNamespaceKey)
meta, err := w.TxStore.GetBlockMetaForHash(ns, startBlock.hash)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look up the header and extract the height from that. I want to remove BlockMeta eventually as it is old code that is made irrelevant now that all headers are saved.

wallet/wallet.go Outdated
} else {
err := walletdb.View(w.db, func(dbtx walletdb.ReadTx) error {
ns := dbtx.ReadBucket(wtxmgrNamespaceKey)
meta, err := w.TxStore.GetBlockMetaForHash(ns, endBlock.hash)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

wallet/wallet.go Outdated
// XXX Here is where I would look up the ticket information from the db so I can populate spenderhash and ticket status
ticketInfo, err := w.TxStore.TicketDetails(txmgrNs, &details[i])
if err != nil {
log.Errorf("error while trying to get ticket details for ")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should return the error instead of logging (and the log is missing the details about what was looked up too)

@alexlyp alexlyp merged commit c51ca68 into decred:master Oct 19, 2017
@alexlyp alexlyp deleted the ayp_gettickets branch October 19, 2017 18:57
buckbeakk pushed a commit to hybridnetwork/hxwallet that referenced this pull request Feb 19, 2018
buckbeakk pushed a commit to hybridnetwork/hxwallet that referenced this pull request Feb 20, 2018
buckbeakk pushed a commit to hybridnetwork/hxwallet that referenced this pull request Feb 25, 2018
Merge for Hx:

- Remove context changes added in 90f42ca.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants