Skip to content

Commit

Permalink
[PVM][Dependencies] AddProposalTx, AddVoteTx, FinishProposalsTx
Browse files Browse the repository at this point in the history
  • Loading branch information
evlekht committed Aug 14, 2023
1 parent fadf074 commit e93ecca
Show file tree
Hide file tree
Showing 13 changed files with 966 additions and 17 deletions.
49 changes: 47 additions & 2 deletions api/v2.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2022, Chain4Travel AG. All rights reserved.
// Copyright (C) 2022-2023, Chain4Travel AG. All rights reserved.
//
// This file is a derived work, based on ava-labs code whose
// original notices appear below.
Expand Down Expand Up @@ -153,7 +153,9 @@ func AddV2Routes(ctx *Context, router *web.Router, path string, indexBytes []byt
Get("/cacheassetaggregates", (*V2Context).CacheAssetAggregates).
Get("/cacheaggregates/:id", (*V2Context).CacheAggregates).
Get("/multisigalias/:owners", (*V2Context).GetMultisigAlias).
Post("/rewards", (*V2Context).GetRewardPost)
Post("/rewards", (*V2Context).GetRewardPost).
Get("/proposals", (*V2Context).ListDACProposals).
Get("/proposals/:id/votes", (*V2Context).GetDACProposalVotes)
}

// AVAX
Expand Down Expand Up @@ -1145,3 +1147,46 @@ func (c *V2Context) CacheAggregates(w web.ResponseWriter, r *web.Request) {

WriteJSON(w, b)
}

func (c *V2Context) ListDACProposals(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()

params := &params.ListDACProposalsParams{}
if err := params.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}

c.WriteCacheable(w, caching.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_dac_proposals", params),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListDACProposals(ctx, params)
},
})
}

func (c *V2Context) GetDACProposalVotes(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()

proposalID := r.PathParams["id"]
c.WriteCacheable(w, caching.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForID("get_dac_proposal_votes", proposalID),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.GetDACProposalVotes(ctx, proposalID)
},
})
}
199 changes: 198 additions & 1 deletion db/dbmodel.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2022, Chain4Travel AG. All rights reserved.
// Copyright (C) 2022-2023, Chain4Travel AG. All rights reserved.
//
// This file is a derived work, based on ava-labs code whose
// original notices appear below.
Expand All @@ -21,6 +21,7 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/chain4travel/magellan/models"
"github.com/chain4travel/magellan/services/indexes/params"
"github.com/chain4travel/magellan/utils"
"github.com/gocraft/dbr/v2"
)
Expand Down Expand Up @@ -56,6 +57,8 @@ const (
TableMultisigAliases = "multisig_aliases"
TableReward = "reward"
TableRewardOwner = "reward_owner"
TableDACProposals = "dac_proposals"
TableDACVotes = "dac_votes"
)

type Persist interface {
Expand Down Expand Up @@ -440,6 +443,45 @@ type Persist interface {
dbr.SessionRunner,
*Reward,
) error

InsertDACProposal(
ctx context.Context,
session dbr.SessionRunner,
proposal *DACProposal,
) error

UpdateDACProposalsStatus(
ctx context.Context,
session dbr.SessionRunner,
proposalIDs []string,
proposalStatus models.ProposalStatus,
) error

FinishDACProposal(
ctx context.Context,
session dbr.SessionRunner,
proposalID string,
proposalStatus models.ProposalStatus,
outcome []byte,
) error

QueryDACProposals(
ctx context.Context,
session dbr.SessionRunner,
params *params.ListDACProposalsParams,
) ([]DACProposal, error)

InsertDACVote(
ctx context.Context,
session dbr.SessionRunner,
vote *DACVote,
) error

QueryDACProposalVotes(
ctx context.Context,
session dbr.SessionRunner,
proposalID string,
) ([]DACVote, error)
}

type persist struct{}
Expand Down Expand Up @@ -2390,3 +2432,158 @@ func (p *persist) DeactivateReward(ctx context.Context, session dbr.SessionRunne

return p.InsertReward(ctx, session, v)
}

