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

explorer: Get transaction from mempool #2977

Open
wants to merge 1 commit into
base: master
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
12 changes: 7 additions & 5 deletions explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add decode feature for `memo` field [#2527]
- Add top node info in StatisticsPanel [#2613]
- Add Provisioners page [#2649]
- Check if transaction exists in mempool [#2877]

### Changed

Expand Down Expand Up @@ -67,8 +68,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- ISSUES -->

[#2017]: https://github.com/dusk-network/rusk/issues/2017
[#1892]: https://github.com/dusk-network/rusk/issues/1892
[#2017]: https://github.com/dusk-network/rusk/issues/2017
[#2025]: https://github.com/dusk-network/rusk/issues/2025
[#2034]: https://github.com/dusk-network/rusk/issues/2034
[#2036]: https://github.com/dusk-network/rusk/issues/2036
Expand All @@ -79,21 +80,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#2059]: https://github.com/dusk-network/rusk/issues/2059
[#2061]: https://github.com/dusk-network/rusk/issues/2061
[#2159]: https://github.com/dusk-network/rusk/issues/2159
[#2166]: https://github.com/dusk-network/rusk/issues/2166
[#2220]: https://github.com/dusk-network/rusk/issues/2220
[#2347]: https://github.com/dusk-network/rusk/issues/2347
[#2348]: https://github.com/dusk-network/rusk/issues/2348
[#2362]: https://github.com/dusk-network/rusk/issues/2362
[#2363]: https://github.com/dusk-network/rusk/issues/2363
[#2363]: https://github.com/dusk-network/rusk/issues/2347
[#2364]: https://github.com/dusk-network/rusk/issues/2364
[#2389]: https://github.com/dusk-network/rusk/issues/2389
[#2527]: https://github.com/dusk-network/rusk/issues/2527
[#2166]: https://github.com/dusk-network/rusk/issues/2166
[#2585]: https://github.com/dusk-network/rusk/issues/2585
[#2640]: https://github.com/dusk-network/rusk/issues/2640
[#2668]: https://github.com/dusk-network/rusk/issues/2668
[#2613]: https://github.com/dusk-network/rusk/issues/2613
[#2640]: https://github.com/dusk-network/rusk/issues/2640
[#2649]: https://github.com/dusk-network/rusk/issues/2649
[#2662]: https://github.com/dusk-network/rusk/issues/2662
[#2668]: https://github.com/dusk-network/rusk/issues/2668
[#2877]: https://github.com/dusk-network/rusk/issues/2877
[#3038]: https://github.com/dusk-network/rusk/issues/3038
[#3064]: https://github.com/dusk-network/rusk/issues/3064

Expand Down
1 change: 0 additions & 1 deletion explorer/src/lib/components/data-card/DataCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
export let className = undefined;

$: classes = makeClassName(["data-card", className]);

$: hasEmptyData = Array.isArray(data) && data.length === 0;
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@
/** @type {boolean} */
let isMemoDecoded = false;

$: classes = makeClassName(["transaction-details", className]);

onMount(() => {
const resizeObserver = new ResizeObserver((entries) => {
const entry = entries[0];
Expand All @@ -70,6 +68,8 @@

return () => resizeObserver.disconnect();
});

$: classes = makeClassName(["transaction-details", className]);
</script>

<DataCard
Expand Down
46 changes: 46 additions & 0 deletions explorer/src/lib/dusk/components/banner/Banner.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.dusk-banner {
width: 100%;
display: flex;
align-items: center;
padding: 1rem 1.25rem;
border-radius: 0.75rem;
font-size: 0.875rem;
border-style: solid;
border-width: 0.0625rem;
line-height: 1.5;
}

.dusk-banner .dusk-banner--info {
border-color: var(--banner-info-color);
}

.dusk-banner .dusk-banner--warning {
border-color: var(--banner-warning-color);
}

.dusk-banner .dusk-banner--error {
border-color: var(--banner-error-color);
}

.dusk-banner .dusk-banner__title {
font-weight: 500;
font-size: 1.1rem;
display: block;
}

.dusk-banner .dusk-banner__icon {
margin-right: var(--default-gap);
flex-shrink: 0;
}

.dusk-banner .dusk-banner__icon--info {
fill: var(--banner-info-color);
}

.dusk-banner .dusk-banner__icon--warning {
fill: var(--banner-warning-color);
}

.dusk-banner .dusk-banner__icon--error {
fill: var(--banner-error-color);
}
51 changes: 51 additions & 0 deletions explorer/src/lib/dusk/components/banner/Banner.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script>
import { makeClassName } from "$lib/dusk/string";
import { Icon } from "$lib/dusk/components";
import {
mdiAlertCircleOutline,
mdiAlertDecagramOutline,
mdiAlertOutline,
} from "@mdi/js";

import "./Banner.css";

/** @type {string} */
export let title;

/** @type {String | Undefined} */
export let className = undefined;

/** @type {BannerVariant} */
export let variant = "info";

function getBannerIconPath() {
switch (variant) {
case "warning":
return mdiAlertOutline;
case "error":
return mdiAlertDecagramOutline;
default:
return mdiAlertCircleOutline;
}
}

$: classes = makeClassName([
"dusk-banner",
`dusk-banner--${variant}`,
className,
]);
</script>

<div {...$$restProps} class={classes}>
<Icon
path={getBannerIconPath()}
size="large"
className="dusk-banner__icon dusk-banner__icon--{variant}"
/>
<div>
<strong class="dusk-banner__title">{title}</strong>
<slot>
<p>No banner content provided.</p>
</slot>
</div>
</div>
2 changes: 2 additions & 0 deletions explorer/src/lib/dusk/components/dusk.components.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
type BadgeVariant = "neutral" | "success" | "warning" | "error" | "alt";

type BannerVariant = "info" | "warning" | "error";

type ButtonSize = "normal" | "small";

type ButtonVariant = "primary" | "secondary" | "tertiary";
Expand Down
1 change: 1 addition & 0 deletions explorer/src/lib/dusk/components/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as Anchor } from "./anchor/Anchor.svelte";
export { default as AnchorButton } from "./anchor-button/AnchorButton.svelte";
export { default as Banner } from "./banner/Banner.svelte";
export { default as Badge } from "./badge/Badge.svelte";
export { default as Button } from "./button/Button.svelte";
export { default as Card } from "./card/Card.svelte";
Expand Down
12 changes: 6 additions & 6 deletions explorer/src/lib/services/__tests__/duskAPI.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe("duskAPI", () => {
expect(fetchSpy.mock.calls[0][0]).toStrictEqual(gqlExpectedURL);
expect(fetchSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
{
"body": "{"data":"\\n \\n\\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo\\n txType\\n }\\n}\\n\\nfragment BlockInfo on Block {\\n header {\\n hash,\\n gasLimit,\\n height,\\n prevBlockHash,\\n seed,\\n stateHash,\\n timestamp,\\n version\\n },\\n fees,\\n gasSpent,\\n reward,\\n transactions {...TransactionInfo}\\n}\\n\\n query($id: String!) { block(hash: $id) {...BlockInfo} }\\n ","topic":"gql"}",
"body": "{"data":"\\n \\n\\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo,\\n txType\\n }\\n}\\n\\nfragment BlockInfo on Block {\\n header {\\n hash,\\n gasLimit,\\n height,\\n prevBlockHash,\\n seed,\\n stateHash,\\n timestamp,\\n version\\n },\\n fees,\\n gasSpent,\\n reward,\\n transactions {...TransactionInfo}\\n}\\n\\n query($id: String!) { block(hash: $id) {...BlockInfo} }\\n ","topic":"gql"}",
"headers": {
"Accept": "application/json",
"Accept-Charset": "utf-8",
Expand Down Expand Up @@ -183,7 +183,7 @@ describe("duskAPI", () => {
expect(fetchSpy.mock.calls[0][0]).toStrictEqual(gqlExpectedURL);
expect(fetchSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
{
"body": "{"data":"\\n \\n\\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo\\n txType\\n }\\n}\\n\\nfragment BlockInfo on Block {\\n header {\\n hash,\\n gasLimit,\\n height,\\n prevBlockHash,\\n seed,\\n stateHash,\\n timestamp,\\n version\\n },\\n fees,\\n gasSpent,\\n reward,\\n transactions {...TransactionInfo}\\n}\\n\\n query($amount: Int!) { blocks(last: $amount) {...BlockInfo} }\\n ","topic":"gql"}",
"body": "{"data":"\\n \\n\\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo,\\n txType\\n }\\n}\\n\\nfragment BlockInfo on Block {\\n header {\\n hash,\\n gasLimit,\\n height,\\n prevBlockHash,\\n seed,\\n stateHash,\\n timestamp,\\n version\\n },\\n fees,\\n gasSpent,\\n reward,\\n transactions {...TransactionInfo}\\n}\\n\\n query($amount: Int!) { blocks(last: $amount) {...BlockInfo} }\\n ","topic":"gql"}",
"headers": {
"Accept": "application/json",
"Accept-Charset": "utf-8",
Expand All @@ -207,7 +207,7 @@ describe("duskAPI", () => {
expect(fetchSpy.mock.calls[0][0]).toStrictEqual(gqlExpectedURL);
expect(fetchSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
{
"body": "{"data":"\\n \\n\\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo\\n txType\\n }\\n}\\n\\nfragment BlockInfo on Block {\\n header {\\n hash,\\n gasLimit,\\n height,\\n prevBlockHash,\\n seed,\\n stateHash,\\n timestamp,\\n version\\n },\\n fees,\\n gasSpent,\\n reward,\\n transactions {...TransactionInfo}\\n}\\n\\n query($amount: Int!) {\\n blocks(last: $amount) {...BlockInfo},\\n transactions(last: $amount) {...TransactionInfo}\\n }\\n ","topic":"gql"}",
"body": "{"data":"\\n \\n\\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo,\\n txType\\n }\\n}\\n\\nfragment BlockInfo on Block {\\n header {\\n hash,\\n gasLimit,\\n height,\\n prevBlockHash,\\n seed,\\n stateHash,\\n timestamp,\\n version\\n },\\n fees,\\n gasSpent,\\n reward,\\n transactions {...TransactionInfo}\\n}\\n\\n query($amount: Int!) {\\n blocks(last: $amount) {...BlockInfo},\\n transactions(last: $amount) {...TransactionInfo}\\n }\\n ","topic":"gql"}",
"headers": {
"Accept": "application/json",
"Accept-Charset": "utf-8",
Expand Down Expand Up @@ -338,7 +338,7 @@ describe("duskAPI", () => {
expect(fetchSpy.mock.calls[0][0]).toStrictEqual(gqlExpectedURL);
expect(fetchSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
{
"body": "{"data":"\\n \\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo\\n txType\\n }\\n}\\n\\n query($id: String!) { tx(hash: $id) {...TransactionInfo} }\\n ","topic":"gql"}",
"body": "{"data":"\\n \\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo,\\n txType\\n }\\n}\\n\\n query($id: String!) { tx(hash: $id) {...TransactionInfo} }\\n ","topic":"gql"}",
"headers": {
"Accept": "application/json",
"Accept-Charset": "utf-8",
Expand All @@ -361,7 +361,7 @@ describe("duskAPI", () => {
expect(fetchSpy.mock.calls[0][0]).toStrictEqual(gqlExpectedURL);
expect(fetchSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
{
"body": "{"data":"query($id: String!) { tx(hash: $id) { tx {json} } }","topic":"gql"}",
"body": "{"data":"query($id: String!) { tx(hash: $id) { tx { json } } }","topic":"gql"}",
"headers": {
"Accept": "application/json",
"Accept-Charset": "utf-8",
Expand All @@ -383,7 +383,7 @@ describe("duskAPI", () => {
expect(fetchSpy.mock.calls[0][0]).toStrictEqual(gqlExpectedURL);
expect(fetchSpy.mock.calls[0][1]).toMatchInlineSnapshot(`
{
"body": "{"data":"\\n \\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo\\n txType\\n }\\n}\\n\\n query($amount: Int!) { transactions(last: $amount) {...TransactionInfo} }\\n ","topic":"gql"}",
"body": "{"data":"\\n \\nfragment TransactionInfo on SpentTransaction {\\n\\tblockHash,\\n\\tblockHeight,\\n\\tblockTimestamp,\\n err,\\n\\tgasSpent,\\n\\tid,\\n tx {\\n callData {\\n contractId,\\n data,\\n fnName\\n },\\n gasLimit,\\n gasPrice,\\n id,\\n isDeploy,\\n memo,\\n txType\\n }\\n}\\n\\n query($amount: Int!) { transactions(last: $amount) {...TransactionInfo} }\\n ","topic":"gql"}",
"headers": {
"Accept": "application/json",
"Accept-Charset": "utf-8",
Expand Down
18 changes: 16 additions & 2 deletions explorer/src/lib/services/duskAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,26 @@ const duskAPI = {

/**
* @param {string} id
* @returns {Promise<Transaction>}
* @returns {Promise<Transaction | String>}
*/
getTransaction(id) {
return gqlGet(gqlQueries.getTransactionQueryInfo(id))
.then(getKey("tx"))
.then(transformTransaction);
.then((tx) => {
if (tx === null) {
return gqlGet(gqlQueries.getMempoolTx(id))
.then(getKey("mempoolTx"))
.then((mempoolTx) => {
if (mempoolTx) {
return "This transaction is currently in the mempool and has not yet been confirmed. The transaction details will be displayed after confirmation.";
} else {
throw new Error("Transaction not found");
}
});
} else {
return transformTransaction(tx);
}
});
},

/**
Expand Down
10 changes: 8 additions & 2 deletions explorer/src/lib/services/gql-queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fragment TransactionInfo on SpentTransaction {
gasPrice,
id,
isDeploy,
kieranhall marked this conversation as resolved.
Show resolved Hide resolved
memo
memo,
txType
}
}
Expand Down Expand Up @@ -86,6 +86,12 @@ export const getLatestChainQueryInfo = (amount) => ({
variables: { amount },
});

/** @param {string} id */
export const getMempoolTx = (id) => ({
query: "query($id: String!) { mempoolTx(hash: $id) { isDeploy } }",
variables: { id },
});

/** @param {string} id */
export const getTransactionQueryInfo = (id) => ({
query: `
Expand All @@ -106,7 +112,7 @@ export const getTransactionsQueryInfo = (amount) => ({

/** @param {string} id */
export const getTransactionDetailsQueryInfo = (id) => ({
query: "query($id: String!) { tx(hash: $id) { tx {json} } }",
query: "query($id: String!) { tx(hash: $id) { tx { json } } }",
variables: { id },
});

Expand Down
29 changes: 18 additions & 11 deletions explorer/src/routes/transactions/transaction/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
import { onMount } from "svelte";
import { navigating, page } from "$app/stores";
import { TransactionDetails } from "$lib/components/";
import { Banner } from "$lib/dusk/components/";
import { duskAPI } from "$lib/services";
import { marketDataStore } from "$lib/stores";
import { createDataStore } from "$lib/dusk/svelte-stores";

const dataStore = createDataStore(duskAPI.getTransaction);
const payloadStore = createDataStore(duskAPI.getTransactionDetails);

const getTransaction = () => {
dataStore.getData($page.url.searchParams.get("id"));
payloadStore.getData($page.url.searchParams.get("id"));
const id = $page.url.searchParams.get("id");
dataStore.getData(id);
payloadStore.getData(id);
};

onMount(getTransaction);
Expand All @@ -28,12 +29,18 @@
</script>

<section class="transaction">
<TransactionDetails
on:retry={getTransaction}
{data}
{error}
loading={isLoading}
payload={payloadData}
market={marketData}
/>
{#if typeof data === "string"}
<Banner title="This transaction is being processed" variant="info">
{data}
</Banner>
{:else}
<TransactionDetails
on:retry={getTransaction}
{data}
{error}
loading={isLoading}
payload={payloadData}
market={marketData}
/>
{/if}
</section>
9 changes: 9 additions & 0 deletions explorer/src/style/dusk/colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,13 @@
--warning: #ffcf23;
--error: #ed254e;
--info: #71b1ff;

--success-500: #16db93;
--success-700: #0f9363;
--warning-500: #ffcf23;
--warning-700: #d1a300;
--error-500: #ed254e;
--error-700: #8e112c;
--info-500: #71b1ff;
--info-700: #0863d1;
}
Loading
Loading