github.com/decred/politeia@v1.4.0/politeiad/plugins/ticketvote/ticketvote.go (about) 1 // Copyright (c) 2020-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 // Package ticketvote provides a plugin for running votes that require decred 6 // tickets to participate. 7 package ticketvote 8 9 const ( 10 // PluginID is the unique identifier for this plugin. 11 PluginID = "ticketvote" 12 13 // Plugin commands 14 CmdAuthorize = "authorize" // Authorize a vote 15 CmdStart = "start" // Start a vote 16 CmdCastBallot = "castballot" // Cast a ballot of votes 17 CmdDetails = "details" // Get vote details 18 CmdResults = "results" // Get vote results 19 CmdSummary = "summary" // Get vote summary 20 CmdSubmissions = "submissions" // Get runoff vote submissions 21 CmdInventory = "inventory" // Get inventory by vote status 22 CmdTimestamps = "timestamps" // Get vote timestamps 23 ) 24 25 // Plugin setting keys can be used to specify custom plugin settings. Default 26 // plugin setting values can be overridden by providing a plugin setting key 27 // and value to the plugin on startup. 28 const ( 29 // SettingKeyLinkByPeriodMin is the plugin setting key for the 30 // SettingLinkByPeriodMin plugin setting. 31 SettingKeyLinkByPeriodMin = "linkbyperiodmin" 32 33 // SettingKeyLinkByPeriodMax is the plugin setting key for the 34 // SettingLinkByPeriodMax plugin setting. 35 SettingKeyLinkByPeriodMax = "linkbyperiodmax" 36 37 // SettingKeyVoteDurationMin is the plugin setting key for the 38 // SettingVoteDurationMin plugin setting. 39 SettingKeyVoteDurationMin = "votedurationmin" 40 41 // SettingKeyVoteDurationMax is the plugin setting key for the 42 // SettingVoteDurationMax plugin setting. 43 SettingKeyVoteDurationMax = "votedurationmax" 44 45 // SettingKeySummariesPageSize is the plugin setting key for the 46 // SettingSummariesPageSize plugin setting. 47 SettingKeySummariesPageSize = "summariespagesize" 48 49 // SettingKeyInventoryPageSize is the plugin setting key for the 50 // SettingInventoryPageSize plugin setting. 51 SettingKeyInventoryPageSize = "inventorypagesize" 52 53 // SettingKeyTimestampsPageSize is the plugin setting key for the 54 // SettingTimestampsPageSize plugin setting. 55 SettingKeyTimestampsPageSize = "timestampspagesize" 56 ) 57 58 // Plugin setting default values. These can be overridden by providing a plugin 59 // setting key and value to the plugin on startup. 60 const ( 61 // SettingMainNetLinkByPeriodMin is the default minimum amount of 62 // time, in seconds, that the link by period can be set to. This 63 // value of 2 weeks was chosen assuming a 1 week voting period on 64 // mainnet. 65 SettingMainNetLinkByPeriodMin int64 = 1209600 66 67 // SettingMainNetLinkByPeriodMax is the default maximum amount of 68 // time, in seconds, that the link by period can be set to. This 69 // value of 3 months was chosen arbitrarily. 70 SettingMainNetLinkByPeriodMax int64 = 7776000 71 72 // SettingTestNeLinkByPeriodMin is the default minimum amount of 73 // time, in seconds, that the link by period can be set to. This 74 // value of 1 second was chosen because this is the testnet 75 // default and a 1 second miniumum makes testing various scenarios 76 // easier. 77 SettingTestNetLinkByPeriodMin int64 = 1 78 79 // SettingTestNetLinkByPeriodMax is the default maximum amount of 80 // time, in seconds, that the link by period can be set to. This 81 // value of 3 months was chosen arbitrarily. 82 SettingTestNetLinkByPeriodMax int64 = 7776000 83 84 // SettingMainNetVoteDurationMin is the default minimum vote 85 // duration on mainnet in blocks. 86 SettingMainNetVoteDurationMin uint32 = 2016 87 88 // SettingMainNetVoteDurationMax is the default maximum vote 89 // duration on mainnet in blocks. 90 SettingMainNetVoteDurationMax uint32 = 4032 91 92 // SettingTestNetVoteDurationMin is the default minimum vote 93 // duration on testnet in blocks. 94 SettingTestNetVoteDurationMin uint32 = 1 95 96 // SettingTestNetVoteDurationMax is the default maximum vote 97 // duration on testnet in blocks. 98 SettingTestNetVoteDurationMax uint32 = 4032 99 100 // SettingSummariesPageSize is the default maximum number of 101 // vote summaries that can be requested at any one time. 102 SettingSummariesPageSize uint32 = 5 103 104 // SettingInventoryPageSize is the default maximum number of tokens 105 // that will be returned for any single status in an InventoryReply. 106 SettingInventoryPageSize uint32 = 20 107 108 // SettingTimestampsPageSize is the default maximum number of comment 109 // timestamps that can be requested at any one time. 110 SettingTimestampsPageSize uint32 = 100 111 ) 112 113 // ErrorCodeT represents and error that is caused by the user. 114 type ErrorCodeT uint32 115 116 const ( 117 // ErrorCodeInvalid is an invalid error code. 118 ErrorCodeInvalid ErrorCodeT = 0 119 120 // ErrorCodeTokenInvalid is returned when a record token is 121 // provided as part of a plugin command payload and is not a valid 122 // token or the payload token does not match the token that was 123 // used in the API request. 124 ErrorCodeTokenInvalid ErrorCodeT = 1 125 126 // ErrorCodePublicKeyInvalid is returned when a public key is not 127 // a valid hex encoded, Ed25519 public key. 128 ErrorCodePublicKeyInvalid ErrorCodeT = 2 129 130 // ErrorCodeSignatureInvalid is returned when a signature is not 131 // a valid hex encoded, Ed25519 signature or when the signature is 132 // wrong. 133 ErrorCodeSignatureInvalid ErrorCodeT = 3 134 135 // ErrorCodeRecordVersionInvalid is returned when the record 136 // version used in a plugin command is not the most recent record 137 // version. 138 ErrorCodeRecordVersionInvalid ErrorCodeT = 4 139 140 // ErrorCodeAuthorizationInvalid is returned when a vote 141 // authorization is invalid. 142 ErrorCodeAuthorizationInvalid ErrorCodeT = 5 143 144 // ErrorCodeStartDetailsMissing is returned when a start command 145 // is missing one or more of the start details that it expects to 146 // be present. 147 ErrorCodeStartDetailsMissing ErrorCodeT = 6 148 149 // ErrorCodeStartDetailsInvalid is returned when a start command 150 // contains a start details that is not suppose to be included. 151 ErrorCodeStartDetailsInvalid ErrorCodeT = 7 152 153 // ErrorCodeVoteTypeInvalid is returned when a start details vote 154 // type is invalid. 155 ErrorCodeVoteTypeInvalid ErrorCodeT = 8 156 157 // ErrorCodeVoteDurationInvalid is returned when a start details 158 // vote duration is invalid. 159 ErrorCodeVoteDurationInvalid ErrorCodeT = 9 160 161 // ErrorCodeVoteQuorumInvalid is returned when a start details 162 // quorum percentage is invalid. 163 ErrorCodeVoteQuorumInvalid ErrorCodeT = 10 164 165 // ErrorCodeVotePassRateInvalid is returned when a start details 166 // pass percentage is invalid. 167 ErrorCodeVotePassRateInvalid ErrorCodeT = 11 168 169 // ErrorCodeVoteOptionsInvalid is returned when a start details 170 // vote options are invalid. 171 ErrorCodeVoteOptionsInvalid ErrorCodeT = 12 172 173 // ErrorCodeVoteBitsInvalid is returned when a vote bit or the mask 174 // of a start details is invalid. 175 ErrorCodeVoteBitsInvalid ErrorCodeT = 13 176 177 // ErrorCodeVoteParentInvalid is returned when a parent record 178 // of a runoff submission's start details is invalid. 179 ErrorCodeVoteParentInvalid ErrorCodeT = 14 180 181 // ErrorCodeVoteStatusInvalid is returned when the record's vote 182 // status does not allow for the command to be executed. 183 ErrorCodeVoteStatusInvalid ErrorCodeT = 15 184 185 // ErrorCodeVoteMetadataInvalid is returned when vote metadata 186 // attached to a record is invalid. 187 ErrorCodeVoteMetadataInvalid ErrorCodeT = 16 188 189 // ErrorCodeLinkByInvalid is returned when a vote metadata link by 190 // is invalid. 191 ErrorCodeLinkByInvalid ErrorCodeT = 17 192 193 // ErrorCodeLinkToInvalid is returned when a vote metadata link to 194 // is invalid. 195 ErrorCodeLinkToInvalid ErrorCodeT = 18 196 197 // ErrorCodeLinkByNotExpired is returned when a runoff vote is 198 // attempted to be started before the link by deadline has expired. 199 ErrorCodeLinkByNotExpired ErrorCodeT = 19 200 201 // ErrorCodeRecordStatusInvalid is returned when a ticketvote write 202 // command is executed on a record that is not public. 203 ErrorCodeRecordStatusInvalid ErrorCodeT = 20 204 205 // ErrorCodeLast unit test only 206 ErrorCodeLast ErrorCodeT = 21 207 ) 208 209 var ( 210 // ErrorCodes contains the human readable error messages. 211 ErrorCodes = map[ErrorCodeT]string{ 212 ErrorCodeInvalid: "error code invalid", 213 ErrorCodeTokenInvalid: "token invalid", 214 ErrorCodePublicKeyInvalid: "public key invalid", 215 ErrorCodeSignatureInvalid: "signature invalid", 216 ErrorCodeRecordVersionInvalid: "record version invalid", 217 ErrorCodeAuthorizationInvalid: "authorization invalid", 218 ErrorCodeStartDetailsMissing: "start details missing", 219 ErrorCodeStartDetailsInvalid: "start details invalid", 220 ErrorCodeVoteTypeInvalid: "vote type invalid", 221 ErrorCodeVoteDurationInvalid: "vote duration invalid", 222 ErrorCodeVoteQuorumInvalid: "quorum percentage invalid", 223 ErrorCodeVotePassRateInvalid: "pass rate invalid", 224 ErrorCodeVoteOptionsInvalid: "vote options invalid", 225 ErrorCodeVoteBitsInvalid: "vote bits invalid", 226 ErrorCodeVoteParentInvalid: "vote parent invalid", 227 ErrorCodeVoteStatusInvalid: "vote status invalid", 228 ErrorCodeVoteMetadataInvalid: "vote metadata invalid", 229 ErrorCodeLinkByInvalid: "linkby invalid", 230 ErrorCodeLinkToInvalid: "linkto invalid", 231 ErrorCodeLinkByNotExpired: "linkby not exipred", 232 ErrorCodeRecordStatusInvalid: "record status invalid", 233 } 234 ) 235 236 const ( 237 // FileNameVoteMetadata is the filename of the VoteMetadata file 238 // that is saved to politeiad. VoteMetadata is saved to politeiad 239 // as a file, not as a metadata stream, since it contains user 240 // provided metadata and needs to be included in the merkle root 241 // that politeiad signs. 242 FileNameVoteMetadata = "votemetadata.json" 243 ) 244 245 // VoteMetadata is metadata that is specified by the user and attached to 246 // a record on submission. This metadata is required for certain types of 247 // votes. 248 type VoteMetadata struct { 249 // LinkBy is set when the user intends for the record to be the 250 // parent record in a runoff vote. It is a UNIX timestamp that 251 // serves as the deadline for other records to declare their intent 252 // to participate in the runoff vote. 253 LinkBy int64 `json:"linkby,omitempty"` 254 255 // LinkTo is the censorship token of a runoff vote parent record. 256 // It is set when a record is being submitted as a vote options in 257 // the runoff vote. 258 LinkTo string `json:"linkto,omitempty"` 259 } 260 261 // AuthDetails is the structure that is saved to disk when a vote is authorized 262 // or a previous authorization is revoked. It contains all the fields from a 263 // Authorize and a AuthorizeReply. 264 type AuthDetails struct { 265 // Data generated by client 266 Token string `json:"token"` // Record token 267 Version uint32 `json:"version"` // Record version 268 Action string `json:"action"` // Authorize or revoke 269 PublicKey string `json:"publickey"` // Public key used for signature 270 Signature string `json:"signature"` // Signature of token+version+action 271 272 // Metadata generated by server 273 Timestamp int64 `json:"timestamp"` // Received UNIX timestamp 274 Receipt string `json:"receipt"` // Server signature of client signature 275 } 276 277 // VoteT represents the different types of ticket votes that are available. 278 type VoteT uint32 279 280 const ( 281 // VoteTypeInvalid is an invalid vote type. 282 VoteTypeInvalid VoteT = 0 283 284 // VoteTypeStandard is used to indicate a simple approve or reject 285 // vote where the winner is the voting option that has met the 286 // specified quorum and pass requirements. Standard votes must be 287 // authorized before the vote can be started. 288 VoteTypeStandard VoteT = 1 289 290 // VoteTypeRunoff specifies a runoff vote that multiple records 291 // compete in. All records are voted on like normal, but there can 292 // only be one winner in a runoff vote. The winner is the record 293 // that meets the quorum requirement, meets the pass requirement, 294 // and that has the most net yes votes. The winning record is 295 // considered approved and all other records are considered to be 296 // rejected. If no records meet the quorum and pass requirements 297 // then all records are considered rejected. Note, in a runoff vote 298 // it's possible for a record to meet both the quorum and pass 299 // requirements but still be rejected if it does not have the most 300 // net yes votes. Runoff vote participants are not required to have 301 // the voting period authorized prior to the vote starting. 302 VoteTypeRunoff VoteT = 2 303 ) 304 305 const ( 306 // VoteOptionIDApprove is the vote option ID that indicates the vote 307 // should be approved. Votes that are an approve/reject vote are 308 // required to use this vote option ID. 309 VoteOptionIDApprove = "yes" 310 311 // VoteOptionIDReject is the vote option ID that indicates the vote 312 // should be not be approved. Votes that are an approve/reject vote 313 // are required to use this vote option ID. 314 VoteOptionIDReject = "no" 315 ) 316 317 // VoteOption describes a single vote option. 318 type VoteOption struct { 319 ID string `json:"id"` // Single, unique word (e.g. yes) 320 Description string `json:"description"` // Longer description of the vote 321 Bit uint64 `json:"bit"` // Bit used for this option 322 } 323 324 // VoteParams describes the options and parameters of a ticket vote. 325 type VoteParams struct { 326 Token string `json:"token"` // Record token 327 Version uint32 `json:"version"` // Record version 328 Type VoteT `json:"type"` // Vote type 329 Mask uint64 `json:"mask"` // Valid vote bits 330 Duration uint32 `json:"duration"` // Duration in blocks 331 332 // QuorumPercentage is the percent of elligible votes required for 333 // the vote to meet a quorum. 334 QuorumPercentage uint32 `json:"quorumpercentage"` 335 336 // PassPercentage is the percent of cast votes required for a vote 337 // option to be considered as passing. 338 PassPercentage uint32 `json:"passpercentage"` 339 340 Options []VoteOption `json:"options"` 341 342 // Parent is the token of the parent record. This field will only 343 // be populated for runoff votes. 344 Parent string `json:"parent,omitempty"` 345 } 346 347 // VoteDetails is the structure that is saved to disk when a vote is started. 348 // It contains all of the fields from a Start and a StartReply. A vote details 349 // with the eligible tickets snapshot will be ~0.35MB. 350 // 351 // Signature is the client signature of the SHA256 digest of the JSON encoded 352 // Vote struct. 353 // 354 // Receipt is the server signature of ClientSignature+StartBlockHash. 355 type VoteDetails struct { 356 // Data generated by client 357 Params VoteParams `json:"params"` 358 PublicKey string `json:"publickey"` 359 Signature string `json:"signature"` 360 361 // Metadata generated by server 362 Receipt string `json:"receipt"` 363 StartBlockHeight uint32 `json:"startblockheight"` 364 StartBlockHash string `json:"startblockhash"` 365 EndBlockHeight uint32 `json:"endblockheight"` 366 EligibleTickets []string `json:"eligibletickets"` // Ticket hashes 367 } 368 369 // CastVoteDetails contains the details of a cast vote. 370 // 371 // Signature is the client signature of the Token+Ticket+VoteBit. The client 372 // uses the ticket's largest commitment address to create the signature. The 373 // receipt is the server signature of the client signature. 374 type CastVoteDetails struct { 375 // Data generated by client 376 Token string `json:"token"` // Record token 377 Ticket string `json:"ticket"` // Ticket hash 378 VoteBit string `json:"votebit"` // Vote bit, hex encoded 379 Signature string `json:"signature"` // Client signature 380 381 // Metdata generated by server 382 Address string `json:"address"` // Largest commitment address 383 Receipt string `json:"receipt"` // Server signature 384 Timestamp int64 `json:"timestamp"` // Unix timestamp 385 } 386 387 // AuthActionT represents the ticket vote authorization actions. 388 type AuthActionT string 389 390 const ( 391 // AuthActionAuthorize is used to authorize a ticket vote. 392 AuthActionAuthorize AuthActionT = "authorize" 393 394 // AuthActionRevoke is used to revoke a previous ticket vote 395 // authorization. 396 AuthActionRevoke AuthActionT = "revoke" 397 ) 398 399 // Authorize authorizes a ticket vote or revokes a previous authorization. 400 // 401 // Signature contains the client signature of the Token+Version+Action. 402 type Authorize struct { 403 Token string `json:"token"` // Record token 404 Version uint32 `json:"version"` // Record version 405 Action AuthActionT `json:"action"` // Authorize or revoke 406 PublicKey string `json:"publickey"` // Public key used for signature 407 Signature string `json:"signature"` // Client signature 408 } 409 410 // AuthorizeReply is the reply to the Authorize command. 411 type AuthorizeReply struct { 412 Timestamp int64 `json:"timestamp"` // Received UNIX timestamp 413 Receipt string `json:"receipt"` // Server signature of client signature 414 } 415 416 // StartDetails is the structure that is provided when starting a ticket vote. 417 // 418 // Signature is the signature of a SHA256 digest of the JSON encoded VoteParams 419 // structure. 420 type StartDetails struct { 421 Params VoteParams `json:"params"` 422 PublicKey string `json:"publickey"` // Public key used for signature 423 Signature string `json:"signature"` // Client signature 424 } 425 426 // Start starts a ticket vote. 427 type Start struct { 428 Starts []StartDetails `json:"starts"` 429 } 430 431 // StartReply is the reply to the Start command. 432 // 433 // The Receipt is the server signature of ClientSignature+StartBlockHash. 434 type StartReply struct { 435 Receipt string `json:"receipt"` 436 StartBlockHeight uint32 `json:"startblockheight"` 437 StartBlockHash string `json:"startblockhash"` 438 EndBlockHeight uint32 `json:"endblockheight"` 439 EligibleTickets []string `json:"eligibletickets"` 440 } 441 442 // VoteErrorT represents errors that can occur while attempting to cast ticket 443 // votes. 444 type VoteErrorT uint32 445 446 const ( 447 // VoteErrorInvalid is an invalid vote error. 448 VoteErrorInvalid VoteErrorT = 0 449 450 // VoteErrorInternalError is returned when an internal server error 451 // occurred. 452 VoteErrorInternalError VoteErrorT = 1 453 454 // VoteErrorTokenInvalid is returned when the record censorship 455 // token is invalid. 456 VoteErrorTokenInvalid VoteErrorT = 2 457 458 // VoteErrorRecordNotFound is returned when the specified record 459 // does not exist. 460 VoteErrorRecordNotFound VoteErrorT = 3 461 462 // VoteErrorMultipleRecordVotes is returned when votes are casts 463 // for multiple records in a single ballot. 464 VoteErrorMultipleRecordVotes VoteErrorT = 4 465 466 // VoteErrorVoteStatusInvalid is returned when the ticket vote 467 // status does not allow for votes to be cast, such as when a vote 468 // has already finished. 469 VoteErrorVoteStatusInvalid VoteErrorT = 5 470 471 // VoteErrorVoteBitInvalid is returned when the vote being cast 472 // uses invalid vote bits. 473 VoteErrorVoteBitInvalid VoteErrorT = 6 474 475 // VoteErrorSignatureInvalid is returned when the vote being cast 476 // has an invalid signature. 477 VoteErrorSignatureInvalid VoteErrorT = 7 478 479 // VoteErrorTicketNotEligible is returned when a vote is being cast 480 // using a ticket that is not part of the vote. 481 VoteErrorTicketNotEligible VoteErrorT = 8 482 483 // VoteErrorTicketAlreadyVoted is returned when a vote is cast 484 // using a ticket that has already voted. 485 VoteErrorTicketAlreadyVoted VoteErrorT = 9 486 487 // VoteErrorLast unit test only. 488 VoteErrorLast VoteErrorT = 10 489 ) 490 491 var ( 492 // VoteErrors contains the human readable error messages for the 493 // vote errors. 494 VoteErrors = map[VoteErrorT]string{ 495 VoteErrorInvalid: "vote error invalid", 496 VoteErrorInternalError: "internal server error", 497 VoteErrorTokenInvalid: "token invalid", 498 VoteErrorRecordNotFound: "record not found", 499 VoteErrorMultipleRecordVotes: "attempting to vote on multiple records", 500 VoteErrorVoteStatusInvalid: "record vote status invalid", 501 VoteErrorVoteBitInvalid: "vote bit invalid", 502 VoteErrorSignatureInvalid: "signature invalid", 503 VoteErrorTicketNotEligible: "ticket not eligible", 504 VoteErrorTicketAlreadyVoted: "ticket already voted", 505 } 506 ) 507 508 // CastVote is a signed ticket vote. This structure gets saved to disk when 509 // a vote is cast. 510 type CastVote struct { 511 Token string `json:"token"` // Record token 512 Ticket string `json:"ticket"` // Ticket ID 513 VoteBit string `json:"votebit"` // Selected vote bit, hex encoded 514 Signature string `json:"signature"` // Signature of Token+Ticket+VoteBit 515 } 516 517 // CastVoteReply contains the receipt for the cast vote. 518 type CastVoteReply struct { 519 Ticket string `json:"ticket"` // Ticket ID 520 Receipt string `json:"receipt"` // Server signature of client signature 521 522 // The follwing fields will only be present if an error occurred 523 // while attempting to cast the vote. 524 ErrorCode *VoteErrorT `json:"errorcode,omitempty"` 525 ErrorContext string `json:"errorcontext,omitempty"` 526 } 527 528 // CastBallot casts a ballot of votes. A ballot can only contain votes for a 529 // single record. 530 type CastBallot struct { 531 Ballot []CastVote `json:"ballot"` 532 } 533 534 // CastBallotReply is a reply to a batched list of votes. 535 type CastBallotReply struct { 536 Receipts []CastVoteReply `json:"receipts"` 537 } 538 539 // Details returns the vote details for a record. 540 type Details struct{} 541 542 // DetailsReply is the reply to the Details command. 543 type DetailsReply struct { 544 Auths []AuthDetails `json:"auths"` 545 Vote *VoteDetails `json:"vote,omitempty"` 546 } 547 548 // Results requests the results of a vote. 549 type Results struct{} 550 551 // ResultsReply is the rely to the Results command. 552 type ResultsReply struct { 553 Votes []CastVoteDetails `json:"votes"` 554 } 555 556 // VoteStatusT represents the status of a ticket vote. 557 type VoteStatusT uint32 558 559 const ( 560 // VoteStatusInvalid is an invalid vote status. 561 VoteStatusInvalid VoteStatusT = 0 562 563 // VoteStatusUnauthorized indicates the ticket vote has not been 564 // authorized yet. 565 VoteStatusUnauthorized VoteStatusT = 1 566 567 // VoteStatusAuthorized indicates the ticket vote has been 568 // authorized. 569 VoteStatusAuthorized VoteStatusT = 2 570 571 // VoteStatusStarted indicates the ticket vote has been started. 572 VoteStatusStarted VoteStatusT = 3 573 574 // VoteStatusFinished indicates the ticket vote has finished. This 575 // vote status is used for vote types that do not have a clear 576 // approved or rejected outcome, such as multiple choice votes. 577 VoteStatusFinished VoteStatusT = 4 578 579 // VoteStatusApproved indicates that a vote has finished and the 580 // vote has met the criteria for being approved. This vote status 581 // is only used when the vote type allows for a clear approved or 582 // rejected outcome. 583 VoteStatusApproved VoteStatusT = 5 584 585 // VoteStatusRejected indicates that a vote has finished and the 586 // vote did NOT the criteria for being approved. This vote status 587 // is only used when the vote type allows for a clear approved or 588 // rejected outcome. 589 VoteStatusRejected VoteStatusT = 6 590 591 // VoteStatusIneligible indicates that a record is not eligible to 592 // be voted on. This happens when a record is censored or archived. 593 VoteStatusIneligible VoteStatusT = 7 594 595 // VoteStatusLast unit test only. 596 VoteStatusLast VoteStatusT = 8 597 ) 598 599 var ( 600 // VoteStatuses contains the human readable vote statuses. 601 VoteStatuses = map[VoteStatusT]string{ 602 VoteStatusInvalid: "invalid", 603 VoteStatusUnauthorized: "unauthorized", 604 VoteStatusAuthorized: "authorized", 605 VoteStatusStarted: "started", 606 VoteStatusFinished: "finished", 607 VoteStatusApproved: "approved", 608 VoteStatusRejected: "rejected", 609 VoteStatusIneligible: "ineligible", 610 } 611 ) 612 613 // VoteOptionResult describes a vote option and the total number of votes that 614 // have been cast for this option. 615 type VoteOptionResult struct { 616 ID string `json:"id"` // Single unique word (e.g. yes) 617 Description string `json:"description"` // Longer description of the vote 618 VoteBit uint64 `json:"votebit"` // Bits used for this option 619 Votes uint64 `json:"votes"` // Votes cast for this option 620 } 621 622 // Summary requests the vote summary for a record. 623 type Summary struct{} 624 625 // SummaryReply is the reply to the Summary command. 626 type SummaryReply struct { 627 Status VoteStatusT `json:"status"` 628 629 // Timestamp is the unix timestamp of the most recent vote status change. 630 // 631 // This field will only be populated prior to the start of the voting period. 632 // Once the voting period starts, the vote statuses are based on the block 633 // height and the vote results. These statuses do not have timestamps 634 // associated with them. 635 Timestamp int64 `json:"timestamp,omitempty"` 636 637 // The following fields will only be populated once the voting period has 638 // been started or has finished. 639 Type VoteT `json:"type,omitempty"` 640 Duration uint32 `json:"duration,omitempty"` 641 StartBlockHeight uint32 `json:"startblockheight,omitempty"` 642 StartBlockHash string `json:"startblockhash,omitempty"` 643 EndBlockHeight uint32 `json:"endblockheight,omitempty"` 644 EligibleTickets uint32 `json:"eligibletickets,omitempty"` 645 QuorumPercentage uint32 `json:"quorumpercentage,omitempty"` 646 PassPercentage uint32 `json:"passpercentage,omitempty"` 647 Results []VoteOptionResult `json:"results,omitempty"` 648 649 // BestBlock is the best block value that was used to prepare this summary. 650 BestBlock uint32 `json:"bestblock"` 651 } 652 653 // Submissions requests the submissions of a runoff vote. The only records that 654 // will have a submissions list are the parent records in a runoff vote. The 655 // list will contain all public runoff vote submissions, i.e. records that 656 // have linked to the parent record using the VoteMetadata.LinkTo field. 657 type Submissions struct { 658 Token string `json:"token"` 659 } 660 661 // SubmissionsReply is the reply to the Submissions command. 662 type SubmissionsReply struct { 663 Submissions []string `json:"submissions"` 664 } 665 666 // Inventory requests the tokens of public records in the inventory categorized 667 // by vote status. 668 // 669 // The status and page arguments can be provided to request a specific page of 670 // record tokens. 671 // 672 // If no status is provided then a page of tokens for all statuses will be 673 // returned. The page argument will be ignored. 674 type Inventory struct { 675 Status VoteStatusT `json:"status,omitempty"` 676 Page uint32 `json:"page,omitempty"` 677 } 678 679 // InventoryReply is the reply to the Inventory command. The returned map is a 680 // map[votestatus][]token where the votestatus key is the human readable vote 681 // status defined by the VoteStatuses array in this package. 682 // 683 // Sorted by timestamp in descending order: 684 // Unauthorized, Authorized 685 // 686 // Sorted by vote start block height in descending order: 687 // Started 688 // 689 // Sorted by vote end block height in descending order: 690 // Finished, Approved, Rejected 691 type InventoryReply struct { 692 Tokens map[string][]string `json:"tokens"` 693 694 // BestBlock is the best block value that was used to prepare the 695 // inventory. 696 BestBlock uint32 `json:"bestblock"` 697 } 698 699 // Proof contains an inclusion proof for the digest in the merkle root. The 700 // ExtraData field is used by certain types of proofs to include additional 701 // data that is required to validate the proof. 702 type Proof struct { 703 Type string `json:"type"` 704 Digest string `json:"digest"` 705 MerkleRoot string `json:"merkleroot"` 706 MerklePath []string `json:"merklepath"` 707 ExtraData string `json:"extradata"` // JSON encoded 708 } 709 710 // Timestamp contains all of the data required to verify that a piece of data 711 // was timestamped onto the decred blockchain. 712 // 713 // All digests are hex encoded SHA256 digests. The merkle root can be found in 714 // the OP_RETURN of the specified DCR transaction. 715 // 716 // TxID, MerkleRoot, and Proofs will only be populated once the merkle root has 717 // been included in a DCR tx and the tx has 6 confirmations. The Data field 718 // will not be populated if the data has been censored. 719 type Timestamp struct { 720 Data string `json:"data"` // JSON encoded 721 Digest string `json:"digest"` 722 TxID string `json:"txid"` 723 MerkleRoot string `json:"merkleroot"` 724 Proofs []Proof `json:"proofs"` 725 } 726 727 // Timestamps requests the timestamps for a ticket vote. 728 // 729 // If no votes page number is provided then the vote authorization and vote 730 // details timestamps will be returned. If a votes page number is provided then 731 // the specified page of votes will be returned. 732 type Timestamps struct { 733 VotesPage uint32 `json:"votespage,omitempty"` 734 } 735 736 // TimestampsReply is the reply to the Timestamps command. 737 type TimestampsReply struct { 738 Auths []Timestamp `json:"auths"` 739 Details *Timestamp `json:"details,omitempty"` 740 Votes []Timestamp `json:"votes"` 741 }