type DACProposal struct {
ID string `db:"id"`
ProposerAddr string `db:"proposer_addr"`
StartTime time.Time `db:"start_time"`
EndTime time.Time `db:"end_time"`
Type models.ProposalType `db:"type"`
Options []byte `db:"options"`
Memo []byte `db:"memo"`
Outcome []byte `db:"outcome"` // one or multiple options indexes ?
Status models.ProposalStatus `db:"status"`
}

func (p *persist) InsertDACProposal(ctx context.Context, session dbr.SessionRunner, proposal *DACProposal) error {
_, err := session.
InsertInto(TableDACProposals).
Pair("id", proposal.ID).
Pair("proposer_addr", proposal.ProposerAddr).
Pair("start_time", proposal.StartTime).
Pair("end_time", proposal.EndTime).
Pair("type", proposal.Type).
Pair("options", proposal.Options).
Pair("status", proposal.Status).
ExecContext(ctx)
if err != nil {
return EventErr(TableDACProposals, false, err)
}
return nil
}

func (p *persist) UpdateDACProposalsStatus(
ctx context.Context,
session dbr.SessionRunner,
proposalIDs []string,
proposalStatus models.ProposalStatus,
) error {
_, err := session.
Update(TableDACProposals).
Set("status", proposalStatus).
Where("id IN ?", proposalIDs).
ExecContext(ctx)
if err != nil {
return EventErr(TableDACProposals, false, err)
}
return nil
}

func (p *persist) FinishDACProposal(
ctx context.Context,
session dbr.SessionRunner,
proposalID string,
proposalStatus models.ProposalStatus,
outcome []byte,
) error {
_, err := session.
Update(TableDACProposals).
Set("status", proposalStatus).
Set("outcome", outcome).
Where("id = ?", proposalID).
ExecContext(ctx)
if err != nil {
return EventErr(TableDACProposals, false, err)
}
return nil
}

func (p *persist) QueryDACProposals(
ctx context.Context,
session dbr.SessionRunner,
params *params.ListDACProposalsParams,
) ([]DACProposal, error) {
v := &[]DACProposal{}
query := session.Select(
"P.id",
"P.proposer_addr",
"P.start_time",
"P.end_time",
"P.type",
"P.options",
"T.memo",
"P.outcome",
"P.status",
).From(dbr.I(TableDACProposals).As("P")).
Join(dbr.I(TableTransactions).As("T"), "T.id=P.id")

if params.Offset > 0 {
query.Offset(uint64(params.Offset))
}
if params.Limit > 0 {
query.Limit(uint64(params.Limit))
}
if params.ListParams.StartTimeProvided {
query.Where("P.start_time <= ?", params.StartTime)
}
if params.EndTimeProvided {
query.Where("P.end_time >= ?", params.EndTime)
}
if params.ProposalType != nil {
query.Where("P.type = ?", params.ProposalType)
}
if params.ProposalStatus != nil {
if *params.ProposalStatus == models.ProposalStatusCompleted {
// query.Where(dbr.Or(
// dbr.Eq("status", models.ProposalStatusSuccess),
// dbr.Eq("status", models.ProposalStatusFailed),
// ))
query.Where("P.status = ? OR P.status = ?", models.ProposalStatusSuccess, models.ProposalStatusFailed)
} else {
query.Where("P.status = ?", params.ProposalStatus)
}
}

_, err := query.LoadContext(ctx, v)
return *v, err
}

type DACVote struct {
VoteTxID string `db:"id"`
VoterAddr string `db:"voter_addr"`
VotedAt time.Time `db:"voted_at"`
ProposalID string `db:"proposal_id"`
VotedOptions []byte `db:"voted_options"`
}

func (p *persist) InsertDACVote(ctx context.Context, session dbr.SessionRunner, vote *DACVote) error {
_, err := session.
InsertInto(TableDACVotes).
Pair("id", vote.VoteTxID).
Pair("voter_addr", vote.VoterAddr).
Pair("voted_at", vote.VotedAt).
Pair("proposal_id", vote.ProposalID).
Pair("voted_options", vote.VotedOptions).
ExecContext(ctx)
if err != nil {
return EventErr(TableDACVotes, false, err)
}
return nil
}

