Skip to content

Commit

Permalink
add /purchaseticket API endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
itswisdomagain committed Sep 4, 2019
1 parent a94b696 commit 2819207
Showing 1 changed file with 119 additions and 2 deletions.
121 changes: 119 additions & 2 deletions controllers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ func (controller *MainController) API(c web.C, r *http.Request) *system.APIRespo
switch command {
case "address":
_, code, response, err = controller.APIAddress(c, r)
case "purchaseticket":
data, code, response, err = controller.APIPurchaseTicket(c, r)
case "voting":
_, code, response, err = controller.APIVoting(c, r)
default:
Expand Down Expand Up @@ -299,7 +301,7 @@ func (controller *MainController) APIAddress(c web.C, r *http.Request) ([]string
}

// Get the ticket address for this user
pooladdress, err := controller.TicketAddressForUserID(int(c.Env["APIUserID"].(int64)))
pooladdress, err := controller.TicketAddressForUserID(int(user.Id))
if err != nil {
log.Errorf("unable to derive ticket address: %v", err)
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
Expand Down Expand Up @@ -337,6 +339,7 @@ func (controller *MainController) APIAddress(c web.C, r *http.Request) ([]string
var importedHeight int64
importedHeight, err = controller.Cfg.StakepooldServers.ImportScript(serializedScript)
if err != nil {
log.Warnf("unexpected error importing multisig redeem script: %v", err)
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

Expand All @@ -350,7 +353,7 @@ func (controller *MainController) APIAddress(c web.C, r *http.Request) ([]string
createMultiSig.RedeemScript, poolPubKeyAddr, userPubKeyAddr,
userFeeAddr.EncodeAddress(), importedHeight)

log.Infof("successfully create multisigaddress for user %d", c.Env["APIUserID"])
log.Infof("successfully create multisigaddress for user %d", int(user.Id))

err = controller.StakepooldUpdateUsers(dbMap)
if err != nil {
Expand All @@ -360,6 +363,120 @@ func (controller *MainController) APIAddress(c web.C, r *http.Request) ([]string
return nil, codes.OK, "address successfully imported", nil
}

// APIPurchaseTicket returns relevant vsp information to enable clients purchase tickets that this vsp can vote on
func (controller *MainController) APIPurchaseTicket(c web.C, r *http.Request) (*poolapi.PurchaseInfo, codes.Code, string, error) {
userPubKeyAddr := r.FormValue("UserPubKeyAddr")

if _, err := validateUserPubKeyAddr(userPubKeyAddr); err != nil {
return nil, codes.InvalidArgument, "address error", err
}

dbMap := controller.GetDbMap(c)

// check if this userPubKeyAddr has been used previously to generate ticket purchase parameters
user := models.GetUserByEmail(dbMap, userPubKeyAddr)
if user != nil {
purchaseInfo := &poolapi.PurchaseInfo{
PoolAddress: user.UserFeeAddr,
PoolFees: controller.Cfg.PoolFees,
Script: user.MultiSigScript,
TicketAddress: user.MultiSigAddress,
VoteBits: uint16(user.VoteBits),
}
return purchaseInfo, codes.OK, "APIPurchaseTicket: purchaseinfo retrieved for existing userPubKeyAddr", nil
}

user = &models.User{
Username: userPubKeyAddr,
Email: userPubKeyAddr,
EmailVerified: 0,
VoteBits: 1,
VoteBitsVersion: int64(controller.voteVersion),
}

remoteIP := getClientIP(r, controller.Cfg.RealIPHeader)
log.Infof("APIPurchaseTicket POST from %v, created new user account %v. Inserting.", remoteIP, user.Email)

err := models.InsertUser(dbMap, user)
if err != nil {
log.Errorf("Error while creating new user account for ticket purchase: %v", err)
return nil, codes.Unavailable, "system error", errors.New("unable to setup db entry for purchase")
}

// load saved user info from db to get the user id
user = models.GetUserByEmail(dbMap, userPubKeyAddr)
userId := int(user.Id)

// Get the ticket address for this user
pooladdress, err := controller.TicketAddressForUserID(int(user.Id))
if err != nil {
log.Errorf("unable to derive ticket address: %v", err)
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

poolValidateAddress, err := controller.Cfg.StakepooldServers.ValidateAddress(pooladdress)
if err != nil {
log.Errorf("unable to validate address: %v", err)
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}
if !poolValidateAddress.IsMine {
log.Errorf("unable to validate ismine for pool ticket address: %s",
pooladdress.String())
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

poolPubKeyAddr := poolValidateAddress.PubKeyAddr

if _, err = dcrutil.DecodeAddress(poolPubKeyAddr); err != nil {
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

createMultiSig, err := controller.Cfg.StakepooldServers.CreateMultisig([]string{poolPubKeyAddr, userPubKeyAddr})
if err != nil {
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

// Serialize the redeem script (hex string -> []byte)
serializedScript, err := hex.DecodeString(createMultiSig.RedeemScript)
if err != nil {
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

// Import the redeem script
var importedHeight int64
importedHeight, err = controller.Cfg.StakepooldServers.ImportScript(serializedScript)
if err != nil {
log.Warnf("unexpected error importing multisig redeem script: %v", err)
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

userFeeAddr, err := controller.FeeAddressForUserID(int(user.Id))
if err != nil {
log.Warnf("unexpected error deriving pool addr: %s", err.Error())
return nil, codes.Unavailable, "system error", errors.New("unable to process wallet commands")
}

models.UpdateUserByID(dbMap, user.Id, createMultiSig.Address,
createMultiSig.RedeemScript, poolPubKeyAddr, userPubKeyAddr,
userFeeAddr.EncodeAddress(), importedHeight)

log.Infof("successfully create multisigaddress for user %d", userId)

err = controller.StakepooldUpdateUsers(dbMap)
if err != nil {
log.Warnf("failure to update users: %v", err)
}

purchaseInfo := &poolapi.PurchaseInfo{
PoolAddress: userFeeAddr.EncodeAddress(),
PoolFees: controller.Cfg.PoolFees,
Script: createMultiSig.RedeemScript,
TicketAddress: createMultiSig.Address,
VoteBits: uint16(user.VoteBits),
}
return purchaseInfo, codes.OK, "APIPurchaseTicket: purchaseinfo generated for userPubKeyAddr", nil
}

// APIPurchaseInfo fetches and returns the user's info or an error
func (controller *MainController) APIPurchaseInfo(c web.C,
r *http.Request) (*poolapi.PurchaseInfo, codes.Code, string, error) {
Expand Down

0 comments on commit 2819207

Please sign in to comment.