Skip to content
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

Cns 266 remove core.block and use instead blockhash that is saved in storage #281

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cookbook/spec_add_arbitrum.json
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,14 @@
"blocks_in_finalization_proof": 3,
"average_block_time": "500",
"allowed_block_lag_for_qos_sync": "20",
"min_stake_provider": {
"denom": "ulava",
"amount": "1000"
},
"min_stake_client": {
"denom": "ulava",
"amount": "100"
},
"apis": [
{
"name": "rpc_modules",
Expand Down
8 changes: 8 additions & 0 deletions cookbook/spec_add_cosmoshub.json
Original file line number Diff line number Diff line change
Expand Up @@ -5797,6 +5797,14 @@
"blocks_in_finalization_proof": 1,
"average_block_time": "6500",
"allowed_block_lag_for_qos_sync": "10",
"min_stake_provider": {
"denom": "ulava",
"amount": "1000"
},
"min_stake_client": {
"denom": "ulava",
"amount": "100"
},
"apis": [
{
"name": "abci_info",
Expand Down
8 changes: 8 additions & 0 deletions cookbook/spec_add_fantom.json
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,14 @@
"blocks_in_finalization_proof": 1,
"average_block_time": "1500",
"allowed_block_lag_for_qos_sync": "5",
"min_stake_provider": {
"denom": "ulava",
"amount": "1000"
},
"min_stake_client": {
"denom": "ulava",
"amount": "100"
},
"apis": [
{
"name": "web3_clientVersion",
Expand Down
8 changes: 8 additions & 0 deletions cookbook/spec_add_juno.json
Original file line number Diff line number Diff line change
Expand Up @@ -6565,6 +6565,14 @@
"blocks_in_finalization_proof": 1,
"average_block_time": "6500",
"allowed_block_lag_for_qos_sync": "2",
"min_stake_provider": {
"denom": "ulava",
"amount": "1000"
},
"min_stake_client": {
"denom": "ulava",
"amount": "100"
},
"apis": [
{
"name": "abci_info",
Expand Down
8 changes: 8 additions & 0 deletions cookbook/spec_add_osmosis.json
Original file line number Diff line number Diff line change
Expand Up @@ -9565,6 +9565,14 @@
"blocks_in_finalization_proof": 1,
"average_block_time": "6500",
"allowed_block_lag_for_qos_sync": "3",
"min_stake_provider": {
"denom": "ulava",
"amount": "1000"
},
"min_stake_client": {
"denom": "ulava",
"amount": "100"
},
"apis": [
{
"name": "abci_info",
Expand Down
8 changes: 8 additions & 0 deletions cookbook/spec_add_polygon.json
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,14 @@
"blocks_in_finalization_proof": 3,
"average_block_time": "2000",
"allowed_block_lag_for_qos_sync": "30",
"min_stake_provider": {
"denom": "ulava",
"amount": "1000"
},
"min_stake_client": {
"denom": "ulava",
"amount": "100"
},
"apis": [
{
"name": "rpc_modules",
Expand Down
574 changes: 331 additions & 243 deletions docs/static/openapi.yml

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions testutil/keeper/keepers_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"context"
"crypto/rand"
"testing"
"time"

Expand Down Expand Up @@ -32,6 +33,8 @@ import (

const BLOCK_TIME = 30 * time.Second

const BLOCK_HEADER_LEN = 32

type Keepers struct {
Epochstorage epochstoragekeeper.Keeper
Spec speckeeper.Keeper
Expand Down Expand Up @@ -147,6 +150,10 @@ func AdvanceBlock(ctx context.Context, ks *Keepers, customBlockTime ...time.Dura

block := uint64(unwrapedCtx.BlockHeight() + 1)
unwrapedCtx = unwrapedCtx.WithBlockHeight(int64(block))

headerHash := make([]byte, BLOCK_HEADER_LEN)
rand.Read(headerHash)
unwrapedCtx = unwrapedCtx.WithHeaderHash(headerHash)
if len(customBlockTime) > 0 {
NewBlock(sdk.WrapSDKContext(unwrapedCtx), ks, customBlockTime...)
} else {
Expand Down
6 changes: 3 additions & 3 deletions x/epochstorage/keeper/stake_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,13 +470,13 @@ func (k Keeper) GetStakeEntryForAllProvidersEpoch(ctx sdk.Context, chainID strin
return &stakeStorage.StakeEntries, nil
}

func (k Keeper) GetEpochStakeEntries(ctx sdk.Context, block uint64, storageType string, chainID string) (entries []types.StakeEntry, found bool) {
func (k Keeper) GetEpochStakeEntries(ctx sdk.Context, block uint64, storageType string, chainID string) (entries []types.StakeEntry, found bool, epochHash []byte) {
key := k.StakeStorageKey(storageType, block, chainID)
stakeStorage, found := k.GetStakeStorage(ctx, key)
if !found {
return nil, false
return nil, false, nil
}
return stakeStorage.StakeEntries, true
return stakeStorage.StakeEntries, true, stakeStorage.EpochBlockHash
}

// append to epoch stake entries ONLY if it doesn't exist
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/keeper/grpc_query_static_providers_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (k Keeper) StaticProvidersList(goCtx context.Context, req *types.QueryStati
}

epoch := k.epochStorageKeeper.GetEpochStart(ctx)
stakes, found := k.epochStorageKeeper.GetEpochStakeEntries(ctx, epoch, epochstoragetypes.ProviderKey, req.GetChainID())
stakes, found, _ := k.epochStorageKeeper.GetEpochStakeEntries(ctx, epoch, epochstoragetypes.ProviderKey, req.GetChainID())

if !found {
return &types.QueryStaticProvidersListResponse{}, nil
Expand Down
8 changes: 4 additions & 4 deletions x/pairing/keeper/msg_server_stake_unstake_gov_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ func TestStakeGovEpochBlocksDecrease(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {

// check if the provider/client are staked
_, foundProvider := ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ProviderKey, ts.spec.GetIndex())
_, foundProvider, _ := ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ProviderKey, ts.spec.GetIndex())
require.Equal(t, tt.shouldBeStaked, foundProvider)
_, foundClient := ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ClientKey, ts.spec.GetIndex())
_, foundClient, _ := ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ClientKey, ts.spec.GetIndex())
require.Equal(t, tt.shouldBeStaked, foundClient)
})
}
Expand Down Expand Up @@ -173,9 +173,9 @@ func TestStakeGovEpochBlocksIncrease(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {

// check if the provider/client are staked
_, found := ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ProviderKey, ts.spec.GetIndex())
_, found, _ := ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ProviderKey, ts.spec.GetIndex())
require.Equal(t, tt.shouldBeStaked, found)
_, found = ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ClientKey, ts.spec.GetIndex())
_, found, _ = ts.keepers.Epochstorage.GetEpochStakeEntries(sdk.UnwrapSDKContext(ts.ctx), tt.epoch, epochstoragetypes.ClientKey, ts.spec.GetIndex())
require.Equal(t, tt.shouldBeStaked, found)
})
}
Expand Down
25 changes: 9 additions & 16 deletions x/pairing/keeper/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types"
spectypes "github.com/lavanet/lava/x/spec/types"
tendermintcrypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/rpc/core"
)

const INVALID_INDEX = -2
Expand Down Expand Up @@ -48,7 +47,7 @@ func (k Keeper) VerifyPairingData(ctx sdk.Context, chainID string, clientAddress
verifiedUser := false

// we get the user stakeEntries at the time of check. for unstaking users, we make sure users can't unstake sooner than blocksToSave so we can charge them if the pairing is valid
userStakedEntries, found := k.epochStorageKeeper.GetEpochStakeEntries(ctx, requestedEpochStart, epochstoragetypes.ClientKey, chainID)
userStakedEntries, found, _ := k.epochStorageKeeper.GetEpochStakeEntries(ctx, requestedEpochStart, epochstoragetypes.ClientKey, chainID)
if !found {
return nil, utils.LavaError(ctx, logger, "client_entries_pairing", map[string]string{"chainID": chainID, "query Epoch": strconv.FormatUint(requestedEpochStart, 10), "query block": strconv.FormatUint(block, 10), "current epoch": strconv.FormatUint(currentEpochStart, 10)}, "no EpochStakeEntries entries at all for this spec")
}
Expand Down Expand Up @@ -84,12 +83,12 @@ func (k Keeper) GetPairingForClient(ctx sdk.Context, chainID string, clientAddre
return nil, fmt.Errorf("invalid user for pairing: %s", err)
}

possibleProviders, found := k.epochStorageKeeper.GetEpochStakeEntries(ctx, currentEpoch, epochstoragetypes.ProviderKey, chainID)
possibleProviders, found, epochHash := k.epochStorageKeeper.GetEpochStakeEntries(ctx, currentEpoch, epochstoragetypes.ProviderKey, chainID)
if !found {
return nil, fmt.Errorf("did not find providers for pairing: epoch:%d, chainID: %s", currentEpoch, chainID)
}

providers, _, errorRet = k.calculatePairingForClient(ctx, possibleProviders, clientAddress, currentEpoch, chainID, clientStakeEntry.Geolocation)
providers, _, errorRet = k.calculatePairingForClient(ctx, possibleProviders, clientAddress, currentEpoch, chainID, clientStakeEntry.Geolocation, epochHash)

return
}
Expand All @@ -107,12 +106,12 @@ func (k Keeper) ValidatePairingForClient(ctx sdk.Context, chainID string, client
return false, nil, INVALID_INDEX, fmt.Errorf("invalid user for pairing: %s", err)
}

providerStakeEntries, found := k.epochStorageKeeper.GetEpochStakeEntries(ctx, epochStart, epochstoragetypes.ProviderKey, chainID)
providerStakeEntries, found, blockHash := k.epochStorageKeeper.GetEpochStakeEntries(ctx, epochStart, epochstoragetypes.ProviderKey, chainID)
if !found {
return false, nil, INVALID_INDEX, fmt.Errorf("could not get provider epoch stake entries for: %d, %s", epochStart, chainID)
}

_, validAddresses, errorRet := k.calculatePairingForClient(ctx, providerStakeEntries, clientAddress, epochStart, chainID, userStake.Geolocation)
_, validAddresses, errorRet := k.calculatePairingForClient(ctx, providerStakeEntries, clientAddress, epochStart, chainID, userStake.Geolocation, blockHash)
if errorRet != nil {
return false, nil, INVALID_INDEX, errorRet
}
Expand All @@ -124,7 +123,7 @@ func (k Keeper) ValidatePairingForClient(ctx sdk.Context, chainID string, client
return false, userStake, INVALID_INDEX, nil
}

func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, clientAddress sdk.AccAddress, epochStartBlock uint64, chainID string, geolocation uint64) (validProviders []epochstoragetypes.StakeEntry, addrList []sdk.AccAddress, err error) {
func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstoragetypes.StakeEntry, clientAddress sdk.AccAddress, epochStartBlock uint64, chainID string, geolocation uint64, epochHash []byte) (validProviders []epochstoragetypes.StakeEntry, addrList []sdk.AccAddress, err error) {
if epochStartBlock > uint64(ctx.BlockHeight()) {
k.Logger(ctx).Error("\ninvalid session start\n")
panic(fmt.Sprintf("invalid session start saved in keeper %d, current block was %d", epochStartBlock, uint64(ctx.BlockHeight())))
Expand All @@ -145,7 +144,7 @@ func (k Keeper) calculatePairingForClient(ctx sdk.Context, providers []epochstor
if spec.ProvidersTypes == spectypes.Spec_dynamic {
// calculates a hash and randomly chooses the providers

validProviders = k.returnSubsetOfProvidersByStake(ctx, clientAddress, validProviders, servicersToPairCount, epochStartBlock, chainID)
validProviders = k.returnSubsetOfProvidersByStake(ctx, clientAddress, validProviders, servicersToPairCount, epochStartBlock, chainID, epochHash)
} else {
validProviders = k.returnSubsetOfProvidersByHighestStake(ctx, validProviders, servicersToPairCount)
}
Expand Down Expand Up @@ -181,7 +180,7 @@ func (k Keeper) getGeolocationProviders(ctx sdk.Context, providers []epochstorag
}

// this function randomly chooses count providers by weight
func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, clientAddress sdk.AccAddress, providersMaps []epochstoragetypes.StakeEntry, count uint64, block uint64, chainID string) (returnedProviders []epochstoragetypes.StakeEntry) {
func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, clientAddress sdk.AccAddress, providersMaps []epochstoragetypes.StakeEntry, count uint64, block uint64, chainID string, epochHash []byte) (returnedProviders []epochstoragetypes.StakeEntry) {
stakeSum := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(0))
hashData := make([]byte, 0)
for _, stakedProvider := range providersMaps {
Expand All @@ -193,13 +192,7 @@ func (k Keeper) returnSubsetOfProvidersByStake(ctx sdk.Context, clientAddress sd
}

// add the session start block hash to the function to make it as unpredictable as we can
block_height := int64(block)
epochStartBlock, err := core.Block(nil, &block_height)
if err != nil {
k.Logger(ctx).Error("Failed To Get block from tendermint core")
}
sessionBlockHash := epochStartBlock.Block.Hash()
hashData = append(hashData, sessionBlockHash...)
hashData = append(hashData, epochHash...)
hashData = append(hashData, chainID...) // to make this pairing unique per chainID
hashData = append(hashData, clientAddress...) // to make this pairing unique per consumer

Expand Down
12 changes: 12 additions & 0 deletions x/pairing/keeper/pairing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func TestPairingUniqueness(t *testing.T) {

ctx = testkeeper.AdvanceEpoch(ctx, keepers)

// test that 2 different clients get different pairings
providers1, err := keepers.Pairing.GetPairingForClient(sdk.UnwrapSDKContext(ctx), spec.Index, consumer1.Addr)
require.Nil(t, err)

Expand All @@ -62,6 +63,17 @@ func TestPairingUniqueness(t *testing.T) {

require.True(t, diffrent)

ctx = testkeeper.AdvanceEpoch(ctx, keepers)

// test that in different epoch we get different pairings for consumer1
providers11, err := keepers.Pairing.GetPairingForClient(sdk.UnwrapSDKContext(ctx), spec.Index, consumer1.Addr)
require.Nil(t, err)

require.Equal(t, len(providers1), len(providers11))
for i := range providers1 {
require.NotEqual(t, providers1[i].Address, providers11[i].Address)
Yaroms marked this conversation as resolved.
Show resolved Hide resolved
}

}

// Test that verifies that new get-pairing return values (CurrentEpoch, TimeLeftToNextPairing, SpecLastUpdatedBlock) is working properly
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type EpochstorageKeeper interface {
GetStakeEntryByAddressCurrent(ctx sdk.Context, storageType string, chainID string, address sdk.AccAddress) (value epochstoragetypes.StakeEntry, found bool, index uint64)
UnstakeEntryByAddress(ctx sdk.Context, storageType string, address sdk.AccAddress) (value epochstoragetypes.StakeEntry, found bool, index uint64)
GetStakeStorageCurrent(ctx sdk.Context, storageType string, chainID string) (epochstoragetypes.StakeStorage, bool)
GetEpochStakeEntries(ctx sdk.Context, block uint64, storageType string, chainID string) (entries []epochstoragetypes.StakeEntry, found bool)
GetEpochStakeEntries(ctx sdk.Context, block uint64, storageType string, chainID string) (entries []epochstoragetypes.StakeEntry, found bool, epochHash []byte)
GetStakeEntryByAddressFromStorage(ctx sdk.Context, stakeStorage epochstoragetypes.StakeStorage, address sdk.AccAddress) (value epochstoragetypes.StakeEntry, found bool, index uint64)
GetNextEpoch(ctx sdk.Context, block uint64) (nextEpoch uint64, erro error)
GetStakeEntryForClientEpoch(ctx sdk.Context, chainID string, selectedClient sdk.AccAddress, epoch uint64) (entry *epochstoragetypes.StakeEntry, err error)
Expand Down