func (p *persist) QueryDACProposalVotes(
ctx context.Context,
session dbr.SessionRunner,
proposalID string,
) ([]DACVote, error) {
v := &[]DACVote{}
_, err := session.Select(
"id",
"voter_addr",
"voted_at",
"voted_options",
).From(TableDACVotes).
Where("proposal_id = ?", proposalID).
LoadContext(ctx, v)
return *v, err
}
78 changes: 78 additions & 0 deletions db/dbmodel_mock.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// Copyright (C) 2022-2023, Chain4Travel AG. All rights reserved.
//
// This file is a derived work, based on ava-labs code whose
// original notices appear below.
//
// It is distributed under the same license conditions as the
// original code from which it is derived.
//
// Much love to the original authors for their work.
// **********************************************************
// (c) 2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

Expand All @@ -7,7 +17,10 @@ import (
"context"
"sync"

"github.com/chain4travel/magellan/models"
"github.com/chain4travel/magellan/services/indexes/params"
"github.com/gocraft/dbr/v2"
"golang.org/x/exp/slices"
)

type MockPersist struct {
Expand Down Expand Up @@ -43,6 +56,8 @@ type MockPersist struct {
MultisigAlias map[string]*MultisigAlias
RewardOwner map[string]*RewardOwner
Reward map[string]*Reward
DACProposals map[string]*DACProposal
DACVotes map[string]*DACVote
}

func NewPersistMock() *MockPersist {
Expand Down Expand Up @@ -665,3 +680,66 @@ func (m *MockPersist) InsertReward(ctx context.Context, session dbr.SessionRunne
m.Reward[nv.RewardOwnerHash] = nv
return nil
}

func (m *MockPersist) InsertDACProposal(ctx context.Context, session dbr.SessionRunner, proposal *DACProposal) error {
m.lock.Lock()
defer m.lock.Unlock()
nv := &DACProposal{}
*nv = *proposal
m.DACProposals[proposal.ID] = nv
return nil
}

func (m *MockPersist) QueryDACProposals(ctx context.Context, session dbr.SessionRunner, params *params.ListDACProposalsParams) ([]DACProposal, error) {
m.lock.Lock()
defer m.lock.Unlock()
proposals := make([]DACProposal, 0, len(m.DACProposals))
for _, v := range m.DACProposals {
proposals = append(proposals, *v)
}
return proposals, nil
}

func (m *MockPersist) UpdateDACProposalsStatus(ctx context.Context, session dbr.SessionRunner, proposalIDs []string, proposalStatus models.ProposalStatus) error {
m.lock.Lock()
defer m.lock.Unlock()
for _, v := range m.DACProposals {
if slices.Contains(proposalIDs, v.ID) {
v.Status = proposalStatus
}
}
return nil
}

func (m *MockPersist) FinishDACProposal(ctx context.Context, session dbr.SessionRunner, proposalID string, proposalStatus models.ProposalStatus, outcome []byte) error {
m.lock.Lock()
defer m.lock.Unlock()
proposal, ok := m.DACProposals[proposalID]
if !ok {
return nil
}
proposal.Status = proposalStatus
proposal.Outcome = outcome
return nil
}

func (m *MockPersist) InsertDACVote(ctx context.Context, session dbr.SessionRunner, vote *DACVote) error {
m.lock.Lock()
defer m.lock.Unlock()
nv := &DACVote{}
*nv = *vote
m.DACVotes[vote.VoterAddr] = nv
return nil
}

func (m *MockPersist) QueryDACProposalVotes(ctx context.Context, session dbr.SessionRunner, voterAddr string) ([]DACVote, error) {
m.lock.Lock()
defer m.lock.Unlock()
votes := make([]DACVote, 0, len(m.DACVotes))
for _, v := range m.DACVotes {
if v.VoterAddr == voterAddr {
votes = append(votes, *v)
}
}
return votes, nil
}
Loading

0 comments on commit e93ecca

Please sign in to comment.