From 6989bd6078d355d211e6387a769adc94f5d05495 Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 12 Apr 2021 17:28:17 +0700 Subject: [PATCH 01/11] Add more fields for exporting genesis --- chain/x/oracle/genesis.go | 40 ++++++++++++++++++++++++++----- chain/x/oracle/keeper/reporter.go | 15 ++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/chain/x/oracle/genesis.go b/chain/x/oracle/genesis.go index 2c1ecc16ab..7c603ba362 100644 --- a/chain/x/oracle/genesis.go +++ b/chain/x/oracle/genesis.go @@ -12,9 +12,12 @@ import ( // GenesisState is the oracle state that must be provided at genesis. type GenesisState struct { - Params types.Params `json:"params" yaml:"params"` - DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` - OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` + Params types.Params `json:"params" yaml:"params"` + DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` + OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` + DataSourceFiles map[string][]byte `json:"data_source_files" yaml:"data_source_files"` + OracleScriptFiles map[string][]byte `json:"oracle_script_files" yaml:"oracle_script_files"` + Reporters map[string]sdk.ValAddress `json:"reporters" yaml:"reporters"` } // DefaultGenesisState returns the default oracle genesis state. @@ -52,10 +55,35 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU // ExportGenesis returns a GenesisState for a given context and keeper. func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { + params := k.GetParams(ctx) + dataSources := k.GetAllDataSources(ctx) + oracleScripts := k.GetAllOracleScripts(ctx) + + dataSourceFiles := make(map[string][]byte) + for _, dataSource := range dataSources { + dataSourceFile := k.GetFile(dataSource.Filename) + if len(dataSourceFile) > 0 { + dataSourceFiles[dataSource.Filename] = dataSourceFile + } + } + + oracleScriptFiles := make(map[string][]byte) + for _, oracleScript := range oracleScripts { + oracleScriptFile := k.GetFile(oracleScript.Filename) + if len(oracleScriptFile) > 0 { + oracleScriptFiles[oracleScript.Filename] = oracleScriptFile + } + } + + reporters := k.GetAllReporters(ctx) + return GenesisState{ - Params: k.GetParams(ctx), - DataSources: k.GetAllDataSources(ctx), - OracleScripts: k.GetAllOracleScripts(ctx), + Params: params, + DataSources: dataSources, + OracleScripts: oracleScripts, + DataSourceFiles: dataSourceFiles, + OracleScriptFiles: oracleScriptFiles, + Reporters: reporters, } } diff --git a/chain/x/oracle/keeper/reporter.go b/chain/x/oracle/keeper/reporter.go index f69083b69b..56c2a90b6c 100644 --- a/chain/x/oracle/keeper/reporter.go +++ b/chain/x/oracle/keeper/reporter.go @@ -3,6 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/staking/exported" "github.com/bandprotocol/bandchain/chain/x/oracle/types" ) @@ -51,3 +52,17 @@ func (k Keeper) GetReporters(ctx sdk.Context, val sdk.ValAddress) (reporters []s } return reporters } + +func (k Keeper) GetAllReporters(ctx sdk.Context) map[string]sdk.ValAddress { + reporterMap := make(map[string]sdk.ValAddress) + k.stakingKeeper.IterateBondedValidatorsByPower(ctx, func(index int64, validator exported.ValidatorI) (stop bool) { + valAddress := validator.GetOperator() + reporters := k.GetReporters(ctx, valAddress) + for _, reporter := range reporters { + reporterMap[reporter.String()] = valAddress + } + return true + }) + + return reporterMap +} From d1a5ffbacbadf838f405f72497b8c7aef9226a0d Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Fri, 16 Apr 2021 09:12:11 +0700 Subject: [PATCH 02/11] Add test --- chain/x/oracle/keeper/reporter.go | 2 +- chain/x/oracle/keeper/reporter_test.go | 37 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/chain/x/oracle/keeper/reporter.go b/chain/x/oracle/keeper/reporter.go index 56c2a90b6c..e27a2fbc44 100644 --- a/chain/x/oracle/keeper/reporter.go +++ b/chain/x/oracle/keeper/reporter.go @@ -61,7 +61,7 @@ func (k Keeper) GetAllReporters(ctx sdk.Context) map[string]sdk.ValAddress { for _, reporter := range reporters { reporterMap[reporter.String()] = valAddress } - return true + return false }) return reporterMap diff --git a/chain/x/oracle/keeper/reporter_test.go b/chain/x/oracle/keeper/reporter_test.go index bfb0485a4f..9161f9cb72 100644 --- a/chain/x/oracle/keeper/reporter_test.go +++ b/chain/x/oracle/keeper/reporter_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/bandprotocol/bandchain/chain/x/oracle/testapp" @@ -62,3 +63,39 @@ func TestGetReporters(t *testing.T) { require.Contains(t, reporters, testapp.Bob.Address) require.Contains(t, reporters, testapp.Carol.Address) } + +func TestGetAllReporters(t *testing.T) { + _, ctx, k := testapp.CreateTestInput(true) + // Initially, only validators should be reporters of themselves + reporters := k.GetAllReporters(ctx) + require.Equal(t, 3, len(reporters)) + require.Contains(t, reporters, testapp.Validator1.Address.String()) + require.Equal(t, reporters[testapp.Validator1.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) + require.Contains(t, reporters, testapp.Validator2.Address.String()) + require.Equal(t, reporters[testapp.Validator2.Address.String()], sdk.ValAddress(testapp.Validator2.Address)) + require.Contains(t, reporters, testapp.Validator3.Address.String()) + require.Equal(t, reporters[testapp.Validator3.Address.String()], sdk.ValAddress(testapp.Validator3.Address)) + + // After Alice, Bob, and Carol are added, they should be included in result of GetAllReporters + err := k.AddReporter(ctx, testapp.Validator1.ValAddress, testapp.Alice.Address) + require.NoError(t, err) + err = k.AddReporter(ctx, testapp.Validator1.ValAddress, testapp.Bob.Address) + require.NoError(t, err) + err = k.AddReporter(ctx, testapp.Validator3.ValAddress, testapp.Carol.Address) + require.NoError(t, err) + + reporters = k.GetAllReporters(ctx) + require.Equal(t, 6, len(reporters)) + require.Contains(t, reporters, testapp.Validator1.Address.String()) + require.Equal(t, reporters[testapp.Validator1.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) + require.Contains(t, reporters, testapp.Validator2.Address.String()) + require.Equal(t, reporters[testapp.Validator2.Address.String()], sdk.ValAddress(testapp.Validator2.Address)) + require.Contains(t, reporters, testapp.Validator3.Address.String()) + require.Equal(t, reporters[testapp.Validator3.Address.String()], sdk.ValAddress(testapp.Validator3.Address)) + require.Contains(t, reporters, testapp.Alice.Address.String()) + require.Equal(t, reporters[testapp.Alice.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) + require.Contains(t, reporters, testapp.Bob.Address.String()) + require.Equal(t, reporters[testapp.Bob.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) + require.Contains(t, reporters, testapp.Carol.Address.String()) + require.Equal(t, reporters[testapp.Carol.Address.String()], sdk.ValAddress(testapp.Validator3.Address)) +} From 43c13b2e41fadd2d9c278e20130e4ae22cda4a8c Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Fri, 16 Apr 2021 09:49:36 +0700 Subject: [PATCH 03/11] Added method for InitGenesis --- chain/x/oracle/genesis.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/chain/x/oracle/genesis.go b/chain/x/oracle/genesis.go index 7c603ba362..a4e328eb92 100644 --- a/chain/x/oracle/genesis.go +++ b/chain/x/oracle/genesis.go @@ -23,9 +23,12 @@ type GenesisState struct { // DefaultGenesisState returns the default oracle genesis state. func DefaultGenesisState() GenesisState { return GenesisState{ - Params: types.DefaultParams(), - DataSources: []types.DataSource{}, - OracleScripts: []types.OracleScript{}, + Params: types.DefaultParams(), + DataSources: []types.DataSource{}, + OracleScripts: []types.OracleScript{}, + DataSourceFiles: make(map[string][]byte), + OracleScriptFiles: make(map[string][]byte), + Reporters: make(map[string]sdk.ValAddress), } } @@ -45,11 +48,18 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU k.SetRequestLastExpired(ctx, 0) k.SetRollingSeed(ctx, make([]byte, types.RollingSeedSizeInBytes)) for _, dataSource := range data.DataSources { + k.AddExecutableFile(data.DataSourceFiles[dataSource.Filename]) _ = k.AddDataSource(ctx, dataSource) } for _, oracleScript := range data.OracleScripts { + k.AddOracleScriptFile(data.OracleScriptFiles[oracleScript.Filename]) _ = k.AddOracleScript(ctx, oracleScript) } + for reporterAddrBech32, valAddr := range data.Reporters { + reporterAddr, _ := sdk.AccAddressFromBech32(reporterAddrBech32) + k.AddReporter(ctx, valAddr, reporterAddr) + } + return []abci.ValidatorUpdate{} } From f22196f8c0403168acd75287130d6db878de13dd Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Fri, 16 Apr 2021 15:08:41 +0700 Subject: [PATCH 04/11] format test --- chain/x/oracle/keeper/reporter_test.go | 43 ++++++++++++++------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/chain/x/oracle/keeper/reporter_test.go b/chain/x/oracle/keeper/reporter_test.go index 9161f9cb72..f9c90221bd 100644 --- a/chain/x/oracle/keeper/reporter_test.go +++ b/chain/x/oracle/keeper/reporter_test.go @@ -68,13 +68,16 @@ func TestGetAllReporters(t *testing.T) { _, ctx, k := testapp.CreateTestInput(true) // Initially, only validators should be reporters of themselves reporters := k.GetAllReporters(ctx) - require.Equal(t, 3, len(reporters)) - require.Contains(t, reporters, testapp.Validator1.Address.String()) - require.Equal(t, reporters[testapp.Validator1.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) - require.Contains(t, reporters, testapp.Validator2.Address.String()) - require.Equal(t, reporters[testapp.Validator2.Address.String()], sdk.ValAddress(testapp.Validator2.Address)) - require.Contains(t, reporters, testapp.Validator3.Address.String()) - require.Equal(t, reporters[testapp.Validator3.Address.String()], sdk.ValAddress(testapp.Validator3.Address)) + expectedReporters := map[string]sdk.ValAddress{ + testapp.Validator1.Address.String(): sdk.ValAddress(testapp.Validator1.Address), + testapp.Validator2.Address.String(): sdk.ValAddress(testapp.Validator2.Address), + testapp.Validator3.Address.String(): sdk.ValAddress(testapp.Validator3.Address), + } + require.Equal(t, len(expectedReporters), len(reporters)) + for reporter, validator := range expectedReporters { + require.Contains(t, reporters, reporter) + require.Equal(t, reporters[reporter], sdk.ValAddress(validator)) + } // After Alice, Bob, and Carol are added, they should be included in result of GetAllReporters err := k.AddReporter(ctx, testapp.Validator1.ValAddress, testapp.Alice.Address) @@ -85,17 +88,17 @@ func TestGetAllReporters(t *testing.T) { require.NoError(t, err) reporters = k.GetAllReporters(ctx) - require.Equal(t, 6, len(reporters)) - require.Contains(t, reporters, testapp.Validator1.Address.String()) - require.Equal(t, reporters[testapp.Validator1.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) - require.Contains(t, reporters, testapp.Validator2.Address.String()) - require.Equal(t, reporters[testapp.Validator2.Address.String()], sdk.ValAddress(testapp.Validator2.Address)) - require.Contains(t, reporters, testapp.Validator3.Address.String()) - require.Equal(t, reporters[testapp.Validator3.Address.String()], sdk.ValAddress(testapp.Validator3.Address)) - require.Contains(t, reporters, testapp.Alice.Address.String()) - require.Equal(t, reporters[testapp.Alice.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) - require.Contains(t, reporters, testapp.Bob.Address.String()) - require.Equal(t, reporters[testapp.Bob.Address.String()], sdk.ValAddress(testapp.Validator1.Address)) - require.Contains(t, reporters, testapp.Carol.Address.String()) - require.Equal(t, reporters[testapp.Carol.Address.String()], sdk.ValAddress(testapp.Validator3.Address)) + expectedReporters = map[string]sdk.ValAddress{ + testapp.Validator1.Address.String(): sdk.ValAddress(testapp.Validator1.Address), + testapp.Validator2.Address.String(): sdk.ValAddress(testapp.Validator2.Address), + testapp.Validator3.Address.String(): sdk.ValAddress(testapp.Validator3.Address), + testapp.Alice.Address.String(): sdk.ValAddress(testapp.Validator1.Address), + testapp.Bob.Address.String(): sdk.ValAddress(testapp.Validator1.Address), + testapp.Carol.Address.String(): sdk.ValAddress(testapp.Validator3.Address), + } + require.Equal(t, len(expectedReporters), len(reporters)) + for reporter, validator := range expectedReporters { + require.Contains(t, reporters, reporter) + require.Equal(t, reporters[reporter], sdk.ValAddress(validator)) + } } From e7d17617de6dd1df16e77ad095a65dae5457c02b Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Fri, 16 Apr 2021 15:44:40 +0700 Subject: [PATCH 05/11] removed oracle/datasource files --- chain/x/oracle/genesis.go | 54 +++++++++------------------------------ 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/chain/x/oracle/genesis.go b/chain/x/oracle/genesis.go index a4e328eb92..245f0a4e99 100644 --- a/chain/x/oracle/genesis.go +++ b/chain/x/oracle/genesis.go @@ -12,23 +12,19 @@ import ( // GenesisState is the oracle state that must be provided at genesis. type GenesisState struct { - Params types.Params `json:"params" yaml:"params"` - DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` - OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` - DataSourceFiles map[string][]byte `json:"data_source_files" yaml:"data_source_files"` - OracleScriptFiles map[string][]byte `json:"oracle_script_files" yaml:"oracle_script_files"` - Reporters map[string]sdk.ValAddress `json:"reporters" yaml:"reporters"` + Params types.Params `json:"params" yaml:"params"` + DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` + OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` + Reporters map[string]sdk.ValAddress `json:"reporters" yaml:"reporters"` } // DefaultGenesisState returns the default oracle genesis state. func DefaultGenesisState() GenesisState { return GenesisState{ - Params: types.DefaultParams(), - DataSources: []types.DataSource{}, - OracleScripts: []types.OracleScript{}, - DataSourceFiles: make(map[string][]byte), - OracleScriptFiles: make(map[string][]byte), - Reporters: make(map[string]sdk.ValAddress), + Params: types.DefaultParams(), + DataSources: []types.DataSource{}, + OracleScripts: []types.OracleScript{}, + Reporters: make(map[string]sdk.ValAddress), } } @@ -48,11 +44,9 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU k.SetRequestLastExpired(ctx, 0) k.SetRollingSeed(ctx, make([]byte, types.RollingSeedSizeInBytes)) for _, dataSource := range data.DataSources { - k.AddExecutableFile(data.DataSourceFiles[dataSource.Filename]) _ = k.AddDataSource(ctx, dataSource) } for _, oracleScript := range data.OracleScripts { - k.AddOracleScriptFile(data.OracleScriptFiles[oracleScript.Filename]) _ = k.AddOracleScript(ctx, oracleScript) } for reporterAddrBech32, valAddr := range data.Reporters { @@ -65,35 +59,11 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU // ExportGenesis returns a GenesisState for a given context and keeper. func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { - params := k.GetParams(ctx) - dataSources := k.GetAllDataSources(ctx) - oracleScripts := k.GetAllOracleScripts(ctx) - - dataSourceFiles := make(map[string][]byte) - for _, dataSource := range dataSources { - dataSourceFile := k.GetFile(dataSource.Filename) - if len(dataSourceFile) > 0 { - dataSourceFiles[dataSource.Filename] = dataSourceFile - } - } - - oracleScriptFiles := make(map[string][]byte) - for _, oracleScript := range oracleScripts { - oracleScriptFile := k.GetFile(oracleScript.Filename) - if len(oracleScriptFile) > 0 { - oracleScriptFiles[oracleScript.Filename] = oracleScriptFile - } - } - - reporters := k.GetAllReporters(ctx) - return GenesisState{ - Params: params, - DataSources: dataSources, - OracleScripts: oracleScripts, - DataSourceFiles: dataSourceFiles, - OracleScriptFiles: oracleScriptFiles, - Reporters: reporters, + Params: k.GetParams(ctx), + DataSources: k.GetAllDataSources(ctx), + OracleScripts: k.GetAllOracleScripts(ctx), + Reporters: k.GetAllReporters(ctx), } } From 6e270402041f50b47de050c5cdfe3c002b72dfee Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 19 Apr 2021 11:05:19 +0700 Subject: [PATCH 06/11] Use Reporter struct instead of map --- chain/x/oracle/genesis.go | 15 +++++----- chain/x/oracle/keeper/reporter.go | 8 +++--- chain/x/oracle/keeper/reporter_test.go | 40 +++++++++++++++----------- chain/x/oracle/types/reporter.go | 17 +++++++++++ 4 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 chain/x/oracle/types/reporter.go diff --git a/chain/x/oracle/genesis.go b/chain/x/oracle/genesis.go index 245f0a4e99..76ce6a84dd 100644 --- a/chain/x/oracle/genesis.go +++ b/chain/x/oracle/genesis.go @@ -12,10 +12,10 @@ import ( // GenesisState is the oracle state that must be provided at genesis. type GenesisState struct { - Params types.Params `json:"params" yaml:"params"` - DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` - OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` - Reporters map[string]sdk.ValAddress `json:"reporters" yaml:"reporters"` + Params types.Params `json:"params" yaml:"params"` + DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` + OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` + Reporters []types.Reporter `json:"reporters" yaml:"reporters"` } // DefaultGenesisState returns the default oracle genesis state. @@ -24,7 +24,7 @@ func DefaultGenesisState() GenesisState { Params: types.DefaultParams(), DataSources: []types.DataSource{}, OracleScripts: []types.OracleScript{}, - Reporters: make(map[string]sdk.ValAddress), + Reporters: []types.Reporter{}, } } @@ -49,9 +49,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU for _, oracleScript := range data.OracleScripts { _ = k.AddOracleScript(ctx, oracleScript) } - for reporterAddrBech32, valAddr := range data.Reporters { - reporterAddr, _ := sdk.AccAddressFromBech32(reporterAddrBech32) - k.AddReporter(ctx, valAddr, reporterAddr) + for _, reporter := range data.Reporters { + k.AddReporter(ctx, reporter.Validator, reporter.Reporter) } return []abci.ValidatorUpdate{} diff --git a/chain/x/oracle/keeper/reporter.go b/chain/x/oracle/keeper/reporter.go index e27a2fbc44..6b06d84d83 100644 --- a/chain/x/oracle/keeper/reporter.go +++ b/chain/x/oracle/keeper/reporter.go @@ -53,16 +53,16 @@ func (k Keeper) GetReporters(ctx sdk.Context, val sdk.ValAddress) (reporters []s return reporters } -func (k Keeper) GetAllReporters(ctx sdk.Context) map[string]sdk.ValAddress { - reporterMap := make(map[string]sdk.ValAddress) +func (k Keeper) GetAllReporters(ctx sdk.Context) []types.Reporter { + var reporterList []types.Reporter k.stakingKeeper.IterateBondedValidatorsByPower(ctx, func(index int64, validator exported.ValidatorI) (stop bool) { valAddress := validator.GetOperator() reporters := k.GetReporters(ctx, valAddress) for _, reporter := range reporters { - reporterMap[reporter.String()] = valAddress + reporterList = append(reporterList, types.NewReporter(reporter, valAddress)) } return false }) - return reporterMap + return reporterList } diff --git a/chain/x/oracle/keeper/reporter_test.go b/chain/x/oracle/keeper/reporter_test.go index f9c90221bd..c308ca608b 100644 --- a/chain/x/oracle/keeper/reporter_test.go +++ b/chain/x/oracle/keeper/reporter_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/bandprotocol/bandchain/chain/x/oracle/testapp" + "github.com/bandprotocol/bandchain/chain/x/oracle/types" ) func TestCheckSelfReporter(t *testing.T) { @@ -68,15 +69,21 @@ func TestGetAllReporters(t *testing.T) { _, ctx, k := testapp.CreateTestInput(true) // Initially, only validators should be reporters of themselves reporters := k.GetAllReporters(ctx) - expectedReporters := map[string]sdk.ValAddress{ - testapp.Validator1.Address.String(): sdk.ValAddress(testapp.Validator1.Address), - testapp.Validator2.Address.String(): sdk.ValAddress(testapp.Validator2.Address), - testapp.Validator3.Address.String(): sdk.ValAddress(testapp.Validator3.Address), + expectedReporters := []types.Reporter{ + { + Reporter: testapp.Validator1.Address, + Validator: sdk.ValAddress(testapp.Validator1.Address), + }, { + Reporter: testapp.Validator2.Address, + Validator: sdk.ValAddress(testapp.Validator2.Address), + }, { + Reporter: testapp.Validator3.Address, + Validator: sdk.ValAddress(testapp.Validator3.Address), + }, } require.Equal(t, len(expectedReporters), len(reporters)) - for reporter, validator := range expectedReporters { + for _, reporter := range expectedReporters { require.Contains(t, reporters, reporter) - require.Equal(t, reporters[reporter], sdk.ValAddress(validator)) } // After Alice, Bob, and Carol are added, they should be included in result of GetAllReporters @@ -88,17 +95,18 @@ func TestGetAllReporters(t *testing.T) { require.NoError(t, err) reporters = k.GetAllReporters(ctx) - expectedReporters = map[string]sdk.ValAddress{ - testapp.Validator1.Address.String(): sdk.ValAddress(testapp.Validator1.Address), - testapp.Validator2.Address.String(): sdk.ValAddress(testapp.Validator2.Address), - testapp.Validator3.Address.String(): sdk.ValAddress(testapp.Validator3.Address), - testapp.Alice.Address.String(): sdk.ValAddress(testapp.Validator1.Address), - testapp.Bob.Address.String(): sdk.ValAddress(testapp.Validator1.Address), - testapp.Carol.Address.String(): sdk.ValAddress(testapp.Validator3.Address), - } + expectedReporters = append(expectedReporters, types.NewReporter( + testapp.Alice.Address, + sdk.ValAddress(testapp.Validator1.Address), + ), types.NewReporter( + testapp.Bob.Address, + sdk.ValAddress(testapp.Validator1.Address), + ), types.NewReporter( + testapp.Carol.Address, + sdk.ValAddress(testapp.Validator3.Address), + )) require.Equal(t, len(expectedReporters), len(reporters)) - for reporter, validator := range expectedReporters { + for _, reporter := range expectedReporters { require.Contains(t, reporters, reporter) - require.Equal(t, reporters[reporter], sdk.ValAddress(validator)) } } diff --git a/chain/x/oracle/types/reporter.go b/chain/x/oracle/types/reporter.go new file mode 100644 index 0000000000..80573cba22 --- /dev/null +++ b/chain/x/oracle/types/reporter.go @@ -0,0 +1,17 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// Reporter represents address of reporter and its associated validator +type Reporter struct { + Reporter sdk.AccAddress `json:"reporter" yaml:"reporter"` + Validator sdk.ValAddress `json:"validator" yaml:"validator"` +} + +// NewReporter creates new instance of Reporter +func NewReporter(reporter sdk.AccAddress, validator sdk.ValAddress) Reporter { + return Reporter{ + Reporter: reporter, + Validator: validator, + } +} From bf7fc9d33c34a6690246add89b4fb625caf8fa67 Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 19 Apr 2021 11:30:09 +0700 Subject: [PATCH 07/11] Reformat structure --- chain/x/oracle/genesis.go | 16 ++++---- chain/x/oracle/keeper/reporter.go | 8 ++-- chain/x/oracle/keeper/reporter_test.go | 52 ++++++++++++-------------- chain/x/oracle/types/reporter.go | 16 ++++---- 4 files changed, 44 insertions(+), 48 deletions(-) diff --git a/chain/x/oracle/genesis.go b/chain/x/oracle/genesis.go index 76ce6a84dd..ca9e5f8c27 100644 --- a/chain/x/oracle/genesis.go +++ b/chain/x/oracle/genesis.go @@ -12,10 +12,10 @@ import ( // GenesisState is the oracle state that must be provided at genesis. type GenesisState struct { - Params types.Params `json:"params" yaml:"params"` - DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` - OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` - Reporters []types.Reporter `json:"reporters" yaml:"reporters"` + Params types.Params `json:"params" yaml:"params"` + DataSources []types.DataSource `json:"data_sources" yaml:"data_sources"` + OracleScripts []types.OracleScript `json:"oracle_scripts" yaml:"oracle_scripts"` + Reporters []types.ReportersPerValidator `json:"reporters" yaml:"reporters"` } // DefaultGenesisState returns the default oracle genesis state. @@ -24,7 +24,7 @@ func DefaultGenesisState() GenesisState { Params: types.DefaultParams(), DataSources: []types.DataSource{}, OracleScripts: []types.OracleScript{}, - Reporters: []types.Reporter{}, + Reporters: []types.ReportersPerValidator{}, } } @@ -49,8 +49,10 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU for _, oracleScript := range data.OracleScripts { _ = k.AddOracleScript(ctx, oracleScript) } - for _, reporter := range data.Reporters { - k.AddReporter(ctx, reporter.Validator, reporter.Reporter) + for _, reportersPerValidator := range data.Reporters { + for _, reporter := range reportersPerValidator.Reporters { + k.AddReporter(ctx, reportersPerValidator.Validator, reporter) + } } return []abci.ValidatorUpdate{} diff --git a/chain/x/oracle/keeper/reporter.go b/chain/x/oracle/keeper/reporter.go index 6b06d84d83..bc8c3c57d8 100644 --- a/chain/x/oracle/keeper/reporter.go +++ b/chain/x/oracle/keeper/reporter.go @@ -53,14 +53,12 @@ func (k Keeper) GetReporters(ctx sdk.Context, val sdk.ValAddress) (reporters []s return reporters } -func (k Keeper) GetAllReporters(ctx sdk.Context) []types.Reporter { - var reporterList []types.Reporter +func (k Keeper) GetAllReporters(ctx sdk.Context) []types.ReportersPerValidator { + var reporterList []types.ReportersPerValidator k.stakingKeeper.IterateBondedValidatorsByPower(ctx, func(index int64, validator exported.ValidatorI) (stop bool) { valAddress := validator.GetOperator() reporters := k.GetReporters(ctx, valAddress) - for _, reporter := range reporters { - reporterList = append(reporterList, types.NewReporter(reporter, valAddress)) - } + reporterList = append(reporterList, types.NewReportersPerValidator(valAddress, reporters)) return false }) diff --git a/chain/x/oracle/keeper/reporter_test.go b/chain/x/oracle/keeper/reporter_test.go index c308ca608b..96fc08471f 100644 --- a/chain/x/oracle/keeper/reporter_test.go +++ b/chain/x/oracle/keeper/reporter_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" "github.com/bandprotocol/bandchain/chain/x/oracle/testapp" - "github.com/bandprotocol/bandchain/chain/x/oracle/types" ) func TestCheckSelfReporter(t *testing.T) { @@ -69,21 +68,18 @@ func TestGetAllReporters(t *testing.T) { _, ctx, k := testapp.CreateTestInput(true) // Initially, only validators should be reporters of themselves reporters := k.GetAllReporters(ctx) - expectedReporters := []types.Reporter{ - { - Reporter: testapp.Validator1.Address, - Validator: sdk.ValAddress(testapp.Validator1.Address), - }, { - Reporter: testapp.Validator2.Address, - Validator: sdk.ValAddress(testapp.Validator2.Address), - }, { - Reporter: testapp.Validator3.Address, - Validator: sdk.ValAddress(testapp.Validator3.Address), - }, + expectedReporterMap := map[string][]sdk.AccAddress{ + sdk.ValAddress(testapp.Validator1.Address).String(): {testapp.Validator1.Address}, + sdk.ValAddress(testapp.Validator2.Address).String(): {testapp.Validator2.Address}, + sdk.ValAddress(testapp.Validator3.Address).String(): {testapp.Validator3.Address}, } - require.Equal(t, len(expectedReporters), len(reporters)) - for _, reporter := range expectedReporters { - require.Contains(t, reporters, reporter) + require.Equal(t, len(expectedReporterMap), len(reporters)) + for _, reportersPerValidator := range reporters { + valAddr := sdk.ValAddress(reportersPerValidator.Validator).String() + require.Contains(t, expectedReporterMap, valAddr) + for _, reporter := range reportersPerValidator.Reporters { + require.Contains(t, expectedReporterMap[valAddr], reporter) + } } // After Alice, Bob, and Carol are added, they should be included in result of GetAllReporters @@ -95,18 +91,18 @@ func TestGetAllReporters(t *testing.T) { require.NoError(t, err) reporters = k.GetAllReporters(ctx) - expectedReporters = append(expectedReporters, types.NewReporter( - testapp.Alice.Address, - sdk.ValAddress(testapp.Validator1.Address), - ), types.NewReporter( - testapp.Bob.Address, - sdk.ValAddress(testapp.Validator1.Address), - ), types.NewReporter( - testapp.Carol.Address, - sdk.ValAddress(testapp.Validator3.Address), - )) - require.Equal(t, len(expectedReporters), len(reporters)) - for _, reporter := range expectedReporters { - require.Contains(t, reporters, reporter) + expectedReporterMap = map[string][]sdk.AccAddress{ + sdk.ValAddress(testapp.Validator1.Address).String(): {testapp.Validator1.Address, testapp.Bob.Address, testapp.Alice.Address}, + sdk.ValAddress(testapp.Validator2.Address).String(): {testapp.Validator2.Address}, + sdk.ValAddress(testapp.Validator3.Address).String(): {testapp.Validator3.Address, testapp.Carol.Address}, + } + + require.Equal(t, len(expectedReporterMap), len(reporters)) + for _, reportersPerValidator := range reporters { + valAddr := sdk.ValAddress(reportersPerValidator.Validator).String() + require.Contains(t, expectedReporterMap, valAddr) + for _, reporter := range reportersPerValidator.Reporters { + require.Contains(t, expectedReporterMap[valAddr], reporter) + } } } diff --git a/chain/x/oracle/types/reporter.go b/chain/x/oracle/types/reporter.go index 80573cba22..244d39617e 100644 --- a/chain/x/oracle/types/reporter.go +++ b/chain/x/oracle/types/reporter.go @@ -2,16 +2,16 @@ package types import sdk "github.com/cosmos/cosmos-sdk/types" -// Reporter represents address of reporter and its associated validator -type Reporter struct { - Reporter sdk.AccAddress `json:"reporter" yaml:"reporter"` - Validator sdk.ValAddress `json:"validator" yaml:"validator"` +// ReportersPerValidator represents list of reporter address and their associated validator +type ReportersPerValidator struct { + Validator sdk.ValAddress `json:"validator" yaml:"validator"` + Reporters []sdk.AccAddress `json:"reporters" yaml:"reporter"` } -// NewReporter creates new instance of Reporter -func NewReporter(reporter sdk.AccAddress, validator sdk.ValAddress) Reporter { - return Reporter{ - Reporter: reporter, +// NewReportersPerValidator creates new instance of ReportersPerValidator +func NewReportersPerValidator(validator sdk.ValAddress, reporters []sdk.AccAddress) ReportersPerValidator { + return ReportersPerValidator{ Validator: validator, + Reporters: reporters, } } From 7bdf699b11e282cacaf2d5a365bbaaebbd89e03c Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 19 Apr 2021 12:20:23 +0700 Subject: [PATCH 08/11] Added logs --- chain/app/export.go | 7 ++++++- chain/cmd/bandd/main.go | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/chain/app/export.go b/chain/app/export.go index e196d7bdea..2dba115c61 100644 --- a/chain/app/export.go +++ b/chain/app/export.go @@ -5,6 +5,7 @@ import ( "log" abci "github.com/tendermint/tendermint/abci/types" + tlog "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" @@ -14,20 +15,24 @@ import ( ) // ExportAppStateAndValidators export the state of band for a genesis file -func (app *BandApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string, +func (app *BandApp) ExportAppStateAndValidators(logger tlog.Logger, forZeroHeight bool, jailWhiteList []string, ) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) if forZeroHeight { + logger.Info("Preparing state for zero-height genesis") app.prepForZeroHeightGenesis(ctx, jailWhiteList) } + logger.Info("Begin exporting states from each module") genState := app.mm.ExportGenesis(ctx) + logger.Info("Encode exported states to JSON") appState, err = codec.MarshalJSONIndent(app.cdc, genState) if err != nil { return nil, nil, err } + logger.Info("Writing validators for the genesis") validators = staking.WriteValidators(ctx, app.StakingKeeper) return appState, validators, nil } diff --git a/chain/cmd/bandd/main.go b/chain/cmd/bandd/main.go index 91bb71c3dc..223fd86e36 100644 --- a/chain/cmd/bandd/main.go +++ b/chain/cmd/bandd/main.go @@ -140,17 +140,19 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application func exportAppStateAndTMValidators( logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string, ) (json.RawMessage, []tmtypes.GenesisValidator, error) { + logger.Info("Start exporting genesis file...") if height != -1 { bandApp := app.NewBandApp(logger, db, traceStore, false, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) + logger.Info("Setup store at specific height", "height", height) err := bandApp.LoadHeight(height) if err != nil { return nil, nil, err } - return bandApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) + return bandApp.ExportAppStateAndValidators(logger, forZeroHeight, jailWhiteList) } bandApp := app.NewBandApp(logger, db, traceStore, true, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) - return bandApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) + return bandApp.ExportAppStateAndValidators(logger, forZeroHeight, jailWhiteList) } From e146618c8e6b3825e37e84fbc78d14f66043a735 Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 19 Apr 2021 12:35:58 +0700 Subject: [PATCH 09/11] Add a bunch of logs --- chain/app/export.go | 24 ++++++++++++++++++------ chain/cmd/bandd/main.go | 4 ++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/chain/app/export.go b/chain/app/export.go index 2dba115c61..a47d493215 100644 --- a/chain/app/export.go +++ b/chain/app/export.go @@ -5,7 +5,6 @@ import ( "log" abci "github.com/tendermint/tendermint/abci/types" - tlog "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" @@ -15,24 +14,24 @@ import ( ) // ExportAppStateAndValidators export the state of band for a genesis file -func (app *BandApp) ExportAppStateAndValidators(logger tlog.Logger, forZeroHeight bool, jailWhiteList []string, +func (app *BandApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string, ) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) if forZeroHeight { - logger.Info("Preparing state for zero-height genesis") + ctx.Logger().Info("Preparing state for zero-height genesis") app.prepForZeroHeightGenesis(ctx, jailWhiteList) } - logger.Info("Begin exporting states from each module") + ctx.Logger().Info("Begin exporting states from each module") genState := app.mm.ExportGenesis(ctx) - logger.Info("Encode exported states to JSON") + ctx.Logger().Info("Encode exported states to JSON") appState, err = codec.MarshalJSONIndent(app.cdc, genState) if err != nil { return nil, nil, err } - logger.Info("Writing validators for the genesis") + ctx.Logger().Info("Writing validators for the genesis") validators = staking.WriteValidators(ctx, app.StakingKeeper) return appState, validators, nil } @@ -59,11 +58,13 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st } /* Just to be safe, assert the invariants on current state. */ + ctx.Logger().Info("Asserting invarient") app.CrisisKeeper.AssertInvariants(ctx) /* Handle fee distribution state. */ // withdraw all validator commission + ctx.Logger().Info("Withdraw all validator commission") app.StakingKeeper.IterateValidators(ctx, func(_ int64, val staking.ValidatorI) (stop bool) { accumCommission := app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, val.GetOperator()) if accumCommission.IsZero() { @@ -77,6 +78,7 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st }) // withdraw all delegator rewards + ctx.Logger().Info("Withdraw all delegator rewards") dels := app.StakingKeeper.GetAllDelegations(ctx) for _, delegation := range dels { _, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress) @@ -86,16 +88,20 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st } // clear validator slash events + ctx.Logger().Info("Clear all validator slash events") app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx) // clear validator historical rewards + ctx.Logger().Info("Clear all validator historical rewards") app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx) // set context height to zero + ctx.Logger().Info("Set context height to zero") height := ctx.BlockHeight() ctx = ctx.WithBlockHeight(0) // reinitialize all validators + ctx.Logger().Info("Re-Initialize all validators") app.StakingKeeper.IterateValidators(ctx, func(_ int64, val staking.ValidatorI) (stop bool) { // donate any unwithdrawn outstanding reward fraction tokens to the community pool @@ -109,17 +115,20 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st }) // reinitialize all delegations + ctx.Logger().Info("Re-Initialize all delegations") for _, del := range dels { app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.DelegatorAddress, del.ValidatorAddress) app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.DelegatorAddress, del.ValidatorAddress) } // reset context height + ctx.Logger().Info("Reset context height") ctx = ctx.WithBlockHeight(height) /* Handle staking state. */ // iterate through redelegations, reset creation height + ctx.Logger().Info("Iterate through redelegations, reset creation height") app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red staking.Redelegation) (stop bool) { for i := range red.Entries { red.Entries[i].CreationHeight = 0 @@ -129,6 +138,7 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st }) // iterate through unbonding delegations, reset creation height + ctx.Logger().Info("Iterate through unbonding delegations, reset creation height") app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd staking.UnbondingDelegation) (stop bool) { for i := range ubd.Entries { ubd.Entries[i].CreationHeight = 0 @@ -139,6 +149,7 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st // Iterate through validators by power descending, reset bond heights, and // update bond intra-tx counters. + ctx.Logger().Info("Iterate through validators by power descending, reset bond heights, and update bond intra-tx counters.") store := ctx.KVStore(app.keys[staking.StoreKey]) iter := sdk.KVStoreReversePrefixIterator(store, staking.ValidatorsKey) counter := int16(0) @@ -166,6 +177,7 @@ func (app *BandApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st /* Handle slashing state. */ // reset start height on signing infos + ctx.Logger().Info("Reset start height on signing infos") app.SlashingKeeper.IterateValidatorSigningInfos( ctx, func(addr sdk.ConsAddress, info slashing.ValidatorSigningInfo) (stop bool) { diff --git a/chain/cmd/bandd/main.go b/chain/cmd/bandd/main.go index 223fd86e36..21a99a03c0 100644 --- a/chain/cmd/bandd/main.go +++ b/chain/cmd/bandd/main.go @@ -150,9 +150,9 @@ func exportAppStateAndTMValidators( return nil, nil, err } - return bandApp.ExportAppStateAndValidators(logger, forZeroHeight, jailWhiteList) + return bandApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } bandApp := app.NewBandApp(logger, db, traceStore, true, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) - return bandApp.ExportAppStateAndValidators(logger, forZeroHeight, jailWhiteList) + return bandApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } From 3bcbcac7ee372bdace444978732389ce883ed259 Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 19 Apr 2021 13:44:46 +0700 Subject: [PATCH 10/11] Log to stderr instead --- chain/cmd/bandd/main.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/chain/cmd/bandd/main.go b/chain/cmd/bandd/main.go index 21a99a03c0..9f87117985 100644 --- a/chain/cmd/bandd/main.go +++ b/chain/cmd/bandd/main.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "io" + "os" "path/filepath" "strconv" "strings" @@ -140,11 +141,12 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application func exportAppStateAndTMValidators( logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string, ) (json.RawMessage, []tmtypes.GenesisValidator, error) { - logger.Info("Start exporting genesis file...") + newLogger := log.NewTMLogger(log.NewSyncWriter(os.Stderr)) + newLogger.Info("Start exporting genesis file...") if height != -1 { - bandApp := app.NewBandApp(logger, db, traceStore, false, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) - logger.Info("Setup store at specific height", "height", height) + bandApp := app.NewBandApp(newLogger, db, traceStore, false, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) + newLogger.Info("Setup store at specific height", "height", height) err := bandApp.LoadHeight(height) if err != nil { return nil, nil, err @@ -153,6 +155,6 @@ func exportAppStateAndTMValidators( return bandApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } - bandApp := app.NewBandApp(logger, db, traceStore, true, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) + bandApp := app.NewBandApp(newLogger, db, traceStore, true, uint(1), map[int64]bool{}, "", viper.GetBool(flagDisableFeelessReports), viper.GetUint32(flagWithOwasmCacheSize)) return bandApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } From a7185660da56df4e266fedefd11d9a421c5835ea Mon Sep 17 00:00:00 2001 From: Nathachai Jaiboon Date: Mon, 19 Apr 2021 14:21:16 +0700 Subject: [PATCH 11/11] Typo --- chain/x/oracle/types/reporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/x/oracle/types/reporter.go b/chain/x/oracle/types/reporter.go index 244d39617e..c0d57f453d 100644 --- a/chain/x/oracle/types/reporter.go +++ b/chain/x/oracle/types/reporter.go @@ -5,7 +5,7 @@ import sdk "github.com/cosmos/cosmos-sdk/types" // ReportersPerValidator represents list of reporter address and their associated validator type ReportersPerValidator struct { Validator sdk.ValAddress `json:"validator" yaml:"validator"` - Reporters []sdk.AccAddress `json:"reporters" yaml:"reporter"` + Reporters []sdk.AccAddress `json:"reporters" yaml:"reporters"` } // NewReportersPerValidator creates new instance of ReportersPerValidator