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  }