-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1cb76ed
Showing
11 changed files
with
610 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
config.toml | ||
main | ||
*.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/BurntSushi/toml" | ||
) | ||
|
||
type Chain struct { | ||
Name string `toml:"name"` | ||
LCDEndpoints []string `toml:"lcd-endpoints"` | ||
Wallets []string `toml:"wallets"` | ||
} | ||
|
||
func (c *Chain) Validate() error { | ||
if c.Name == "" { | ||
return fmt.Errorf("empty chain name") | ||
} | ||
|
||
if len(c.LCDEndpoints) == 0 { | ||
return fmt.Errorf("no LCD endpoints provided") | ||
} | ||
|
||
if len(c.Wallets) == 0 { | ||
return fmt.Errorf("no wallets provided") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type Config struct { | ||
LogConfig LogConfig `toml:"log"` | ||
StatePath string `toml:"state-path"` | ||
Chains []Chain `toml:"chains"` | ||
} | ||
|
||
type LogConfig struct { | ||
LogLevel string `toml:"level"` | ||
JSONOutput bool `toml:"json"` | ||
} | ||
|
||
func (c *Config) Validate() error { | ||
if len(c.Chains) == 0 { | ||
return fmt.Errorf("no chains provided") | ||
} | ||
|
||
for index, chain := range c.Chains { | ||
if err := chain.Validate(); err != nil { | ||
return fmt.Errorf("error in chain %d: %s", index, err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func GetConfig(path string) (*Config, error) { | ||
configBytes, err := os.ReadFile(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
configString := string(configBytes) | ||
|
||
configStruct := Config{} | ||
if _, err = toml.Decode(configString, &configStruct); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &configStruct, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module main | ||
|
||
go 1.18 | ||
|
||
require ( | ||
github.com/BurntSushi/toml v1.1.0 | ||
github.com/rs/zerolog v1.26.1 | ||
github.com/spf13/cobra v1.4.0 | ||
) | ||
|
||
require ( | ||
github.com/inconshreveable/mousetrap v1.0.0 // indirect | ||
github.com/spf13/pflag v1.0.5 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= | ||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= | ||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | ||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= | ||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= | ||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= | ||
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= | ||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= | ||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= | ||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= | ||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= | ||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/rs/zerolog" | ||
) | ||
|
||
func GetDefaultLogger() *zerolog.Logger { | ||
log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() | ||
return &log | ||
} | ||
|
||
func GetLogger(config LogConfig) *zerolog.Logger { | ||
log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() | ||
|
||
logLevel, err := zerolog.ParseLevel(config.LogLevel) | ||
if err != nil { | ||
log.Fatal().Err(err).Msg("Could not parse log level") | ||
} | ||
|
||
if config.JSONOutput { | ||
log = zerolog.New(os.Stdout).With().Timestamp().Logger() | ||
} | ||
|
||
zerolog.SetGlobalLevel(logLevel) | ||
return &log | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
"time" | ||
|
||
"github.com/rs/zerolog" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
const PaginationLimit = 1000 | ||
|
||
func Execute(configPath string) { | ||
config, err := GetConfig(configPath) | ||
if err != nil { | ||
GetDefaultLogger().Fatal().Err(err).Msg("Could not load config") | ||
} | ||
|
||
if err = config.Validate(); err != nil { | ||
GetDefaultLogger().Fatal().Err(err).Msg("Provided config is invalid!") | ||
} | ||
|
||
log := GetLogger(config.LogConfig) | ||
|
||
stateManager := NewStateManager(config.StatePath, log) | ||
reportGenerator := NewReportGenerator(stateManager, log, config.Chains) | ||
|
||
for { | ||
_ = reportGenerator.GenerateReport() | ||
time.Sleep(time.Second * 30) | ||
} | ||
} | ||
|
||
func main() { | ||
var ConfigPath string | ||
|
||
var rootCmd = &cobra.Command{ | ||
Use: "cosmos-proposals-checker", | ||
Long: "Checks the specific wallets on different chains for proposal votes.", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
Execute(ConfigPath) | ||
}, | ||
} | ||
|
||
rootCmd.PersistentFlags().StringVar(&ConfigPath, "config", "", "Config file path") | ||
rootCmd.MarkPersistentFlagRequired("config") | ||
|
||
if err := rootCmd.Execute(); err != nil { | ||
log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger() | ||
log.Fatal().Err(err).Msg("Could not start application") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/rs/zerolog" | ||
) | ||
|
||
type ReportGenerator struct { | ||
StateManager *StateManager | ||
Chains []Chain | ||
RPC *RPC | ||
Logger zerolog.Logger | ||
} | ||
|
||
type ReportEntry struct { | ||
Chain string | ||
Wallet string | ||
ProposalId string | ||
ProposalDescription string | ||
Vote string | ||
} | ||
|
||
type Report struct { | ||
Entries []ReportEntry | ||
} | ||
|
||
func NewReportGenerator( | ||
manager *StateManager, | ||
logger *zerolog.Logger, | ||
chains []Chain, | ||
) *ReportGenerator { | ||
return &ReportGenerator{ | ||
StateManager: manager, | ||
Chains: chains, | ||
Logger: logger.With().Str("component", "report_generator").Logger(), | ||
} | ||
} | ||
|
||
func (g *ReportGenerator) GenerateReport() *Report { | ||
votesMap := make(map[string]map[string]map[string]*Vote) | ||
proposalsMap := make(map[string][]Proposal) | ||
|
||
for _, chain := range g.Chains { | ||
votesMap[chain.Name] = make(map[string]map[string]*Vote) | ||
|
||
rpc := NewRPC(chain.LCDEndpoints, g.Logger) | ||
|
||
g.Logger.Info().Str("name", chain.Name).Msg("Processing a chain") | ||
proposals, err := rpc.GetAllProposals() | ||
if err != nil { | ||
g.Logger.Warn().Err(err).Msg("Error processing proposals") | ||
continue | ||
} | ||
|
||
g.Logger.Info().Int("len", len(proposals)).Msg("Got proposals") | ||
proposalsMap[chain.Name] = proposals | ||
|
||
for _, proposal := range proposals { | ||
for _, wallet := range chain.Wallets { | ||
if g.StateManager.HasVotedBefore(chain.Name, proposal.ProposalID, wallet) { | ||
g.Logger.Trace(). | ||
Str("proposal", proposal.ProposalID). | ||
Str("wallet", wallet). | ||
Msg("Wallet has already voted, not checking again,") | ||
continue | ||
} | ||
|
||
g.Logger.Info(). | ||
Str("proposal", proposal.ProposalID). | ||
Str("wallet", wallet). | ||
Msg("Checking if a wallet had voted") | ||
|
||
vote, err := rpc.GetVote(proposal.ProposalID, wallet) | ||
if err != nil { | ||
g.Logger.Warn().Err(err).Msg("Error processing vote") | ||
} | ||
|
||
g.Logger.Info().Str("result", fmt.Sprintf("%+v", vote)).Msg("Got vote") | ||
g.StateManager.SetVote(chain.Name, proposal.ProposalID, wallet, vote.Vote) | ||
} | ||
} | ||
} | ||
|
||
entries := []ReportEntry{} | ||
|
||
for _, chain := range g.Chains { | ||
for _, proposal := range proposalsMap[chain.Name] { | ||
for _, wallet := range chain.Wallets { | ||
votedNow := g.StateManager.HasVotedNow(chain.Name, proposal.ProposalID, wallet) | ||
votedBefore := g.StateManager.HasVotedBefore(chain.Name, proposal.ProposalID, wallet) | ||
|
||
// Hasn't voted for this proposal - need to notify. | ||
if !votedNow { | ||
entries = append(entries, ReportEntry{ | ||
Chain: chain.Name, | ||
Wallet: wallet, | ||
ProposalId: proposal.ProposalID, | ||
ProposalDescription: proposal.Content.Description, | ||
}) | ||
} | ||
|
||
// Hasn't voted before but voted now - need to close alert/notify about new vote. | ||
if votedNow && !votedBefore { | ||
// entries = append(entries, ReportEntry{ | ||
// Chain: chain.Name, | ||
// Wallet: wallet, | ||
// ProposalId: proposal.ProposalID, | ||
// ProposalDescription: proposal.Content.Description, | ||
// Vote: , | ||
// }) | ||
} | ||
} | ||
} | ||
} | ||
|
||
g.StateManager.CommitNewState() | ||
|
||
return &Report{} | ||
} |
Oops, something went wrong.