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

add /purchaseticket API endpoint for accountless ticket purchase #515

Closed

Conversation

itswisdomagain
Copy link
Member

@itswisdomagain itswisdomagain commented Sep 4, 2019

This introduces a new API endpoint to make ticket purchase possible without user signup/login.

This PR paired with #514 resolves #274 (also resolves decredcommunity/issues#100) - emails become optional and vsp services such as purchasing tickets (implemented here) and setting voting preferences (implemented in #514) can be used without creating user accounts on the vsp.

Accountless ticket purchase is done by making a POST request to api/{v1 or v2}/purchaseticket, passing UserPubKeyAddr in post body. This doc describes how to generate a pubkeyaddr using dcrwallet and dcrctl.

Calling the new /purchaseticket endpoint with a valid pubkeyaddr returns the following (sample) data. Calling the endpoint with the same pubkeyaddr multiple times returns the same data. The message field in the response will read APIPurchaseTicket: purchaseinfo retrieved for existing userPubKeyAddr.

{
    "status": "success",
    "code": 0,
    "message": "APIPurchaseTicket: purchaseinfo generated for userPubKeyAddr",
    "data": {
        "PoolAddress": "TsoWCv4bDemoAddress",
        "PoolFees": 7.5,
        "Script": "512102ffbb6...sample script...efc8b552ae",
        "TicketAddress": "TcZJ5jMFDemoAddress",
        "VoteBits": 1,
        "VoteBitsVersion": 0
    }
}

The redeem script returned with the API response should be imported into the purchasing wallet so you can recover your funds and vote in the unlikely event of a VSP failure.

The ticket address, fee address and fee percentage should be used to create and broadcast the ticket purchase transaction. Read how to do this with dcrwallet+dcrctl.

If you subsequently restore your wallet from seed, redeem scripts for "vsp tickets" would need to be (re)imported. Currently, a user can login to the vsp server to retrieve the redeem script. Since tickets purchase using this new API do not have user account login, redeem scripts can be retrieved by issuing an API call to /getpurchaseinfo using the ticket authentication scheme introduced in #514.

Copy link
Member

@JoeGruffins JoeGruffins left a comment

Choose a reason for hiding this comment

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

It's kind of hard to get the entire workflow into my head.

It might help if you could open an issue explaining everything, maybe make some sort of visual aid? Decrediton will have to use this api, maybe get their opinion?

One concern I have is that it leaves cli users out of the loop. What about them? I can't say that this closes #274, or it's partner #291 without accounting for them.

And some things to consider going forward are that this area may change in a big way. We want to start producing a new redeem script for every ticket, and a new fee address.
The fee addresses has an issue going #504
The redeem script not yet. However the consensus is that we need the client to be able to reproduce the script. So, in the end the pool will need to import some more keys for every user, in order to make unique script hashes that are reproduce-able by the user.
After that the pool fee will need to be paid out-of-band, in order to get coinjoin working according to jrick.

But for now this does look like a good system to me. Even after we get more privacy, a txid will still be a txid and the reward address will still be visible. Right? I still need to actually test this and the other, but if they work, I think this is progress in the right direction.

