diff --git a/pkg/fetcher/cosmos_rpc.go b/pkg/fetcher/cosmos_rpc.go index fa0a754..5329f2e 100644 --- a/pkg/fetcher/cosmos_rpc.go +++ b/pkg/fetcher/cosmos_rpc.go @@ -1,6 +1,8 @@ package fetcher import ( + "bytes" + "encoding/json" "errors" "fmt" configPkg "main/pkg/config" @@ -112,7 +114,26 @@ func (f *CosmosRPCDataFetcher) AbciQuery( return output.Unmarshal(response.Result.Response.Value) } +func (f *CosmosRPCDataFetcher) ParseValidator(validator stakingTypes.Validator) (types.ChainValidator, error) { + if err := validator.UnpackInterfaces(f.ParseCodec); err != nil { + return types.ChainValidator{}, err + } + + addr, err := validator.GetConsAddr() + if err != nil { + return types.ChainValidator{}, err + } + + return types.ChainValidator{ + Moniker: validator.GetMoniker(), + Address: fmt.Sprintf("%X", addr), + RawAddress: addr.String(), + }, nil +} + func (f *CosmosRPCDataFetcher) GetValidators() (*types.ChainValidators, error) { + return f.GetGenesisValidators() + query := stakingTypes.QueryValidatorsRequest{ Pagination: &queryTypes.PageRequest{ Limit: 1000, @@ -135,19 +156,10 @@ func (f *CosmosRPCDataFetcher) GetValidators() (*types.ChainValidators, error) { validators := make(types.ChainValidators, len(validatorsResponse.Validators)) for index, validator := range validatorsResponse.Validators { - if err := validator.UnpackInterfaces(f.ParseCodec); err != nil { + if chainValidator, err := f.ParseValidator(validator); err != nil { return nil, err - } - - addr, err := validator.GetConsAddr() - if err != nil { - return nil, err - } - - validators[index] = types.ChainValidator{ - Moniker: validator.GetMoniker(), - Address: fmt.Sprintf("%X", addr), - RawAddress: addr.String(), + } else { + validators[index] = chainValidator } } @@ -190,25 +202,59 @@ func (f *CosmosRPCDataFetcher) GetValidators() (*types.ChainValidators, error) { func (f *CosmosRPCDataFetcher) GetGenesisValidators() (*types.ChainValidators, error) { f.Logger.Info().Msg("Fetching genesis validators...") - genesisAsBytes := make([]byte, 0) + genesisChunks := make([][]byte, 0) var chunk int64 = 0 for { f.Logger.Info().Int64("chunk", chunk).Msg("Fetching genesis chunk...") genesisChunk, total, err := f.GetGenesisChunk(chunk) + f.Logger.Info().Int64("chunk", chunk).Int64("total", total).Msg("Fetched genesis chunk...") if err != nil { return nil, err } - genesisAsBytes = append(genesisAsBytes, genesisChunk...) + genesisChunks = append(genesisChunks, genesisChunk) - if chunk <= total { + if chunk >= total-1 { break } chunk++ } + genesisBytes := bytes.Join(genesisChunks, []byte{}) + f.Logger.Info().Int("length", len(genesisBytes)).Msg("Fetched genesis") + + var genesisStruct types.Genesis + + if err := json.Unmarshal(genesisBytes, &genesisStruct); err != nil { + f.Logger.Error().Err(err).Msg("Error unmarshalling genesis") + return nil, err + } + + var stakingGenesisState stakingTypes.GenesisState + if err := f.ParseCodec.UnmarshalJSON(genesisStruct.AppState.Staking, &stakingGenesisState); err != nil { + f.Logger.Error().Err(err).Msg("Error unmarshalling staking genesis state") + return nil, err + } + + f.Logger.Info().Int("validators", len(stakingGenesisState.Validators)).Msg("Genesis unmarshalled") + + // 1. Trying to fetch validators from staking module. Works for chain which did not start + // from the first block but had their genesis as an export from older chain. + if len(stakingGenesisState.Validators) > 0 { + validators := make(types.ChainValidators, len(stakingGenesisState.Validators)) + for index, validator := range stakingGenesisState.Validators { + if chainValidator, err := f.ParseValidator(validator); err != nil { + return nil, err + } else { + validators[index] = chainValidator + } + } + + return &validators, nil + } + return nil, fmt.Errorf("genesis validators fetching is not yet supported") } diff --git a/pkg/types/genesis.go b/pkg/types/genesis.go new file mode 100644 index 0000000..ccecc08 --- /dev/null +++ b/pkg/types/genesis.go @@ -0,0 +1,11 @@ +package types + +import "encoding/json" + +type Genesis struct { + AppState AppState `json:"app_state"` +} + +type AppState struct { + Staking json.RawMessage `json:"staking"` +}