From d31c071a782d59d3de0946729c710c70b4dc5f6d Mon Sep 17 00:00:00 2001 From: georgiypetrov Date: Wed, 25 Sep 2024 16:21:55 +0400 Subject: [PATCH 1/2] fix vote extension --- x/symGenutil/gentx.go | 6 +- x/symGenutil/types/expected_keepers.go | 9 +- x/symStaking/abci/proposal.go | 45 ++------- x/symStaking/keeper/keeper.go | 4 +- x/symStaking/keeper/symbiotic_state_change.go | 95 ++++++++++++++++--- x/symStaking/keeper/val_state_change.go | 3 + x/symStaking/types/api_urls.go | 4 +- 7 files changed, 102 insertions(+), 64 deletions(-) diff --git a/x/symGenutil/gentx.go b/x/symGenutil/gentx.go index 575e939b1..793f71bdb 100644 --- a/x/symGenutil/gentx.go +++ b/x/symGenutil/gentx.go @@ -111,9 +111,7 @@ func DeliverGenTxs( } } - if err := stakingKeeper.SymbioticUpdateValidatorsPower(ctx, initBlockHash); err != nil { - return nil, fmt.Errorf("failed to update symbiotic validators power: %w", err) - } + stakingKeeper.CacheBlockHash(initBlockHash, 0) - return stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + return stakingKeeper.BlockValidatorUpdates(ctx) } diff --git a/x/symGenutil/types/expected_keepers.go b/x/symGenutil/types/expected_keepers.go index b7df82b22..6d5eb8318 100644 --- a/x/symGenutil/types/expected_keepers.go +++ b/x/symGenutil/types/expected_keepers.go @@ -2,10 +2,9 @@ package types import ( "context" - "encoding/json" - "github.com/cosmos/cosmos-sdk/types/module" - + "cosmossdk.io/core/appmodule" bankexported "cosmossdk.io/x/bank/exported" + "encoding/json" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,8 +12,8 @@ import ( // StakingKeeper defines the expected staking keeper (noalias) type StakingKeeper interface { - SymbioticUpdateValidatorsPower(ctx context.Context, blockHash string) error - ApplyAndReturnValidatorSetUpdates(context.Context) (updates []module.ValidatorUpdate, err error) + CacheBlockHash(blockHash string, height int64) + BlockValidatorUpdates(ctx context.Context) ([]appmodule.ValidatorUpdate, error) } // AccountKeeper defines the expected account keeper (noalias) diff --git a/x/symStaking/abci/proposal.go b/x/symStaking/abci/proposal.go index be50809a9..f6fa6f981 100644 --- a/x/symStaking/abci/proposal.go +++ b/x/symStaking/abci/proposal.go @@ -6,16 +6,8 @@ import ( "cosmossdk.io/x/symStaking/types" "encoding/json" "errors" - "fmt" abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - "time" -) - -const ( - SYMBIOTIC_SYNC_PERIOD = 10 - SLEEP_ON_RETRY = 200 - RETRIES = 5 ) type ProposalHandler struct { @@ -33,17 +25,7 @@ func NewProposalHandler(logger log.Logger, keeper *keeper2.Keeper) *ProposalHand func (h *ProposalHandler) PrepareProposal() sdk.PrepareProposalHandler { return func(ctx sdk.Context, req *abci.PrepareProposalRequest) (*abci.PrepareProposalResponse, error) { - var err error - var resp *abci.PrepareProposalResponse - - for i := 0; i < RETRIES; i++ { - resp, err = h.internalPrepareProposal(ctx, req) - if err == nil { - break - } - time.Sleep(time.Millisecond * SLEEP_ON_RETRY) - } - + resp, err := h.internalPrepareProposal(ctx, req) if err != nil { panic(errors.Join(types.ErrSymbioticValUpdate, err)) } @@ -53,18 +35,8 @@ func (h *ProposalHandler) PrepareProposal() sdk.PrepareProposalHandler { } func (h *ProposalHandler) PreBlocker() sdk.PreBlocker { - return func(context sdk.Context, req *abci.FinalizeBlockRequest) error { - var err error - - for i := 0; i < RETRIES; i++ { - err = h.internalPreBlocker(context, req) - if err == nil { - break - } - time.Sleep(time.Millisecond * SLEEP_ON_RETRY) - } - - if err != nil { + return func(ctx sdk.Context, req *abci.FinalizeBlockRequest) error { + if err := h.internalPreBlocker(ctx, req); err != nil { panic(errors.Join(types.ErrSymbioticValUpdate, err)) } @@ -75,7 +47,7 @@ func (h *ProposalHandler) PreBlocker() sdk.PreBlocker { func (h *ProposalHandler) internalPrepareProposal(ctx sdk.Context, req *abci.PrepareProposalRequest) (*abci.PrepareProposalResponse, error) { proposalTxs := req.Txs - if req.Height%SYMBIOTIC_SYNC_PERIOD != 0 { + if req.Height%keeper2.SYMBIOTIC_SYNC_PERIOD != 0 { return &abci.PrepareProposalResponse{ Txs: proposalTxs, }, nil @@ -103,7 +75,7 @@ func (h *ProposalHandler) internalPrepareProposal(ctx sdk.Context, req *abci.Pre } func (h *ProposalHandler) internalPreBlocker(context sdk.Context, req *abci.FinalizeBlockRequest) error { - if req.Height%SYMBIOTIC_SYNC_PERIOD != 0 || len(req.Txs) == 0 { + if req.Height%keeper2.SYMBIOTIC_SYNC_PERIOD != 0 || len(req.Txs) == 0 { return nil } @@ -118,12 +90,11 @@ func (h *ProposalHandler) internalPreBlocker(context sdk.Context, req *abci.Fina } if block.Time() < h.prevBlockTime || int64(block.Time()) >= context.HeaderInfo().Time.Unix() || block.Time() < h.keeper.GetMinBlockTimestamp(context) { - return fmt.Errorf("symbiotic invalid proposed block") + h.keeper.CacheBlockHash(keeper2.INVALID_BLOCKHASH, req.Height) + return nil } - if err := h.keeper.SymbioticUpdateValidatorsPower(context, blockHash); err != nil { - return err - } + h.keeper.CacheBlockHash(blockHash, req.Height) h.prevBlockTime = block.Time() diff --git a/x/symStaking/keeper/keeper.go b/x/symStaking/keeper/keeper.go index a0addb119..9a1f6e257 100644 --- a/x/symStaking/keeper/keeper.go +++ b/x/symStaking/keeper/keeper.go @@ -49,8 +49,9 @@ type Keeper struct { validatorAddressCodec addresscodec.Codec consensusAddressCodec addresscodec.Codec cometInfoService comet.Service - apiUrls *types.ApiUrls + apiUrls types.ApiUrls networkMiddlewareAddress string + cachedBlockHash CachedBlockHash Schema collections.Schema @@ -110,6 +111,7 @@ func NewKeeper( consensusAddressCodec: consensusAddressCodec, cometInfoService: cometInfoService, apiUrls: types.NewApiUrls(), + cachedBlockHash: CachedBlockHash{}, networkMiddlewareAddress: networkMiddlewareAddress, LastTotalPower: collections.NewItem(sb, types.LastTotalPowerKey, "last_total_power", sdk.IntValue), HistoricalInfo: collections.NewMap(sb, types.HistoricalInfoKey, "historical_info", collections.Uint64Key, HistoricalInfoCodec(cdc)), diff --git a/x/symStaking/keeper/symbiotic_state_change.go b/x/symStaking/keeper/symbiotic_state_change.go index 56d1a55f0..8efd8a5af 100644 --- a/x/symStaking/keeper/symbiotic_state_change.go +++ b/x/symStaking/keeper/symbiotic_state_change.go @@ -17,6 +17,7 @@ import ( "net/http" "strconv" "strings" + "time" ) // Struct to unmarshal the response from the Beacon Chain API @@ -56,10 +57,19 @@ type Validator struct { ConsAddr [32]byte } +type CachedBlockHash struct { + BlockHash string + Height int64 +} + const ( + SYMBIOTIC_SYNC_PERIOD = 10 + SLEEP_ON_RETRY = 200 + RETRIES = 5 BEACON_GENESIS_TIMESTAMP = 1695902400 SLOTS_IN_EPOCH = 32 SLOT_DURATION = 12 + INVALID_BLOCKHASH = "invalid" BLOCK_PATH = "/eth/v2/beacon/blocks/" GET_VALIDATOR_SET_FUNCTION_NAME = "getValidatorSet" GET_CURRENT_EPOCH_FUNCTION_NAME = "getCurrentEpoch" @@ -110,15 +120,41 @@ const ( ]` ) -func (k Keeper) SymbioticUpdateValidatorsPower(ctx context.Context, blockHash string) error { +func (k *Keeper) CacheBlockHash(blockHash string, height int64) { + k.cachedBlockHash.BlockHash = blockHash + k.cachedBlockHash.Height = height +} + +func (k Keeper) SymbioticUpdateValidatorsPower(ctx context.Context) error { if k.networkMiddlewareAddress == "" { panic("middleware address is not set") } - validators, err := k.getSymbioticValidatorSet(ctx, blockHash) - if err != nil { + height := k.HeaderService.HeaderInfo(ctx).Height + + if height%SYMBIOTIC_SYNC_PERIOD != 0 { + return nil + } + + if k.cachedBlockHash.Height != height { + return fmt.Errorf("symbiotic no blockhash cache, actual cached height %v, expected %v", k.cachedBlockHash.Height, height) + } + + if k.cachedBlockHash.BlockHash == INVALID_BLOCKHASH { + return nil + } + + var validators []Validator + var err error + + for i := 0; i < RETRIES; i++ { + validators, err = k.getSymbioticValidatorSet(ctx, k.cachedBlockHash.BlockHash) + if err == nil { + break + } + k.apiUrls.RotateEthUrl() - return err + time.Sleep(time.Millisecond * SLEEP_ON_RETRY) } for _, v := range validators { @@ -137,19 +173,33 @@ func (k Keeper) SymbioticUpdateValidatorsPower(ctx context.Context, blockHash st } func (k Keeper) GetFinalizedBlockHash(ctx context.Context) (string, error) { - slot := k.getSlot(ctx) - block, err := k.parseBlock(slot) - for errors.Is(err, stakingtypes.ErrSymbioticNotFound) { // some slots on api may be omitted - for i := 1; i < SLOTS_IN_EPOCH; i++ { - block, err = k.parseBlock(slot + i) - if err == nil { - break - } - if !errors.Is(err, stakingtypes.ErrSymbioticNotFound) { - return "", err + var err error + var block Block + + for i := 0; i < RETRIES; i++ { + slot := k.getSlot(ctx) + block, err = k.parseBlock(slot) + + for errors.Is(err, stakingtypes.ErrSymbioticNotFound) { // some slots on api may be omitted + for i := 1; i < SLOTS_IN_EPOCH; i++ { + block, err = k.parseBlock(slot + i) + if err == nil { + break + } + if !errors.Is(err, stakingtypes.ErrSymbioticNotFound) { + return "", err + } } } + + if err == nil { + break + } + + k.apiUrls.RotateBeaconUrl() + time.Sleep(time.Millisecond * SLEEP_ON_RETRY) } + if err != nil { return "", err } @@ -158,13 +208,28 @@ func (k Keeper) GetFinalizedBlockHash(ctx context.Context) (string, error) { } func (k Keeper) GetBlockByHash(ctx context.Context, blockHash string) (*types.Block, error) { + var block *types.Block client, err := ethclient.Dial(k.apiUrls.GetEthApiUrl()) if err != nil { return nil, err } defer client.Close() - return client.BlockByHash(ctx, common.HexToHash(blockHash)) + for i := 0; i < RETRIES; i++ { + block, err = client.BlockByHash(ctx, common.HexToHash(blockHash)) + if err == nil { + break + } + + k.apiUrls.RotateEthUrl() + time.Sleep(time.Millisecond * SLEEP_ON_RETRY) + } + + if err != nil { + return nil, err + } + + return block, nil } func (k Keeper) GetMinBlockTimestamp(ctx context.Context) uint64 { diff --git a/x/symStaking/keeper/val_state_change.go b/x/symStaking/keeper/val_state_change.go index 8d59fa818..e93ed614b 100644 --- a/x/symStaking/keeper/val_state_change.go +++ b/x/symStaking/keeper/val_state_change.go @@ -21,6 +21,9 @@ import ( func (k Keeper) BlockValidatorUpdates(ctx context.Context) ([]appmodule.ValidatorUpdate, error) { // Calculate validator set changes. // + if err := k.SymbioticUpdateValidatorsPower(ctx); err != nil { + panic(errors.Join(types.ErrSymbioticValUpdate, err)) + } // NOTE: ApplyAndReturnValidatorSetUpdates has to come before // UnbondAllMatureValidatorQueue. // This fixes a bug when the unbonding period is instant (is the case in diff --git a/x/symStaking/types/api_urls.go b/x/symStaking/types/api_urls.go index 5f16b3e7f..192432d5c 100644 --- a/x/symStaking/types/api_urls.go +++ b/x/symStaking/types/api_urls.go @@ -12,7 +12,7 @@ type ApiUrls struct { currentEthId int } -func NewApiUrls() *ApiUrls { +func NewApiUrls() ApiUrls { // USE ONLY YOUR LOCAL BEACON CLIENT FOR SAFETY!!! beaconApiUrls := strings.Split(os.Getenv("BEACON_API_URLS"), ",") if len(beaconApiUrls) == 1 && beaconApiUrls[0] == "" { @@ -31,7 +31,7 @@ func NewApiUrls() *ApiUrls { ethApiUrls = append(ethApiUrls, "https://holesky.gateway.tenderly.co") } - return &ApiUrls{beaconApiUrls: beaconApiUrls, ethApiUrls: ethApiUrls} + return ApiUrls{beaconApiUrls: beaconApiUrls, ethApiUrls: ethApiUrls} } func (au ApiUrls) GetEthApiUrl() string { From 0da4c1a5331ca5d2f45ddca1300bd62ea5db27ba Mon Sep 17 00:00:00 2001 From: georgiypetrov Date: Wed, 25 Sep 2024 16:23:43 +0400 Subject: [PATCH 2/2] fix make keeper ref --- x/symStaking/keeper/symbiotic_state_change.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/symStaking/keeper/symbiotic_state_change.go b/x/symStaking/keeper/symbiotic_state_change.go index 8efd8a5af..103604452 100644 --- a/x/symStaking/keeper/symbiotic_state_change.go +++ b/x/symStaking/keeper/symbiotic_state_change.go @@ -125,7 +125,7 @@ func (k *Keeper) CacheBlockHash(blockHash string, height int64) { k.cachedBlockHash.Height = height } -func (k Keeper) SymbioticUpdateValidatorsPower(ctx context.Context) error { +func (k *Keeper) SymbioticUpdateValidatorsPower(ctx context.Context) error { if k.networkMiddlewareAddress == "" { panic("middleware address is not set") } @@ -172,7 +172,7 @@ func (k Keeper) SymbioticUpdateValidatorsPower(ctx context.Context) error { return nil } -func (k Keeper) GetFinalizedBlockHash(ctx context.Context) (string, error) { +func (k *Keeper) GetFinalizedBlockHash(ctx context.Context) (string, error) { var err error var block Block @@ -207,7 +207,7 @@ func (k Keeper) GetFinalizedBlockHash(ctx context.Context) (string, error) { return block.Data.Message.Body.ExecutionPayload.BlockHash, nil } -func (k Keeper) GetBlockByHash(ctx context.Context, blockHash string) (*types.Block, error) { +func (k *Keeper) GetBlockByHash(ctx context.Context, blockHash string) (*types.Block, error) { var block *types.Block client, err := ethclient.Dial(k.apiUrls.GetEthApiUrl()) if err != nil {