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

fix: remove domain overwrite on simple redirects #977

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
32 changes: 6 additions & 26 deletions src/controllers/v1.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { PocketRelayer } from '../services/pocket-relayer'
import { SyncChecker } from '../services/sync-checker'
import { checkWhitelist, RateLimiter, shouldRateLimit } from '../utils/enforcements'
import { parseRawData, parseRPCID } from '../utils/parsing'
import { getBlockchainAliasesByDomain, loadBlockchain } from '../utils/relayer'
import { loadBlockchain } from '../utils/relayer'
import { SendRelayOptions } from '../utils/types'
const logger = require('../services/logger')

Expand Down Expand Up @@ -140,25 +140,6 @@ export class V1Controller {

rpcID = parseRPCID(parsedRawData)

const [blockchainRequest] = this.host.split('.')

logger.log('info', `PUBLIC RPC RELAY REDIRECTED FOR ${blockchainRequest}`, {
requestBody: parsedRawData,
blockchainSubdomain: blockchainRequest,
})

// Since we only have non-gateway url, let's fetch a blockchain that contains this domain
const { blockchainAliases } = await getBlockchainAliasesByDomain(
this.host,
this.cache,
this.blockchainsRepository,
rpcID
)

// Any alias works to load a specific blockchain
// TODO: Move URL to ENV
this.host = `${blockchainAliases[0]}.gateway.pokt.network`

const { blockchainRedirects, blockchainPath } = await loadBlockchain(
this.host,
this.cache,
Expand All @@ -169,10 +150,6 @@ export class V1Controller {

for (const redirect of blockchainRedirects) {
if (this.pocketRelayer.host.toLowerCase().includes(redirect.domain)) {
// Modify the host using the stored blockchain name in DB
this.pocketRelayer.host = redirect.alias
this.host = redirect.alias

// convert the slashes to tildes for processing in the loadBalancerRelay route
const lbID = `${redirect.loadBalancerID}${blockchainPath}`.replace(/\//gi, '~')

Expand Down Expand Up @@ -280,7 +257,7 @@ export class V1Controller {
if (!loadBalancer?.id) {
throw new ErrorObject(
reqRPCID,
new jsonrpc.JsonRpcError(`GS (${redirect.alias}) load balancer not found`, -32054)
new jsonrpc.JsonRpcError(`${redirect.alias} gigastake load balancer not found`, -32054)
crisog marked this conversation as resolved.
Show resolved Hide resolved
)
}

Expand Down Expand Up @@ -774,7 +751,10 @@ export class V1Controller {
const loadBalancer = await this.fetchLoadBalancer(redirect.loadBalancerID, filter)

if (!loadBalancer?.id) {
throw new ErrorObject(rpcID, new jsonrpc.JsonRpcError(`GS (${redirect.alias}) load balancer not found`, -32054))
throw new ErrorObject(
crisog marked this conversation as resolved.
Show resolved Hide resolved
rpcID,
new jsonrpc.JsonRpcError(`${redirect.alias} gigastake load balancer not found`, -32054)
)
}

const application = await this.fetchLoadBalancerApplication(
Expand Down
64 changes: 20 additions & 44 deletions src/utils/relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,26 @@ export async function loadBlockchain(
// Split off the first part of the request's host and check for matches
const [blockchainRequest] = host.split('.')

const [blockchainFilter] = blockchains.filter((b: { blockchainAliases: string[] }) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let blockchainFilter: any

// Search by blockchain alias (f.g. match 'eth-mainnet')
const [blockchainAliasFilter] = blockchains.filter((b: { blockchainAliases: string[] }) =>
b.blockchainAliases.some((alias) => alias.toLowerCase() === blockchainRequest.toLowerCase())
)

if (!blockchainFilter) {
throw new ErrorObject(rpcID, new jsonrpc.JsonRpcError(`Incorrect blockchain: ${host}`, -32057))
blockchainFilter = blockchainAliasFilter

// If there is no match using alias, try with redirect domain (f.g. match 'eth-rpc.gateway.pokt.network')
if (!blockchainAliasFilter) {
const [blockchainDomainFilter] = blockchains.filter((b: { redirects: BlockchainRedirect[] }) =>
b.redirects?.some((rdr) => rdr.domain.toLowerCase() === host.toLowerCase())
)
blockchainFilter = blockchainDomainFilter

// No blockchain match with either alias/domain. Blockchain must be incorrect.
if (!blockchainDomainFilter) {
throw new ErrorObject(rpcID, new jsonrpc.JsonRpcError(`Incorrect blockchain: ${host}`, -32057))
}
}

let blockchainEnforceResult = ''
Expand All @@ -69,11 +83,8 @@ export async function loadBlockchain(
let blockchainRedirects = [] as BlockchainRedirect[]
const blockchainSyncCheck = {} as SyncCheckOptions

const blockchain = blockchainFilter.blockchainAliases.find((alias: string) => {
if (alias.toLowerCase() === blockchainRequest.toLowerCase()) {
return alias // ex. 'eth-mainnet'
}
})
// ex. 'eth-mainnet', 'eth-rpc', 'poly-mainnet'
const blockchain = blockchainRequest

blockchainID = blockchainFilter.hash as string // ex. '0021'

Expand Down Expand Up @@ -132,38 +143,3 @@ export async function loadBlockchain(
blockchainRedirects,
} as BlockchainDetails)
}

// Get blockchain's alias by it's redirect domain
export async function getBlockchainAliasesByDomain(
crisog marked this conversation as resolved.
Show resolved Hide resolved
host: string,
redis: Cache,
blockchainsRepository: BlockchainsRepository,
rpcID: number
): Promise<{ blockchainAliases: string[] }> {
// Load the requested blockchain
const cachedBlockchains = await redis.get('blockchains')
let blockchains

if (!cachedBlockchains) {
blockchains = await blockchainsRepository.find()
await redis.set('blockchains', JSON.stringify(blockchains), 'EX', 60)
} else {
blockchains = JSON.parse(cachedBlockchains)
}

const [blockchainFilter] = blockchains.filter((b: { redirects: BlockchainRedirect[] }) =>
b.redirects?.some((rdr) => rdr.domain.toLowerCase() === host.toLowerCase())
)

if (!blockchainFilter) {
throw new ErrorObject(rpcID, new jsonrpc.JsonRpcError(`Unable to find a blockchain with domain: ${host}`, -32057))
}

let blockchainAliases: string[]

if (blockchainFilter.blockchainAliases) {
blockchainAliases = blockchainFilter.blockchainAliases
}

return Promise.resolve({ blockchainAliases })
}
3 changes: 1 addition & 2 deletions tests/acceptance/v1.controller.acceptance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1983,8 +1983,7 @@ describe('V1 controller (acceptance)', () => {
expect(response.body.error.message).to.startWith('Restricted endpoint: contract address not allowed')
})

// eslint-disable-next-line mocha/no-exclusive-tests
it.only('invokes POST /v1/{appId} and successfully relays a request only through the altruist', async () => {
it('invokes POST /v1/{appId} and successfully relays a request only through the altruist', async () => {
const pocket = pocketMock.object()
const logSpy = sinon.spy(logger, 'log')

Expand Down
74 changes: 72 additions & 2 deletions tests/unit/pocket-relayer.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,32 @@ const BLOCKCHAINS = [
logLimitBlocks: 10000,
altruist: 'https://user:[email protected]:18553',
},
{
hash: '0042',
ticker: 'ETHR',
networkID: '1',
network: 'ETH-2R',
description: 'Ethereum Redirects',
index: 3,
blockchain: 'eth-mainnet-redirects',
blockchainAliases: ['eth-mainnet-redirects'],
active: true,
nodeCount: 1,
chainIDCheck: '{"method":"eth_chainId","id":15,"jsonrpc":"2.0"}',
syncCheckOptions: {
body: '{"method":"eth_blockNumber","id":15,"jsonrpc":"2.0"}',
resultKey: 'result',
} as SyncCheckOptions,
logLimitBlocks: 10000,
altruist: 'https://user:[email protected]:18553',
redirects: [
{
alias: 'eth-mainnet-redirects',
domain: 'eth-rpc.gateway.pokt.network',
loadBalancerID: 'a21fj31d714kgos42e72gcv3',
},
],
},
]

const APPLICATION = {
Expand Down Expand Up @@ -226,7 +252,7 @@ describe('Pocket relayer service (unit)', () => {
it('loads all blockchains from db, caches them and returns config of requested blockchain', async () => {
const dbBlockchains = await blockchainRepository.createAll(BLOCKCHAINS)

expect(dbBlockchains).to.have.length(3)
expect(dbBlockchains).to.have.length(4)

const repositorySpy = sinon.spy(blockchainRepository, 'find')
const cacheGetSpy = sinon.spy(cache, 'get')
Expand Down Expand Up @@ -264,6 +290,50 @@ describe('Pocket relayer service (unit)', () => {
expect(cacheSetSpy.callCount).to.be.equal(1)
})

it('returns config of requested blockchain using redirect domain', async () => {
const dbBlockchains = await blockchainRepository.createAll(BLOCKCHAINS)

expect(dbBlockchains).to.have.length(4)

const repositorySpy = sinon.spy(blockchainRepository, 'find')
const cacheGetSpy = sinon.spy(cache, 'get')
const cacheSetSpy = sinon.spy(cache, 'set')

// Request comes from redirected domain
pocketRelayer.host = 'eth-rpc.gateway.pokt.network'

let blockchainResult = await loadBlockchain(
pocketRelayer.host,
pocketRelayer.cache,
pocketRelayer.blockchainsRepository,
pocketRelayer.defaultLogLimitBlocks,
1
)

expect(blockchainResult).to.be.ok()
expect(blockchainResult.blockchainID).to.be.equal(BLOCKCHAINS[3].hash)

expect(repositorySpy.callCount).to.be.equal(1)
expect(cacheGetSpy.callCount).to.be.equal(1)
expect(cacheSetSpy.callCount).to.be.equal(1)

// Subsequent calls should retrieve results from cache instead
blockchainResult = await loadBlockchain(
pocketRelayer.host,
pocketRelayer.cache,
pocketRelayer.blockchainsRepository,
pocketRelayer.defaultLogLimitBlocks,
1
)

expect(blockchainResult).to.be.ok()
expect(blockchainResult.blockchainID).to.be.equal(BLOCKCHAINS[3].hash)

expect(repositorySpy.callCount).to.be.equal(1)
expect(cacheGetSpy.callCount).to.be.equal(2)
expect(cacheSetSpy.callCount).to.be.equal(1)
})

it('throws an error when loading an invalid blockchain', async () => {
await expect(
loadBlockchain(
Expand Down Expand Up @@ -385,7 +455,7 @@ describe('Pocket relayer service (unit)', () => {
const createBlockchain = async () => {
const dbBlockchain = await blockchainRepository.createAll(BLOCKCHAINS)

expect(dbBlockchain).to.have.length(3)
expect(dbBlockchain).to.have.length(4)
}

// Possible ammount of nodes that a session or blockchain check can return
Expand Down