code.vegaprotocol.io/vega@v0.79.0/core/coreapi/services/proposals.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package services 17 18 import ( 19 "context" 20 "sync" 21 22 "code.vegaprotocol.io/vega/core/events" 23 "code.vegaprotocol.io/vega/core/subscribers" 24 vegapb "code.vegaprotocol.io/vega/protos/vega" 25 ) 26 27 type proposalE interface { 28 events.Event 29 Proposal() vegapb.Proposal 30 } 31 32 type Proposals struct { 33 *subscribers.Base 34 ctx context.Context 35 36 mu sync.RWMutex 37 proposals map[string]vegapb.Proposal 38 // map of proposer -> set of proposal id 39 proposalsPerProposer map[string]map[string]struct{} 40 ch chan vegapb.Proposal 41 } 42 43 func NewProposals(ctx context.Context) (proposals *Proposals) { 44 defer func() { go proposals.consume() }() 45 return &Proposals{ 46 Base: subscribers.NewBase(ctx, 1000, true), 47 ctx: ctx, 48 proposals: map[string]vegapb.Proposal{}, 49 proposalsPerProposer: map[string]map[string]struct{}{}, 50 ch: make(chan vegapb.Proposal, 100), 51 } 52 } 53 54 func (p *Proposals) consume() { 55 defer func() { close(p.ch) }() 56 for { 57 select { 58 case <-p.Closed(): 59 return 60 case prop, ok := <-p.ch: 61 if !ok { 62 // cleanup base 63 p.Halt() 64 // channel is closed 65 return 66 } 67 p.mu.Lock() 68 p.proposals[prop.Id] = prop 69 proposals, ok := p.proposalsPerProposer[prop.PartyId] 70 if !ok { 71 proposals = map[string]struct{}{} 72 p.proposalsPerProposer[prop.PartyId] = proposals 73 } 74 proposals[prop.Id] = struct{}{} 75 p.mu.Unlock() 76 } 77 } 78 } 79 80 func (p *Proposals) Push(evts ...events.Event) { 81 for _, e := range evts { 82 if ae, ok := e.(proposalE); ok { 83 p.ch <- ae.Proposal() 84 } 85 } 86 } 87 88 func (p *Proposals) List(proposal, party string) []*vegapb.Proposal { 89 p.mu.RLock() 90 defer p.mu.RUnlock() 91 if len(proposal) <= 0 && len(party) <= 0 { 92 return p.getAllProposals() 93 } else if len(party) > 0 { 94 return p.getProposalsPerParty(proposal, party) 95 } else if len(proposal) > 0 { 96 return p.getProposalByID(proposal) 97 } 98 return p.getAllProposals() 99 } 100 101 func (p *Proposals) getProposalsPerParty(proposal, party string) []*vegapb.Proposal { 102 out := []*vegapb.Proposal{} 103 partyProposals, ok := p.proposalsPerProposer[party] 104 if !ok { 105 return out 106 } 107 108 if len(proposal) > 0 { 109 _, ok := partyProposals[proposal] 110 if ok { 111 prop := p.proposals[proposal] 112 out = append(out, &prop) 113 } 114 return out 115 } 116 117 for k := range partyProposals { 118 prop := p.proposals[k] 119 out = append(out, &prop) 120 } 121 return out 122 } 123 124 func (p *Proposals) getProposalByID(proposal string) []*vegapb.Proposal { 125 out := []*vegapb.Proposal{} 126 asset, ok := p.proposals[proposal] 127 if ok { 128 out = append(out, &asset) 129 } 130 return out 131 } 132 133 func (p *Proposals) getAllProposals() []*vegapb.Proposal { 134 out := make([]*vegapb.Proposal, 0, len(p.proposals)) 135 for _, v := range p.proposals { 136 v := v 137 out = append(out, &v) 138 } 139 return out 140 } 141 142 func (p *Proposals) Types() []events.Type { 143 return []events.Type{ 144 events.ProposalEvent, 145 } 146 }