-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ADR 17 Implementation: Historical Module #5380
Changes from 6 commits
17fcad3
5f916a4
2b052b4
481ee0d
954c8b1
da266e8
813c634
5c634a3
33154f0
aa34dc7
fb2e660
d0e8d88
5997e15
82d386f
a45a5fa
ef43df5
093dcf5
c3fc30b
e4d2c34
74b3f19
73cbb7e
277054b
a61d28a
1fdc269
3f59d8c
9364ba4
c0f2ac7
4402252
c3ad793
b1a9ac5
ffc64bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package staking | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/x/staking/types" | ||
) | ||
|
||
// BeginBlocker will persist the current header and validator set as a historical entry | ||
// and prune the oldest entry based on the HistoricalEntries parameter | ||
func BeginBlocker(ctx sdk.Context, k Keeper) { | ||
entryNum := k.HistoricalEntries(ctx) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Best to move this entire block into a method on the keeper.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Open to doing this here, but what i have follows the pattern of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They should be updated as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about the EndBlocker? Since that isn't a method on the keeper either? |
||
// if there is no need to persist historicalInfo, return | ||
if entryNum == 0 { | ||
return | ||
} | ||
|
||
// Create HistoricalInfo struct | ||
lastVals := k.GetLastValidators(ctx) | ||
types.Validators(lastVals).Sort() | ||
historicalEntry := types.HistoricalInfo{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, the validation (+ panic on error) is missing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't know if validation here is necessary. Validation is true by construction, so long as Tendermint consensus is working correctly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where is the validation used then? |
||
Header: ctx.BlockHeader(), | ||
ValSet: lastVals, | ||
} | ||
|
||
// Set latest HistoricalInfo at current height | ||
k.SetHistoricalInfo(ctx, ctx.BlockHeight(), historicalEntry) | ||
|
||
// prune store to ensure we only have parameter-defined historical entries | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ctx.BlockHeight() > int64(entryNum) { | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
k.DeleteHistoricalInfo(ctx, ctx.BlockHeight()-int64(entryNum)) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package staking | ||
|
||
import ( | ||
"sort" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/x/staking/keeper" | ||
"github.com/cosmos/cosmos-sdk/x/staking/types" | ||
abci "github.com/tendermint/tendermint/abci/types" | ||
) | ||
|
||
func TestBeginBlocker(t *testing.T) { | ||
ctx, _, k, _ := keeper.CreateTestInput(t, false, 10) | ||
|
||
// set historical entries in params to 5 | ||
params := types.DefaultParams() | ||
params.HistoricalEntries = 5 | ||
k.SetParams(ctx, params) | ||
|
||
// set historical info at 5 which should be pruned | ||
header := abci.Header{ | ||
ChainID: "HelloChain", | ||
Height: 5, | ||
} | ||
valSet := []Validator{ | ||
types.NewValidator(sdk.ValAddress(keeper.Addrs[0]), keeper.PKs[0], types.Description{}), | ||
types.NewValidator(sdk.ValAddress(keeper.Addrs[1]), keeper.PKs[1], types.Description{}), | ||
} | ||
hi5 := types.NewHistoricalInfo(header, valSet) | ||
k.SetHistoricalInfo(ctx, 5, hi5) | ||
recv, found := k.GetHistoricalInfo(ctx, 5) | ||
require.True(t, found) | ||
require.Equal(t, hi5, recv) | ||
|
||
// Set last validators in keeper | ||
val1 := types.NewValidator(sdk.ValAddress(keeper.Addrs[2]), keeper.PKs[2], types.Description{}) | ||
k.SetValidator(ctx, val1) | ||
k.SetLastValidatorPower(ctx, val1.OperatorAddress, 10) | ||
val2 := types.NewValidator(sdk.ValAddress(keeper.Addrs[3]), keeper.PKs[3], types.Description{}) | ||
vals := []types.Validator{val1, val2} | ||
sort.Sort(types.Validators(vals)) | ||
k.SetValidator(ctx, val2) | ||
k.SetLastValidatorPower(ctx, val2.OperatorAddress, 8) | ||
|
||
// Set Header for BeginBlock context | ||
header = abci.Header{ | ||
ChainID: "HelloChain", | ||
Height: 10, | ||
} | ||
ctx = ctx.WithBlockHeader(header) | ||
|
||
BeginBlocker(ctx, k) | ||
|
||
// Check HistoricalInfo at height 10 is persisted | ||
expected := types.HistoricalInfo{ | ||
Header: header, | ||
ValSet: vals, | ||
} | ||
recv, found = k.GetHistoricalInfo(ctx, 10) | ||
require.True(t, found, "GetHistoricalInfo failed after BeginBlock") | ||
require.Equal(t, expected, recv, "GetHistoricalInfo returned eunexpected result") | ||
|
||
// Check HistoricalInfo at height 5 is pruned | ||
recv, found = k.GetHistoricalInfo(ctx, 5) | ||
require.False(t, found, "GetHistoricalInfo did not prune") | ||
require.Equal(t, types.HistoricalInfo{}, recv, "GetHistoricalInfo is not empty after prune") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package keeper | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/x/staking/types" | ||
) | ||
|
||
// GetHistoricalInfo gets the historical info at a given height | ||
func (k Keeper) GetHistoricalInfo(ctx sdk.Context, height int64) (hi types.HistoricalInfo, found bool) { | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
store := ctx.KVStore(k.storeKey) | ||
key := types.GetHistoricalInfoKey(height) | ||
|
||
value := store.Get(key) | ||
|
||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if value == nil { | ||
return types.HistoricalInfo{}, false | ||
} | ||
|
||
hi = types.MustUnmarshalHistoricalInfo(k.cdc, value) | ||
return hi, true | ||
} | ||
|
||
// SetHistoricalInfo sets the historical info at a given height | ||
func (k Keeper) SetHistoricalInfo(ctx sdk.Context, height int64, hi types.HistoricalInfo) { | ||
store := ctx.KVStore(k.storeKey) | ||
key := types.GetHistoricalInfoKey(height) | ||
|
||
value := types.MustMarshalHistoricalInfo(k.cdc, hi) | ||
store.Set(key, value) | ||
} | ||
|
||
// DeleteHistoricalInfo deletes the historical info at a given height | ||
func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) { | ||
store := ctx.KVStore(k.storeKey) | ||
key := types.GetHistoricalInfoKey(height) | ||
|
||
store.Delete(key) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package keeper | ||
|
||
import ( | ||
"sort" | ||
"testing" | ||
|
||
"github.com/cosmos/cosmos-sdk/x/staking/types" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestHistoricalInfo(t *testing.T) { | ||
ctx, _, keeper, _ := CreateTestInput(t, false, 10) | ||
var validators []types.Validator | ||
AdityaSripal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
for i, valAddr := range addrVals { | ||
validators = append(validators, types.NewValidator(valAddr, PKs[i], types.Description{})) | ||
} | ||
|
||
hi := types.NewHistoricalInfo(ctx.BlockHeader(), validators) | ||
|
||
keeper.SetHistoricalInfo(ctx, 2, hi) | ||
|
||
recv, found := keeper.GetHistoricalInfo(ctx, 2) | ||
require.True(t, found, "HistoricalInfo not found after set") | ||
require.Equal(t, hi, recv, "HistoricalInfo not equal") | ||
require.True(t, sort.IsSorted(types.Validators(recv.ValSet)), "HistoricalInfo validators is not sorted") | ||
|
||
keeper.DeleteHistoricalInfo(ctx, 2) | ||
|
||
recv, found = keeper.GetHistoricalInfo(ctx, 2) | ||
require.False(t, found, "HistoricalInfo found after delete") | ||
require.Equal(t, types.HistoricalInfo{}, recv, "HistoricalInfo is not empty") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,14 +14,15 @@ type CodeType = sdk.CodeType | |
const ( | ||
DefaultCodespace sdk.CodespaceType = ModuleName | ||
|
||
CodeInvalidValidator CodeType = 101 | ||
CodeInvalidDelegation CodeType = 102 | ||
CodeInvalidInput CodeType = 103 | ||
CodeValidatorJailed CodeType = 104 | ||
CodeInvalidAddress CodeType = sdk.CodeInvalidAddress | ||
CodeUnauthorized CodeType = sdk.CodeUnauthorized | ||
CodeInternal CodeType = sdk.CodeInternal | ||
CodeUnknownRequest CodeType = sdk.CodeUnknownRequest | ||
CodeInvalidValidator CodeType = 101 | ||
CodeInvalidDelegation CodeType = 102 | ||
CodeInvalidInput CodeType = 103 | ||
CodeValidatorJailed CodeType = 104 | ||
CodeInvalidHistoricalInfo CodeType = 105 | ||
CodeInvalidAddress CodeType = sdk.CodeInvalidAddress | ||
CodeUnauthorized CodeType = sdk.CodeUnauthorized | ||
CodeInternal CodeType = sdk.CodeInternal | ||
CodeUnknownRequest CodeType = sdk.CodeUnknownRequest | ||
) | ||
|
||
//validator | ||
|
@@ -212,3 +213,11 @@ func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { | |
func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { | ||
return sdk.NewError(codespace, CodeInvalidValidator, "missing signature") | ||
} | ||
|
||
func ErrInvalidHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, godocs |
||
return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "invalid historical info") | ||
} | ||
|
||
func ErrNoHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { | ||
return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "no historical info found") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A single changelog entry should be made with bullet points if need be.