err = controller.StakepooldUpdateUsers(dbMap)
if err != nil {
log.Warnf("failure to update users: %v", err)
if purchaseInfo := controller.generateTicketPurchaseInfo(dbMap, user, userPubKeyAddr); purchaseInfo != nil {
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 prefer this fail on error like most other stuff, but maybe just me.

return controller.Address(c, r)
}
func (controller *MainController) generateTicketPurchaseInfo(dbMap *gorp.DbMap, user *models.User,
userPubKeyAddr string) *poolapi.PurchaseInfo {
Copy link
Member

Choose a reason for hiding this comment

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

And would prefer this also returned an error, like must other stuff.

Copy link
Member Author

Choose a reason for hiding this comment

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

Similar to your previous comment, will implement. What I did was mostly a refactor of existing code and I noticed that some errors were not being logged, but returning an error will cause all errors to be logged - which is better I think.

@itswisdomagain
Copy link
Member Author

Decrediton will have to use this api, maybe get their opinion?

Decrediton can use the API for sure, it's pretty similar to what Decrediton currently does, only that an API key isn't necessary.

As described here decred/decrediton#280, to connect a vsp, a user provides the vsp host address and API Key. When a user submits these,

  • Decrediton makes a GET request to /api/v{n}/getpurchaseinfo to confirm if the user has previously set up his vsp account by submitting a pubkey address.
  • If the user hasn't done so, Decrediton generates a pubkey address from the user's wallet and submits the pubkey address in a POST request to /api/v{n}/address. The VSP uses the user's pubkey address to generate a multisig script, voting address and fee address for the owner of the API key.
  • After submitting the pubkey address successfully, Decrediton makes another GET request to /api/v{n}/getpurchaseinfo to retrieve the msa and other data it needs for tickets purchase. This data is gotten from the first step if the user had already submitted a pubkey address.
  • Decrediton saves the msa and other data gotten from /api/v{n}/getpurchaseinfo and uses it subsequently for tickets purchase.

It's worth noting that Decrediton has to authorize each of the above API using a valid API key; and to get this API key, the user first needs to create an account on the vsp frontend using an email address.

With this new API endpoint, Decrediton would no longer need an API key, just the vsp host address. Without requiring an API key, a user absolutely does not need to create an account from the vsp frontend and can purchase tickets directly from Decrediton.

Additionally, Decrediton does not need to make multiple API calls to get the information it needs to purchase tickets. This new API endpoint, both submits the user's pubkey address and returns the data needed by a client app such as Decrediton to complete the ticket purchase.

Also, with this new API endpoint, Decrediton can purchase multiple tickets without reusing voting or vsp fee addresses. Each purchase can begin with generating a pubkey address from the user's wallet, submitting that address to this new API endpoint which would return a new set of voting and vsp fee address that can be used for ticket purchase. Of course, Decrediton can, if it prefers, chose to save the first voting + vsp fee addresses and reuse those for subsequent ticket purchases.

One concern I have is that it leaves cli users out of the loop. What about them?

That's correct. Wasn't sure if it is necessary to provide support for cli users, if that is the case, such provision can be made. Cli support is currently possible because of the vsp frontend where users can submit their pubkey address and retrieve their multisig script+voting address+fee address.

I can't say that this closes #274, or it's partner #291 without accounting for them.

Can't say this resolves #291 as #291 appears to refer to vsp login from the website. It does close #274 since with this PR, tickets can be purchased without using an email. #514 makes it possible to set voting preferences for tickets purchased this way also without requiring email. Email becomes optional - users can still chose to create accounts from the vsp frontend by providing an email address or use a client app like Decrediton to directly access vsp features without creating an account on the vsp frontend.

And some things to consider going forward are that this area may change in a big way. We want to start producing a new redeem script for every ticket, and a new fee address.
The fee addresses has an issue going #504
The redeem script not yet. However the consensus is that we need the client to be able to reproduce the script. So, in the end the pool will need to import some more keys for every user, in order to make unique script hashes that are reproduce-able by the user.
After that the pool fee will need to be paid out-of-band, in order to get coinjoin working according to jrick.

But for now this does look like a good system to me. Even after we get more privacy, a txid will still be a txid and the reward address will still be visible. Right? I still need to actually test this and the other, but if they work, I think this is progress in the right direction.

I agree with that last bit. This PR in no way prevents further work especially wrt adding the ability to (re)produce the redeem script on both the client and vsp end and improvements relating to payments of vsp fees.

What this PR does is simply make it possible for users to interact with/use vsp features without NEEDING to use an email address to create a user account on the vsp site.

@JoeGruffins
Copy link
Member

I've made a consumer of this api endpoint:
decred/tinydecred#22
It seems to be working fine.

Copy link
Member

@JoeGruffins JoeGruffins left a comment

Choose a reason for hiding this comment

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

Left a couple comments, but this is working great for me.

go.mod Outdated Show resolved Hide resolved
Email: userPubKeyAddr,
EmailVerified: 0,
VoteBits: 1,
VoteBitsVersion: int64(controller.voteVersion),
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps it would be best to put in some random password? Just to be safe and sure noone can access this account through http...

@xaur
Copy link

xaur commented Dec 3, 2019

(1) Will purchaseticket result code/status be different for newly registered VSP ticket purchase and just reporting existing one?

(2) Is purchaceticket protected by authentication in #514? (I assume yes, otherwise it is possible to learn and manipulate others' tickets)

(3) How voting prefs are set and changed? Can you provide or point to examples of all requests and responses?

(4) In the current system the communication with the VSP is done once via the browser, and later the user just broadcasts VSP ticket transactions and the VSP detects them. In the new system, each new pubkeyaddr requires communicating with the VSP. Forcing users to use the website is bad anyway (I'd like to do everything without browsers), but if new address is used for each tickets, using the website simply becomes infeasible. This means changes to dcrwallet or a separate staking program is required for CLI users. I would prefer the latter to avoid introducing VSP protocols into dcrwallet.

(5) In case new address is used for each ticket purchase, redeem script returned for each ticket needs to be backed up (!) by the client and imported into his wallet. This will require automation and new features on the client side - either changes to dcrwallet (including commands to export and import an ever growing bundle of redeem scripts) or a standalone program. Server side also needs tools to backup/restore all the redeem scripts. Without these, the new APIs will be unusable (in no address reuse mode). Is that correct?

if it is necessary to provide support for cli users

Absolutely necessary. The approach taken everywhere else in Decred is that CLI support is added first, and then some of that is reused in GUIs.

Also note that "real" CLI support means all important operations can be done without ever using the ugly web browsers.

#291 appears to refer to vsp login from the website

Per the above, ideally it refers to all kinds of access including non-website.

@xaur
Copy link

xaur commented Dec 3, 2019

The whole problem with redeem scripts outlined in (5) goes away if decred/dcrwallet#1613 is implemented.

@JoeGruffins
Copy link
Member

Long time no see! Thank you for continuing this!

I have started adding tests to main.go. It would be great if you could add tests for generateTicketPurchaseInfo. It should be done on top of #602 There you should have all the tools you need to set up a mock stakepoold and sql.

I also still think you need to throw a random password in there for the new accountless users.

@JoeGruffins
Copy link
Member

JoeGruffins commented Mar 12, 2020

One concern.

Right now new users have the hurdle of a captcha, and then email verification, that supposedly prevents automation of creating new users. With this change, what is to prevent a hostile user from creating new users until we hit max users? Suddenly hitting max users would be pretty catastrophic for the stakepool owner, and the attacker could continue if they up the max. Eventually the database would take up lots of space, and poolfee and voting addresses could be exhausted.

Either we need a puzzle here, or not save these users until they buy a ticket, which creates difficulties, because then how do we watch for tickets unless we watch even bogus users?

Or we need to be informed of ticket purchases by these users, then confirm that they have indeed bought said ticket before we add and watch them.

Even if they are all good users, this may bring us to max users much faster if users make a new account for every ticket.

@dajohi dajohi modified the milestones: v1.3.0, v1.6.0 Mar 12, 2020
@xaur
Copy link

xaur commented Mar 12, 2020

How does this work compare to #574 ? Is there any cooperation? (I'm concerned about wasted efforts)

@dajohi
Copy link
Member

dajohi commented Mar 12, 2020

This is a PR and #574 is an issue

@itswisdomagain
Copy link
Member Author

itswisdomagain commented May 10, 2020

Closed in favour of #625

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Accountless VSP privacy: Make email optional
4 participants