Skip to content

Commit

Permalink
Merge pull request #14 from protofire/develop
Browse files Browse the repository at this point in the history
Fix extrinsic URL and added empty data component.
  • Loading branch information
0xslipk authored Jan 26, 2021
2 parents 6efcdf6 + 8fa50a6 commit 5c0b0b6
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 29 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.0.1
Published by **[jarcodallo](https://github.com/jarcodallo)** on **2021/01/26**
- [#13](https://github.com/protofire/polkadot-mempool-explorer/pull/14) Fix extrinsic URL and added empty data component.

## 1.0.0
Published by **[jarcodallo](https://github.com/jarcodallo)** on **2021/01/19**
- [#13](https://github.com/protofire/polkadot-mempool-explorer/pull/13) Release v1.0.0
- [#13](https://github.com/protofire/polkadot-mempool-explorer/pull/13) Release v1.0.0.
20 changes: 20 additions & 0 deletions api/constants/networks.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ const TEST_NETWORKS = [
name: 'Westend',
url: 'wss://westend-rpc.polkadot.io',
},
{
id: 'rococo',
name: 'Rococo',
url: 'wss://rococo-rpc.polkadot.io',
},
{
id: 'rococo-tick',
name: 'Rococo Tick',
url: 'wss://tick-rpc.polkadot.io',
},
{
id: 'rococo-trick',
name: 'Rococo Trick',
url: 'wss://trick-rpc.polkadot.io',
},
{
id: 'rococo-track',
name: 'Rococo Track',
url: 'wss://track-rpc.polkadot.io',
},
];

const LOCAL_NETWORKS = [
Expand Down
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "api",
"version": "1.0.0",
"version": "1.0.1",
"engines": {
"node": ">= 14.0.0"
},
Expand Down
46 changes: 34 additions & 12 deletions api/services/cache/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ class CacheService {

// Lock network and prevent update at the same time
let extrinsicKeys = await lock.acquire(networkId);

try {
if (!extrinsicKeys) {
extrinsicKeys = await CacheService.getNetworkExtrinsicKeys(networkId);
extrinsicKeys = await CacheService.getNetworkExtrinsicKeys(networkId);
extrinsicKeys.reverse();
}

const extrinsicKey = CacheService.getExtrinsicKey(networkId, hash, from, nonce);
Expand Down Expand Up @@ -70,19 +71,40 @@ class CacheService {
}

static async getExtrinsics(networkId) {
const networkKey = CacheService.getNetworkKey(networkId);
const extrinsicKeys = JSON.parse(lruCache.get(networkKey) || null) || [];
const extrinsicKeys = await CacheService.getNetworkExtrinsicKeys(networkId);

if (extrinsicKeys.length > 0) {
const extrinsics = extrinsicKeys.map(
(extrinsicKey) => JSON.parse(lruCache.get(extrinsicKey) || null),
);
const expireExtrinsicKeys = [];
const extrinsics = [];

extrinsicKeys.forEach((extrinsicKey) => {
const extrinsic = JSON.parse(lruCache.get(extrinsicKey) || null);

if (extrinsic) {
extrinsics.push(extrinsic);
} else {
expireExtrinsicKeys.push(extrinsicKey);
}
});

// Remove the least-recently-used extrinsic from network
// In some cases the extrinsic can expire and still be present on the network cache.
if (expireExtrinsicKeys.length > 0) {
expireExtrinsicKeys.forEach((expireExtrinsicKey) => {
const index = extrinsicKeys.indexOf(expireExtrinsicKey);

if (index !== -1) {
extrinsicKeys.splice(index, 1);
}
});

// Update network
await CacheService.setNetworkExtrinsicKeys(networkId, extrinsicKeys);
}

return extrinsics.sort((a, b) => {
if (a.createAt > b.createAt)
return -1;
if (a.createAt < b.createAt)
return 1;
if (a.createAt > b.createAt) return -1;
if (a.createAt < b.createAt) return 1;
return 0;
});
}
Expand All @@ -99,7 +121,7 @@ class CacheService {
static async getNetworkExtrinsicKeys(networkId) {
const networkKey = CacheService.getNetworkKey(networkId);

return (JSON.parse(lruCache.get(networkKey) || null) || []).reverse();
return (JSON.parse(lruCache.get(networkKey) || null) || []);
}

static async setExtrinsic(hash, from, nonce, networkId, data) {
Expand Down
7 changes: 4 additions & 3 deletions api/services/polkadot/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Module dependencies
*/
const { ApiPromise, WsProvider } = require('@polkadot/api');
const { PRODUCTION } = require('../../env');
const { DEVELOPMENT } = require('../../env');
const {
LIVE_NETWORKS,
TEST_NETWORKS,
Expand All @@ -24,10 +24,11 @@ const newHeadWatchers = {};
class PolkadotService {
static getNetworks() {
const local = [...LOCAL_NETWORKS];
const live = [...LIVE_NETWORKS, ...CUSTOM_NETWORKS];
let live = [...LIVE_NETWORKS, ...CUSTOM_NETWORKS];

if (!PRODUCTION) {
if (DEVELOPMENT) {
local.push(...DEV_NETWORKS);
live = LIVE_NETWORKS;
}

return {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "polkadot-mempool-explorer",
"version": "1.0.0",
"version": "1.0.1",
"scripts": {
"start:dev": "docker-compose up -d",
"down": "docker-compose down -v --rmi=local --remove-orphans",
Expand Down
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "web",
"version": "1.0.0",
"version": "1.0.1",
"engines": {
"node": ">= 14.0.0"
},
Expand Down
Empty file removed web/src/assets/.gitkeep
Empty file.
7 changes: 4 additions & 3 deletions web/src/components/common/Transaction/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,22 +222,23 @@ export const Transaction: React.FC<Props> = (props) => {
const result = isValid ? 'Valid' : 'Invalid'
const explorerURL = 'https://polkadot.subscan.io/'
const blockURL = `${explorerURL}block/`
const extrinsicURL = `${explorerURL}extrinsic/`
const accountURL = `${explorerURL}account/`

return (
<Wrapper {...restProps} className={isFinalized ? 'justRemoved' : 'inMempool'}>
<TopWrapper>
<TitleRow>
<Label>Tx Hash:</Label>
<LinkValue href={`${blockURL}${hash}`} target="_blank">
<LinkValue href={`${extrinsicURL}${hash}`} target="_blank">
{hash}
</LinkValue>
<ButtonCopy value={hash} />
<ButtonExternalLink href={`${blockURL}${hash}`} style={{ marginLeft: '2px' }} />
<ButtonExternalLink href={`${extrinsicURL}${hash}`} style={{ marginLeft: '2px' }} />
</TitleRow>
<TimeWrapper>
<TimeIcon />
<Time href={`${blockURL}${hash}`} target="_blank">
<Time href={`${extrinsicURL}${hash}`} target="_blank">
{updateAt}
</Time>
</TimeWrapper>
Expand Down
Empty file removed web/src/layouts/.gitkeep
Empty file.
77 changes: 77 additions & 0 deletions web/src/pages/Main/components/Transactions/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react'

import { ItemPlaceholder } from 'components/common/ItemPlaceholder'
import { Transaction } from 'components/common/Transaction'
import { BaseCard } from 'components/pureStyledComponents/BaseCard'
import { CardText } from 'components/pureStyledComponents/CardText'
import useMempoolExplorer from 'hooks/useMempoolExplorer'

interface Props {
searchBy: string
searchValue: string
transactionState: string
}

export const Transactions: React.FC<Props> = (props) => {
const { searchBy, searchValue, transactionState } = props
const { isLoadingTransactions, transactions } = useMempoolExplorer()
let filterTransactions = transactions

if (searchValue !== '') {
filterTransactions = filterTransactions.filter((transaction) => {
switch (searchBy) {
case 'tx':
return transaction.hash === searchValue
case 'block':
return transaction.block_number === searchValue
case 'from':
return transaction.from === searchValue
case 'to':
return transaction.to === searchValue
default:
return [
transaction.hash,
transaction.block_number,
transaction.from,
transaction.to,
].includes(searchValue)
}
})
}

if (transactionState !== 'all') {
filterTransactions = filterTransactions.filter((transaction) => {
if (transactionState === 'inMempool' && transaction.isFinalized) {
return false
} else if (transactionState === 'inMempool' && !transaction.isFinalized) {
return true
} else if (transactionState === 'justRemoved' && transaction.isFinalized) {
return true
} else if (transactionState === 'justRemoved' && !transaction.isFinalized) {
return false
} else {
return true
}
})
}

if (!isLoadingTransactions && filterTransactions.length === 0) {
return (
<BaseCard>
<CardText>No pending extrinsics in the pool.</CardText>
</BaseCard>
)
}

return (
<>
{isLoadingTransactions && filterTransactions.length < 1
? Array.from({ length: 10 }, (_, i) => i).map((index) => (
<ItemPlaceholder key={index} opacity={(1 - index * 0.15).toString()} />
))
: filterTransactions.map((item, index) => {
return <Transaction data={item} key={index} />
})}
</>
)
}
16 changes: 9 additions & 7 deletions web/src/pages/Main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import { AllTransactions } from 'components/icons/AllTransactions'
import { ChevronDown } from 'components/icons/ChevronDown'
import { InMempool } from 'components/icons/InMempool'
import { JustRemoved } from 'components/icons/JustRemoved'
import { BaseCard } from 'components/pureStyledComponents/BaseCard'
import { CardText } from 'components/pureStyledComponents/CardText'
import { PageTitle } from 'components/text/PageTitle'
import useMempoolExplorer from 'hooks/useMempoolExplorer'

import { Transactions } from './components/Transactions'

const Wrapper = styled.div``

const TitleDropdownButton = styled.button`
Expand Down Expand Up @@ -198,13 +202,11 @@ export const Main: React.FC = (props) => {
>
Mempool Explorer
</PageTitle>
{isLoadingTransactions && filterTransactions.length < 1
? [0, 1, 2, 3, 4, 5].map((index) => (
<ItemPlaceholder key={index} opacity={(1 - index * 0.15).toString()} />
))
: filterTransactions.map((item, index) => {
return <Transaction data={item} key={index} />
})}
<Transactions
searchBy={searchBy}
searchValue={searchValue}
transactionState={transactionState}
/>
</Wrapper>
)
}

0 comments on commit 5c0b0b6

Please sign in to comment.