Skip to content

Commit

Permalink
rebuild mirror feature: mirroring them approval yes no
Browse files Browse the repository at this point in the history
  • Loading branch information
vibros68 committed Dec 12, 2023
1 parent 00d9539 commit 415a747
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 74 deletions.
30 changes: 30 additions & 0 deletions politeiawww/cmd/politeiavoter/mirror_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"sync"
"time"
)

type mirrorCache struct {
last time.Time
refreshDur time.Duration
mx sync.Mutex
yesBits int
noBits int
}

func newMirrorCache(refreshDuration time.Duration) *mirrorCache {
return &mirrorCache{
last: time.Time{},
refreshDur: refreshDuration,
mx: sync.Mutex{},
}
}

func (mc *mirrorCache) getVoteBit() string {
return voteOptionYes
}

func (mc *mirrorCache) updateVoteBit(voteBit string) string {
return voteOptionYes
}
116 changes: 52 additions & 64 deletions politeiawww/cmd/politeiavoter/politeiavoter.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,16 @@ const (
)

const (
voteModeMirror = "mirror"
voteModeNumber = "number"
voteModePercent = "percent"
)

const (
voteOptionYes = "yes"
voteOptionNo = "no"
voteOptionMirror = "mirror"
)

func generateSeed() (int64, error) {
var seedBytes [8]byte
_, err := crand.Read(seedBytes[:])
Expand Down Expand Up @@ -127,9 +132,12 @@ type piv struct {
wallet pb.WalletServiceClient
cache *piCache

// for memcache
version *v1.VersionReply
them VoteStats
summaries map[string]tkv1.Summary
mux sync.RWMutex
mc *mirrorCache
}

func newPiVoter(shutdownCtx context.Context, cfg *config) (*piv, error) {
Expand Down Expand Up @@ -554,7 +562,7 @@ func (p *piv) statsVotes(rr *tkv1.ResultsReply, ctres *pb.CommittedTicketsRespon
}
}
}

p.them = *them
return me, them, nil
}

Expand Down Expand Up @@ -1066,19 +1074,7 @@ func (p *piv) _vote(args []string) error {
if qtyY == 0 && qtyN == 0 && !p.cfg.isMirror {
return fmt.Errorf("request vote yes and no = 0")
}
err = p._processVote(token, qtyY, qtyN)
if p.cfg.isMirror {
for {
select {
case <-time.After(p.cfg.voteDuration):
return p._vote(args)
case <-p.ctx.Done():
return nil
default:
}
}
}
return err
return p._processVote(token, qtyY, qtyN)
}

