Skip to content

Commit

Permalink
ci(tests): historacle e2e (#1687)
Browse files Browse the repository at this point in the history
* grpc test setup

* add umee client

* UmeeClient updates WIP

* update e2e genesis

* add testing price_store

* price store update

* set chain id

* price feeder gas fix

* update e2e test price feeder config

* fix IBC tests

* check all accepted denom medians

* remove extra prints

* add error

* linter fixes

Co-authored-by: zarazan <zarazan@users.noreply.github.com>
  • Loading branch information
adamewozniak and zarazan committed Jan 6, 2023
1 parent ec76a9d commit 1737cb4
Show file tree
Hide file tree
Showing 11 changed files with 707 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ dist/

# OSX
*.DS_Store

# e2e test keychain folder
tests/e2e/keyring-test
24 changes: 22 additions & 2 deletions tests/e2e/e2e_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
appparams "github.com/umee-network/umee/v3/app/params"
"github.com/umee-network/umee/v3/x/leverage/fixtures"
leveragetypes "github.com/umee-network/umee/v3/x/leverage/types"
oracletypes "github.com/umee-network/umee/v3/x/oracle/types"
)

const (
Expand Down Expand Up @@ -230,6 +231,7 @@ func (s *IntegrationTestSuite) initGenesis() {
appGenState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFilePath)
s.Require().NoError(err)

// Gravity Bridge
var gravityGenState gravitytypes.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[gravitytypes.ModuleName], &gravityGenState))

Expand All @@ -242,12 +244,14 @@ func (s *IntegrationTestSuite) initGenesis() {
var bech32GenState bech32ibctypes.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[bech32ibctypes.ModuleName], &bech32GenState))

// bech32
bech32GenState.NativeHRP = sdk.GetConfig().GetBech32AccountAddrPrefix()

bz, err = cdc.MarshalJSON(&bech32GenState)
s.Require().NoError(err)
appGenState[bech32ibctypes.ModuleName] = bz

// Leverage
var leverageGenState leveragetypes.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[leveragetypes.ModuleName], &leverageGenState))

Expand All @@ -259,6 +263,19 @@ func (s *IntegrationTestSuite) initGenesis() {
s.Require().NoError(err)
appGenState[leveragetypes.ModuleName] = bz

// Oracle
var oracleGenState oracletypes.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[oracletypes.ModuleName], &oracleGenState))

oracleGenState.Params.HistoricStampPeriod = 5
oracleGenState.Params.MaximumPriceStamps = 4
oracleGenState.Params.MedianStampPeriod = 20

bz, err = cdc.MarshalJSON(&oracleGenState)
s.Require().NoError(err)
appGenState[oracletypes.ModuleName] = bz

// Bank
var bankGenState banktypes.GenesisState
s.Require().NoError(cdc.UnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState))

Expand Down Expand Up @@ -657,7 +674,9 @@ func (s *IntegrationTestSuite) runIBCRelayer() {
s.tmpDirs = append(s.tmpDirs, tmpDir)

gaiaVal := s.chain.gaiaValidators[0]
umeeVal := s.chain.validators[0]
// umeeVal for the relayer needs to be a different account
// than what we use for runPriceFeeder.
umeeVal := s.chain.validators[1]
hermesCfgPath := path.Join(tmpDir, "hermes")

s.Require().NoError(os.MkdirAll(hermesCfgPath, 0o755))
Expand Down Expand Up @@ -685,7 +704,7 @@ func (s *IntegrationTestSuite) runIBCRelayer() {
fmt.Sprintf("UMEE_E2E_GAIA_VAL_MNEMONIC=%s", gaiaVal.mnemonic),
fmt.Sprintf("UMEE_E2E_UMEE_VAL_MNEMONIC=%s", umeeVal.mnemonic),
fmt.Sprintf("UMEE_E2E_GAIA_VAL_HOST=%s", s.gaiaResource.Container.Name[1:]),
fmt.Sprintf("UMEE_E2E_UMEE_VAL_HOST=%s", s.valResources[0].Container.Name[1:]),
fmt.Sprintf("UMEE_E2E_UMEE_VAL_HOST=%s", s.valResources[1].Container.Name[1:]),
},
Entrypoint: []string{
"sh",
Expand Down Expand Up @@ -942,6 +961,7 @@ func (s *IntegrationTestSuite) runPriceFeeder() {
fmt.Sprintf("UMEE_E2E_PRICE_FEEDER_ADDRESS=%s", umeeValAddr),
fmt.Sprintf("UMEE_E2E_PRICE_FEEDER_VALIDATOR=%s", sdk.ValAddress(umeeValAddr)),
fmt.Sprintf("UMEE_E2E_UMEE_VAL_HOST=%s", s.valResources[0].Container.Name[1:]),
fmt.Sprintf("UMEE_E2E_CHAIN_ID=%s", s.chain.id),
},
Entrypoint: []string{
"sh",
Expand Down
11 changes: 11 additions & 0 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"

appparams "github.com/umee-network/umee/v3/app/params"
"github.com/umee-network/umee/v3/tests/grpc"
)

func (s *IntegrationTestSuite) TestIBCTokenTransfer() {
Expand Down Expand Up @@ -139,3 +140,13 @@ func (s *IntegrationTestSuite) TestUmeeTokenTransfers() {
s.sendFromEthToUmeeCheck(orchestratorIdxSender, umeeValIdxReceiver, umeeERC20Addr, appparams.BondDenom, amount)
})
}

func (s *IntegrationTestSuite) TestHistorical() {
err := grpc.MedianCheck(
s.chain.id,
"tcp://localhost:26657",
"tcp://localhost:9090",
s.chain.validators[0].mnemonic,
)
s.Require().NoError(err)
}
102 changes: 94 additions & 8 deletions tests/e2e/scripts/price_feeder_bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ touch /root/.price-feeder/config.toml

# setup price-feeder configuration
tee /root/.price-feeder/config.toml <<EOF
gas_adjustment = 1.2
gas_adjustment = 1
provider_timeout = "5000ms"
[server]
Expand All @@ -17,37 +17,123 @@ read_timeout = "20s"
verbose_cors = true
write_timeout = "20s"
[[deviation_thresholds]]
base = "USDT"
threshold = "1.5"
[[deviation_thresholds]]
base = "UMEE"
threshold = "1.5"
[[deviation_thresholds]]
base = "ATOM"
threshold = "1.5"
[[deviation_thresholds]]
base = "USDC"
threshold = "1.5"
[[deviation_thresholds]]
base = "CRO"
threshold = "1.5"
[[deviation_thresholds]]
base = "DAI"
threshold = "2"
[[deviation_thresholds]]
base = "ETH"
threshold = "2"
[[deviation_thresholds]]
base = "WBTC"
threshold = "1.5"
[[currency_pairs]]
base = "UMEE"
providers = [
"mock",
"okx",
"gate",
"mexc",
]
quote = "USDT"
[[currency_pairs]]
base = "USDT"
providers = [
"kraken",
"coinbase",
"binanceus",
]
quote = "USD"
[[currency_pairs]]
base = "ATOM"
providers = [
"okx",
"bitget",
]
quote = "USDT"
[[currency_pairs]]
base = "ATOM"
providers = [
"mock",
"kraken",
]
quote = "USDC"
quote = "USD"
[[currency_pairs]]
base = "USDC"
providers = [
"mock",
"okx",
"bitget",
"kraken",
]
quote = "USDT"
[[currency_pairs]]
base = "DAI"
providers = [
"okx",
"bitget",
"huobi",
]
quote = "USDT"
[[currency_pairs]]
base = "DAI"
providers = [
"kraken",
]
quote = "USD"
[[currency_pairs]]
base = "USDT"
base = "ETH"
providers = [
"okx",
"bitget",
]
quote = "USDT"
[[currency_pairs]]
base = "ETH"
providers = [
"mock",
"kraken",
]
quote = "USD"
[[currency_pairs]]
base = "WBTC"
providers = [
"okx",
"bitget",
"crypto",
]
quote = "USDT"
[account]
address = '$UMEE_E2E_PRICE_FEEDER_ADDRESS'
chain_id = "umee-local-testnet"
chain_id = '$UMEE_E2E_CHAIN_ID'
validator = '$UMEE_E2E_PRICE_FEEDER_VALIDATOR'
[keyring]
Expand Down
112 changes: 112 additions & 0 deletions tests/grpc/chain_height.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package grpc

import (
"context"
"errors"
"sync"

"github.com/rs/zerolog"
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
tmctypes "github.com/tendermint/tendermint/rpc/core/types"
tmtypes "github.com/tendermint/tendermint/types"
)

var (
errParseEventDataNewBlockHeader = errors.New("error parsing EventDataNewBlockHeader")
queryEventNewBlockHeader = tmtypes.QueryForEvent(tmtypes.EventNewBlockHeader)
)

// ChainHeight is used to cache the chain height of the
// current node which is being updated each time the
// node sends an event of EventNewBlockHeader.
// It starts a goroutine to subscribe to blockchain new block event and update the cached height.
type ChainHeight struct {
Logger zerolog.Logger

mtx sync.RWMutex
errGetChainHeight error
lastChainHeight int64
HeightChanged chan (int64)
}

// NewChainHeight returns a new ChainHeight struct that
// starts a new goroutine subscribed to EventNewBlockHeader.
func NewChainHeight(
ctx context.Context,
rpcClient tmrpcclient.Client,
logger zerolog.Logger,
) (*ChainHeight, error) {
if !rpcClient.IsRunning() {
if err := rpcClient.Start(); err != nil {
return nil, err
}
}

newBlockHeaderSubscription, err := rpcClient.Subscribe(
ctx, tmtypes.EventNewBlockHeader, queryEventNewBlockHeader.String())
if err != nil {
return nil, err
}

chainHeight := &ChainHeight{
Logger: logger.With().Str("oracle_client", "chain_height").Logger(),
}
chainHeight.HeightChanged = make(chan int64)

go chainHeight.subscribe(ctx, rpcClient, newBlockHeaderSubscription)

return chainHeight, nil
}

// updateChainHeight receives the data to be updated thread safe.
func (chainHeight *ChainHeight) updateChainHeight(blockHeight int64, err error) {
chainHeight.mtx.Lock()
defer chainHeight.mtx.Unlock()

if chainHeight.lastChainHeight != blockHeight {
select {
case chainHeight.HeightChanged <- blockHeight:
default:
}
}
chainHeight.lastChainHeight = blockHeight
chainHeight.errGetChainHeight = err
}

// subscribe listens to new blocks being made
// and updates the chain height.
func (chainHeight *ChainHeight) subscribe(
ctx context.Context,
eventsClient tmrpcclient.EventsClient,
newBlockHeaderSubscription <-chan tmctypes.ResultEvent,
) {
for {
select {
case <-ctx.Done():
err := eventsClient.Unsubscribe(ctx, tmtypes.EventNewBlockHeader, queryEventNewBlockHeader.String())
if err != nil {
chainHeight.Logger.Err(err)
chainHeight.updateChainHeight(chainHeight.lastChainHeight, err)
}
chainHeight.Logger.Info().Msg("closing the ChainHeight subscription")
return

case resultEvent := <-newBlockHeaderSubscription:
eventDataNewBlockHeader, ok := resultEvent.Data.(tmtypes.EventDataNewBlockHeader)
if !ok {
chainHeight.Logger.Err(errParseEventDataNewBlockHeader)
chainHeight.updateChainHeight(chainHeight.lastChainHeight, errParseEventDataNewBlockHeader)
continue
}
chainHeight.updateChainHeight(eventDataNewBlockHeader.Header.Height, nil)
}
}
}

// GetChainHeight returns the last chain height available.
func (chainHeight *ChainHeight) GetChainHeight() (int64, error) {
chainHeight.mtx.RLock()
defer chainHeight.mtx.RUnlock()

return chainHeight.lastChainHeight, chainHeight.errGetChainHeight
}
34 changes: 34 additions & 0 deletions tests/grpc/grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package grpc

import (
"context"
"net"
"strings"
)

func dialerFunc(_ context.Context, addr string) (net.Conn, error) {
return Connect(addr)
}

// Connect dials the given address and returns a net.Conn. The protoAddr
// argument should be prefixed with the protocol,
// eg. "tcp://127.0.0.1:8080" or "unix:///tmp/test.sock".
func Connect(protoAddr string) (net.Conn, error) {
proto, address := ProtocolAndAddress(protoAddr)
conn, err := net.Dial(proto, address)
return conn, err
}

// ProtocolAndAddress splits an address into the protocol and address components.
// For instance, "tcp://127.0.0.1:8080" will be split into "tcp" and "127.0.0.1:8080".
// If the address has no protocol prefix, the default is "tcp".
func ProtocolAndAddress(listenAddr string) (string, string) {
protocol, address := "tcp", listenAddr

parts := strings.SplitN(address, "://", 2)
if len(parts) == 2 {
protocol, address = parts[0], parts[1]
}

return protocol, address
}

0 comments on commit 1737cb4

Please sign in to comment.