func (p *piv) _processVote(token string, qtyY, qtyN int) error {
Expand Down Expand Up @@ -1127,10 +1123,10 @@ func (p *piv) _processVote(token string, qtyY, qtyN int) error {
voteBitY, voteBitN string
)
for _, vv := range dr.Vote.Params.Options {
if vv.ID == "yes" {
if vv.ID == voteOptionYes {
voteBitY = strconv.FormatUint(vv.Bit, 16)
}
if vv.ID == "no" {
if vv.ID == voteOptionNo {
voteBitN = strconv.FormatUint(vv.Bit, 16)
}
}
Expand Down Expand Up @@ -1298,77 +1294,70 @@ func (p *piv) validateArguments(args []string) (qtyYes, qtyNo, voted, total int,
// we have at least 2 arguments: token id and mode vote
var token = args[0]
var mode = args[1]
me, them, err := p.getTotalVotes(token)
me, _, err := p.getTotalVotes(token)
if err != nil {
return 0, 0, 0, 0, err
}
var votedY, votedN int
if p.cfg.EmulateVote > 0 {
total = p.cfg.EmulateVote
} else {
votedY, votedN, total = me.Yes, me.No, me.Total()
}

var voteYes, voteNo int
switch mode {
case voteModeMirror:
if len(args) != 2 {
return 0, 0, 0, 0, fmt.Errorf("invalid arguments")
// validate arguments format
if len(args) == 6 {
if args[2] != voteOptionYes {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
}
p.cfg.isMirror = true
if p.cfg.voteDuration == 0 {
return 0, 0, 0, 0, fmt.Errorf("mirror mode require voteduration is set")
if args[4] != voteOptionNo {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
}
if p.cfg.EmulateVote > 0 {
return 0, 0, 0, 0, fmt.Errorf("mirror mode is not worked with emulatevote")
} else if len(args) == 4 {
if args[2] != voteOptionMirror {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
}
rateYes = float64(them.Yes) / float64(them.Total())
rateNo = float64(them.No) / float64(them.Total())
} else {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
}

var voteYes, voteNo int
switch mode {
case voteModeNumber:
if len(args) != 6 {
return 0, 0, 0, 0, fmt.Errorf("vote: not enough arguments %v", args)
}
if args[2] != "yes" {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
if len(args) == 6 {
voteYes, _ = strconv.Atoi(args[3])
voteNo, _ = strconv.Atoi(args[5])
}
if args[4] != "no" {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
if len(args) == 4 {
p.cfg.isMirror = true
voteYes, _ = strconv.Atoi(args[3])
}
voteYes, _ = strconv.Atoi(args[3])
voteNo, _ = strconv.Atoi(args[5])
if voteYes+voteNo > me.Total() {
return 0, 0, 0, 0,
fmt.Errorf("entered amount is greater than your total own votes: %d", me.Total())
fmt.Errorf("entered amount(%d) is greater than your total own votes: %d", voteYes+voteNo, me.Total())
}

case voteModePercent:
if len(args) != 6 {
return 0, 0, 0, 0, fmt.Errorf("vote: not enough arguments %v", args)
if len(args) == 6 {
rateYes, _ = strconv.ParseFloat(args[3], 64)
rateNo, _ = strconv.ParseFloat(args[5], 64)
}
if args[2] != "yes" {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
}
if args[4] != "no" {
return 0, 0, 0, 0, fmt.Errorf("invalid argument, see the example to correct it")
if len(args) == 4 {
p.cfg.isMirror = true
rateYes, _ = strconv.ParseFloat(args[3], 64)
}
rateYes, _ = strconv.ParseFloat(args[3], 64)
rateNo, _ = strconv.ParseFloat(args[5], 64)
if rateYes < 0 || rateNo < 0 {
return 0, 0, 0, 0, fmt.Errorf("rate must be > 0 and < 1")
}
if rateYes+rateNo > 1 {
return 0, 0, 0, 0, fmt.Errorf("total rate yes and rate no is greater than 1")
}
default:
return 0, 0, 0, 0, fmt.Errorf("mode [%s] is not supported", mode)
}

var votedY, votedN int
if p.cfg.EmulateVote > 0 {
total = p.cfg.EmulateVote
} else {
votedY, votedN, total = me.Yes, me.No, me.Total()
}

if mode != voteModeNumber {
// calculate number vote from the rate
roughYes := float64(total) * rateYes
roughNo := float64(total) * rateNo
voteYes = int(math.Round(roughYes))
voteNo = int(math.Round(roughNo))
default:
return 0, 0, 0, 0, fmt.Errorf("mode [%s] is not supported", mode)
}

if !p.cfg.isMirror {
Expand Down Expand Up @@ -1451,9 +1440,8 @@ func (p *piv) vote(args []string) error {
names, err := p.names(token)
if err != nil {
return err
} else {
fmt.Printf("proposal '%s'\n", names[token])
}
fmt.Printf("proposal '%s'\n", names[token])

err = p._vote(args) //token, qtyYes, qtyNo)
// we return err after printing details
Expand Down
43 changes: 33 additions & 10 deletions politeiawww/cmd/politeiavoter/trickle.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,13 @@ func (p *piv) batchesVoteAlarm(yesVotes, noVotes []*tkv1.CastVote) ([]*voteAlarm
batchesYes = 1
}
batchesNo := int(bunchesLen) - batchesYes
fmt.Printf("votes: yes %d no %d bunches: yes %d no %d \n",
len(yesVotes), len(noVotes), batchesYes, batchesNo)
if p.cfg.isMirror {
fmt.Printf("votes: %d bunches: %d \n",
len(yesVotes), batchesYes)
} else {
fmt.Printf("votes: yes %d no %d bunches: yes %d no %d \n",
len(yesVotes), len(noVotes), batchesYes, batchesNo)
}

timeFrame := voteDuration / time.Duration(p.cfg.ChartCols)
var yesChartConf = make([]int, p.cfg.ChartCols)
Expand Down Expand Up @@ -150,11 +155,16 @@ func (p *piv) batchesVoteAlarm(yesVotes, noVotes []*tkv1.CastVote) ([]*voteAlarm
At: t,
}
}
if p.cfg.isMirror {
fmt.Printf("votes chart: bunches %d \n", batchesYes)
displayChart(yesChartConf, p.cfg.ChartRows)
} else {
fmt.Printf("yes chart: bunches %d \n", batchesYes)
displayChart(yesChartConf, p.cfg.ChartRows)
fmt.Printf("no chart: bunches %d \n", batchesNo)
displayChart(noChartConf, p.cfg.ChartRows)
}

fmt.Printf("yes chart: bunches %d \n", batchesYes)
displayChart(yesChartConf, p.cfg.ChartRows)
fmt.Printf("no chart: bunches %d \n", batchesNo)
displayChart(noChartConf, p.cfg.ChartRows)
return va, nil
}

Expand All @@ -171,10 +181,15 @@ func (p *piv) gaussianVoteAlarm(votesToCast []*tkv1.CastVote) ([]*voteAlarm, err
if err != nil {
return nil, err
}
fmt.Println("Yes vote chart")
displayChart(g.YesTimeGraph, p.cfg.ChartRows)
fmt.Println("No vote chart")
displayChart(g.NoTimeGraph, p.cfg.ChartRows)
if p.cfg.isMirror {
fmt.Println("vote chart")
displayChart(g.YesTimeGraph, p.cfg.ChartRows)
} else {
fmt.Println("Yes vote chart")
displayChart(g.YesTimeGraph, p.cfg.ChartRows)
fmt.Println("No vote chart")
displayChart(g.NoTimeGraph, p.cfg.ChartRows)
}
return va, nil
}

Expand Down Expand Up @@ -242,6 +257,10 @@ func randomTime(d time.Duration, startPoint time.Time) (time.Time, time.Time, er
return time.Unix(startTime, 0), time.Unix(endTime, 0), nil
}

func (p *piv) mirrorVoteBit() string {
return vote

Check failure on line 261 in politeiawww/cmd/politeiavoter/trickle.go

View workflow job for this annotation

GitHub Actions / Go CI (1.19)

vote (type) is not an expression

Check failure on line 261 in politeiawww/cmd/politeiavoter/trickle.go

View workflow job for this annotation

GitHub Actions / Go CI (1.20)

vote (type) is not an expression
}

func (p *piv) voteTicket(ectx context.Context, voteID int, va voteAlarm, voteBitY, voteBitN string) error {
voteID++ // make human readable
if p.cfg.EmulateVote > 0 {
Expand All @@ -265,6 +284,9 @@ func (p *piv) voteTicket(ectx context.Context, voteID int, va voteAlarm, voteBit
return fmt.Errorf("%v vote %v failed: %v",
viewTime(time.Now()), voteID, err)
}
if p.cfg.isMirror {
va.Vote.VoteBit = p.mc.getVoteBit()
}
var voteSide = "yes"
if va.Vote.VoteBit == voteBitN {
voteSide = "no"
Expand Down Expand Up @@ -375,6 +397,7 @@ func (p *piv) voteTicket(ectx context.Context, voteID int, va voteAlarm, voteBit
}

// Success, log it and exit
p.mc.updateVoteBit(va.Vote.VoteBit)
err = p.jsonLog(successJournal, va.Vote.Token, vr)
if err != nil {
return fmt.Errorf("3 jsonLog: %v", err)
Expand Down
7 changes: 7 additions & 0 deletions politeiawww/cmd/politeiavoter/vote_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,10 @@ type VoteStats struct {
func (v *VoteStats) Total() int {
return v.Yes + v.No + v.Yet
}

func (v *VoteStats) Rate() float64 {
if v.Yes == v.No {
return 0.5
}
return float64(v.Yes) / float64(v.Yes+v.No)
}

0 comments on commit 415a747

Please sign in to comment.