diff --git a/packages/cacti-ledger-browser/README.md b/packages/cacti-ledger-browser/README.md
index 950cbafbd1..b396c9d9e3 100644
--- a/packages/cacti-ledger-browser/README.md
+++ b/packages/cacti-ledger-browser/README.md
@@ -1,6 +1,6 @@
# `@hyperledger/cacti-ledger-browser`
-This component allows viewing ledger data in Supabase or other postgreSQL compatible database. The data is fed to supabase by persistence plugins for each ledgers.
+This component allows viewing ledger data in Supabase or other PostgreSQL compatible database. The data is fed to supabase by persistence plugins for each ledgers.
## Summary
@@ -8,9 +8,6 @@ This component allows viewing ledger data in Supabase or other postgreSQL compat
- [Summary](#summary)
- [Remarks](#remarks)
- [Getting Started](#getting-started)
- - [Prerequisites using yarn](#prerequisites-using-yarn)
- - [Alternative Prerequisites using npm](#alternative-prerequisites-using-npm)
- - [Usage](#usage)
- [Contributing](#contributing)
- [License](#license)
- [Acknowledgments](#acknowledgments)
@@ -22,35 +19,9 @@ This component allows viewing ledger data in Supabase or other postgreSQL compat
## Getting Started
-Clone the git repository on your local machine. Follow these instructions that will get you a copy of the project up and running on your local machine for development and testing purposes.
+Clone the git repository on your local machine.
-### Prerequisites using yarn
-
-In the root of the project, execute the command to install and build the dependencies. It will also build this GUI front-end component:
-
-```sh
-yarn run build
-```
-
-### Alternative Prerequisites using npm
-
-In the root of the project, execute the command to install and build the dependencies. It will also build this GUI front-end component:
-
-```sh
-npm install
-```
-
-### Usage
-
-- Run Supabase instance (see documentation for detailed instructions). For development purposes, you can use our image located in `tools/docker/supabase-all-in-one`.
-- Run one or more persistence plugins:
- - [Ethereum](../cacti-plugin-persistence-ethereum)
- - [Fabric] (../cacti-plugin-persistence-fabric)
-- Edit Supabase configuration files, set correct supabase API URL and service_role key.
- - ./src/main/typescript/common/supabase-client.tsx
- - ./src/main/typescript/common/queries.ts
-- Execute `yarn run start` or `npm start` in this package directory.
-- The running application address: http://localhost:3001/ (can be changed in [Vite configuration](./vite.config.ts))
+See [docs/docs/cactus/ledger-browser/setup.md](../../docs/docs/cactus/ledger-browser/setup.md) for detailed information on how to setup and use this package.
## Contributing
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/index.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/index.tsx
index 29e3a84703..abd26442d8 100644
--- a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/index.tsx
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/index.tsx
@@ -4,6 +4,7 @@ import Dashboard from "./pages/Dashboard/Dashboard";
import Blocks from "./pages/Blocks/Blocks";
import Transactions from "./pages/Transactions/Transactions";
import TransactionDetails from "./pages/TransactionDetails/TransactionDetails";
+import Discovery from "./pages/Discovery/Discovery";
import {
AppInstancePersistencePluginOptions,
AppDefinition,
@@ -56,11 +57,19 @@ const fabricBrowserAppDefinition: AppDefinition = {
title: "Dashboard",
url: "/",
},
+ {
+ title: "Discovery",
+ url: "/discovery",
+ },
],
routes: [
{
element: ,
},
+ {
+ path: "discovery",
+ element: ,
+ },
{
path: "blocks",
element: ,
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/Discovery.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/Discovery.tsx
new file mode 100644
index 0000000000..78c0f9c320
--- /dev/null
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/Discovery.tsx
@@ -0,0 +1,91 @@
+import React from "react";
+import { useQuery } from "@tanstack/react-query";
+import Typography from "@mui/material/Typography";
+import Box from "@mui/material/Box";
+import List from "@mui/material/List/List";
+import ListItem from "@mui/material/ListItem/ListItem";
+import ListItemButton from "@mui/material/ListItemButton/ListItemButton";
+import ListItemText from "@mui/material/ListItemText/ListItemText";
+import DoubleArrowIcon from "@mui/icons-material/DoubleArrow";
+import ListItemIcon from "@mui/material/ListItemIcon/ListItemIcon";
+import CircularProgress from "@mui/material/CircularProgress/CircularProgress";
+import Divider from "@mui/material/Divider/Divider";
+
+import { DiscoveryMSP } from "../../supabase-types";
+import PageTitle from "../../../../components/ui/PageTitle";
+import { useNotification } from "../../../../common/context/NotificationContext";
+import { fabricDiscoveryMSPs } from "../../queries";
+import DiscoveryDetails from "./DiscoveryDetails";
+
+function Discovery() {
+ const { showNotification } = useNotification();
+ const [selectedMSP, setSelectedMSP] = React.useState<
+ DiscoveryMSP | undefined
+ >(undefined);
+ const { isError, isPending, data, error } = useQuery(fabricDiscoveryMSPs());
+
+ React.useEffect(() => {
+ isError &&
+ showNotification(`Could not fetch discovery MSPs: ${error}`, "error");
+ }, [isError]);
+
+ const msps = data ?? [];
+
+ return (
+
+ Discovery
+
+
+
+
+ Select MSP
+
+
+ {isPending && (
+
+
+
+ )}
+
+
+ {msps && (
+
+ {msps.map((msp) => (
+
+ setSelectedMSP(msp)}
+ selected={msp.id === (selectedMSP?.id ?? "")}
+ sx={(theme) => ({
+ "&.Mui-selected": {
+ backgroundColor: theme.palette.primary.main,
+ color: "white",
+ },
+ })}
+ >
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+
+ {}
+
+
+ );
+}
+
+export default Discovery;
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/DiscoveryDetails.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/DiscoveryDetails.tsx
new file mode 100644
index 0000000000..bdde8b056c
--- /dev/null
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/DiscoveryDetails.tsx
@@ -0,0 +1,127 @@
+import React from "react";
+import { useQuery } from "@tanstack/react-query";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography/Typography";
+import Card from "@mui/material/Card/Card";
+import CardContent from "@mui/material/CardContent/CardContent";
+import List from "@mui/material/List/List";
+import ListItem from "@mui/material/ListItem/ListItem";
+import ListItemText from "@mui/material/ListItemText/ListItemText";
+import CircularProgress from "@mui/material/CircularProgress/CircularProgress";
+
+import { useNotification } from "../../../../common/context/NotificationContext";
+import { fabricDiscoveryNodes } from "../../queries";
+import { DiscoveryMSP } from "../../supabase-types";
+import PeerCardButton from "./PeerCardButton";
+import OrdererCardButton from "./OrdererCardButton";
+
+function NothingSelectedMessage() {
+ return (
+
+
+ Select MSP on the left to display ledger components.
+
+
+ );
+}
+
+function LoadingSpinner() {
+ return (
+
+
+
+ );
+}
+
+interface DiscoveryDetailsProps {
+ msp: DiscoveryMSP | undefined;
+}
+
+function DiscoveryDetails({ msp }: DiscoveryDetailsProps) {
+ const { showNotification } = useNotification();
+ const { isError, isPending, data, error } = useQuery(
+ fabricDiscoveryNodes(msp?.id),
+ );
+ React.useEffect(() => {
+ isError &&
+ showNotification(
+ `Could not fetch ledger components for MSP ${msp?.name ?? "(Unknown)"}: ${error}`,
+ "error",
+ );
+ }, [isError]);
+
+ if (!msp) {
+ return ;
+ }
+
+ if (isPending) {
+ return ;
+ }
+
+ const mspOUString = JSON.parse(msp.organizational_unit_identifiers).join(
+ ", ",
+ );
+
+ const peers = data?.peers ?? [];
+ const orderers = data?.orderers ?? [];
+
+ return (
+
+
+
+
+ {msp.name} ({msp.mspid})
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Peers
+
+
+ {peers.map((p) => (
+
+ ))}
+ {peers.length === 0 && (
+ No peers defined for this MSP
+ )}
+
+
+
+ Orderers
+
+
+ {orderers.map((o) => (
+
+ ))}
+ {orderers.length === 0 && (
+ No orderers defined for this MSP
+ )}
+
+
+ );
+}
+
+export default DiscoveryDetails;
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/OrdererCardButton.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/OrdererCardButton.tsx
new file mode 100644
index 0000000000..f0f9ab3d42
--- /dev/null
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/OrdererCardButton.tsx
@@ -0,0 +1,39 @@
+import * as React from "react";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogTitle from "@mui/material/DialogTitle";
+import DialogContent from "@mui/material/DialogContent";
+
+import OrdererDetailsBox from "./OrdererDetailsBox";
+import { DiscoveryOrderer } from "../../supabase-types";
+
+interface OrdererCardButtonProps {
+ orderer: DiscoveryOrderer;
+}
+
+export default function OrdererCardButton({ orderer }: OrdererCardButtonProps) {
+ const [openDialog, setOpenDialog] = React.useState(false);
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/OrdererDetailsBox.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/OrdererDetailsBox.tsx
new file mode 100644
index 0000000000..1af55511b0
--- /dev/null
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/OrdererDetailsBox.tsx
@@ -0,0 +1,33 @@
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import { styled } from "@mui/material/styles";
+import { DiscoveryOrderer } from "../../supabase-types";
+import StackedRowItems from "../../../../components/ui/StackedRowItems";
+
+const ListHeaderTypography = styled(Typography)(({ theme }) => ({
+ color: theme.palette.secondary.main,
+ fontWeight: "bold",
+}));
+
+export interface OrdererDetailsBoxProps {
+ orderer: DiscoveryOrderer;
+}
+
+export default function OrdererDetailsBox({ orderer }: OrdererDetailsBoxProps) {
+ return (
+
+
+ Name:
+ {orderer.name}
+
+
+ Host:
+ {orderer.host}
+
+
+ Port:
+ {orderer.port}
+
+
+ );
+}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/PeerCardButton.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/PeerCardButton.tsx
new file mode 100644
index 0000000000..acc2cefc6a
--- /dev/null
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/PeerCardButton.tsx
@@ -0,0 +1,39 @@
+import * as React from "react";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogTitle from "@mui/material/DialogTitle";
+import DialogContent from "@mui/material/DialogContent";
+
+import PeerDetailsBox from "./PeerDetailsBox";
+import { DiscoveryPeer } from "../../supabase-types";
+
+interface PeerCardButtonProps {
+ peer: DiscoveryPeer;
+}
+
+export default function PeerCardButton({ peer }: PeerCardButtonProps) {
+ const [openDialog, setOpenDialog] = React.useState(false);
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/PeerDetailsBox.tsx b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/PeerDetailsBox.tsx
new file mode 100644
index 0000000000..4610bb1ce7
--- /dev/null
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/pages/Discovery/PeerDetailsBox.tsx
@@ -0,0 +1,57 @@
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import List from "@mui/material/List/List";
+import ListItem from "@mui/material/ListItem/ListItem";
+import ListItemText from "@mui/material/ListItemText/ListItemText";
+import { styled } from "@mui/material/styles";
+import { DiscoveryPeer, DiscoveryPeerChaincodes } from "../../supabase-types";
+import StackedRowItems from "../../../../components/ui/StackedRowItems";
+
+const ListHeaderTypography = styled(Typography)(({ theme }) => ({
+ color: theme.palette.secondary.main,
+ fontWeight: "bold",
+}));
+
+export interface PeerDetailsBoxProps {
+ peer: DiscoveryPeer;
+}
+
+export default function PeerDetailsBox({ peer }: PeerDetailsBoxProps) {
+ const parsedChaincodes: DiscoveryPeerChaincodes[] = JSON.parse(
+ peer.chaincodes,
+ );
+
+ return (
+
+
+ Name:
+ {peer.name}
+
+
+ Endpoint:
+ {peer.endpoint}
+
+
+ Ledger Height:
+ {peer.ledger_height}
+
+
+
+ Chaincodes
+
+
+ {parsedChaincodes.map((cc) => {
+ return (
+
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/queries.ts b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/queries.ts
index 5c4e62606b..24ccd711d6 100644
--- a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/queries.ts
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/queries.ts
@@ -6,6 +6,9 @@
import { SupabaseClient, createClient } from "@supabase/supabase-js";
import { queryOptions } from "@tanstack/react-query";
import {
+ DiscoveryMSP,
+ DiscoveryOrderer,
+ DiscoveryPeer,
FabricBlock,
FabricCertificate,
FabricTransaction,
@@ -211,3 +214,68 @@ export function fabricActionEndorsements(actionId: string) {
},
});
}
+
+/**
+ * Get all MSPs discovered on current fabric channel.
+ */
+export function fabricDiscoveryMSPs() {
+ const [supabase, supabaseQueryKey] = useSupabaseClient();
+ const tableName = "discovery_msp";
+
+ return queryOptions({
+ queryKey: [supabaseQueryKey, tableName],
+ queryFn: async () => {
+ const { data, error } = await supabase.from(tableName).select();
+
+ if (error) {
+ throw new Error(`Could not get discovery MSPs: ${error.message}`);
+ }
+
+ return data as DiscoveryMSP[];
+ },
+ });
+}
+
+/**
+ * Get all peers and orderers for specified msp.
+ *
+ * @param mspId: Database ID of the MSP (i.e. uuid in `id` field)
+ */
+export function fabricDiscoveryNodes(mspId?: string) {
+ const [supabase, supabaseQueryKey] = useSupabaseClient();
+
+ return queryOptions({
+ queryKey: [supabaseQueryKey, "fabricDiscoveryNodes", mspId],
+ queryFn: async () => {
+ // Fetch peers
+ const { data: peers, error: peerError } = await supabase
+ .from("discovery_peers")
+ .select()
+ .match({ discovery_msp_id: mspId });
+
+ if (peerError) {
+ throw new Error(
+ `Could not get peers of MSP ID ${mspId}: ${peerError.message}`,
+ );
+ }
+
+ // Fetch orderers
+ const { data: orderers, error: ordererError } = await supabase
+ .from("discovery_orderers")
+ .select()
+ .match({ discovery_msp_id: mspId });
+
+ if (ordererError) {
+ throw new Error(
+ `Could not get orderers of MSP ID ${mspId}: ${ordererError.message}`,
+ );
+ }
+
+ return {
+ peers: peers as DiscoveryPeer[],
+ orderers: orderers as DiscoveryOrderer[],
+ };
+ },
+ enabled: !!mspId,
+ });
+}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/supabase-types.ts b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/supabase-types.ts
index 4c16f694ff..6ab49b6798 100644
--- a/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/supabase-types.ts
+++ b/packages/cacti-ledger-browser/src/main/typescript/apps/fabric/supabase-types.ts
@@ -55,3 +55,33 @@ export interface FabricCertificate {
valid_from: string;
valid_to: string;
}
+
+export interface DiscoveryMSP {
+ id: string;
+ mspid: string;
+ name: string;
+ organizational_unit_identifiers: string;
+ admins: string;
+}
+
+export interface DiscoveryPeer {
+ id: string;
+ endpoint: string;
+ name: string;
+ chaincodes: string;
+ ledger_height: number;
+ discovery_msp_id: string;
+}
+
+export interface DiscoveryPeerChaincodes {
+ name: string;
+ version: string;
+}
+
+export interface DiscoveryOrderer {
+ id: string;
+ host: string;
+ name: string;
+ port: number;
+ discovery_msp_id: string;
+}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/pages/home/AddApplicationPopupCard.tsx b/packages/cacti-ledger-browser/src/main/typescript/pages/home/AddApplicationPopupCard.tsx
index b01b45bbc4..76ab2a3a9b 100644
--- a/packages/cacti-ledger-browser/src/main/typescript/pages/home/AddApplicationPopupCard.tsx
+++ b/packages/cacti-ledger-browser/src/main/typescript/pages/home/AddApplicationPopupCard.tsx
@@ -63,7 +63,7 @@ export default function AddApplicationPopupCard() {
sx={{
display: "flex",
flexDirection: "column",
- width: 400,
+ width: "400px",
minHeight: 250,
backgroundColor: theme.palette.grey[100],
}}
diff --git a/packages/cacti-ledger-browser/src/main/typescript/pages/home/AppCard.tsx b/packages/cacti-ledger-browser/src/main/typescript/pages/home/AppCard.tsx
index 3517da884f..400660bac8 100644
--- a/packages/cacti-ledger-browser/src/main/typescript/pages/home/AppCard.tsx
+++ b/packages/cacti-ledger-browser/src/main/typescript/pages/home/AppCard.tsx
@@ -122,7 +122,7 @@ export default function AppCard({ appConfig }: AppCardProps) {
sx={{
display: "flex",
flexDirection: "column",
- width: 400,
+ width: "400px",
}}
>
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/.openapi-generator/FILES b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/.openapi-generator/FILES
index 9bb625d942..aead169ff7 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/.openapi-generator/FILES
+++ b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/.openapi-generator/FILES
@@ -6,6 +6,7 @@ client.go
configuration.go
go.mod
go.sum
+model_discover_network_response_v1.go
model_error_exception_response_v1.go
model_status_response_v1.go
model_tracked_operation_v1.go
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/README.md b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/README.md
index 118dbf4097..c5f7539662 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/README.md
+++ b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/README.md
@@ -77,11 +77,13 @@ All URIs are relative to *http://localhost*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
+*DefaultApi* | [**DiscoverNetworkV1**](docs/DefaultApi.md#discovernetworkv1) | **Post** /api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network | Refresh Fabric network structure in the database through discovery.
*DefaultApi* | [**GetStatusV1**](docs/DefaultApi.md#getstatusv1) | **Get** /api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/status | Get the status of persistence plugin for fabric
## Documentation For Models
+ - [DiscoverNetworkResponseV1](docs/DiscoverNetworkResponseV1.md)
- [ErrorExceptionResponseV1](docs/ErrorExceptionResponseV1.md)
- [StatusResponseV1](docs/StatusResponseV1.md)
- [TrackedOperationV1](docs/TrackedOperationV1.md)
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api/openapi.yaml b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api/openapi.yaml
index 050a9d59bb..b9cbd91ba2 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api/openapi.yaml
+++ b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api/openapi.yaml
@@ -32,6 +32,28 @@ paths:
http:
verbLowerCase: get
path: /api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/status
+ /api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network:
+ post:
+ operationId: discoverNetworkV1
+ parameters: []
+ responses:
+ "200":
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DiscoverNetworkResponseV1'
+ description: OK
+ "500":
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorExceptionResponseV1'
+ description: Internal Server Error
+ summary: Refresh Fabric network structure in the database through discovery.
+ x-hyperledger-cacti:
+ http:
+ verbLowerCase: post
+ path: /api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network
components:
schemas:
TrackedOperationV1:
@@ -99,6 +121,21 @@ components:
- operationsRunning
- webServicesRegistered
type: object
+ DiscoverNetworkResponseV1:
+ example:
+ message: message
+ status: true
+ properties:
+ status:
+ nullable: false
+ type: boolean
+ message:
+ nullable: false
+ type: string
+ required:
+ - message
+ - status
+ type: object
ErrorExceptionResponseV1:
properties:
message:
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api_default.go b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api_default.go
index dcc4a4252f..b1f5c77670 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api_default.go
+++ b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/api_default.go
@@ -22,6 +22,113 @@ import (
// DefaultApiService DefaultApi service
type DefaultApiService service
+type ApiDiscoverNetworkV1Request struct {
+ ctx context.Context
+ ApiService *DefaultApiService
+}
+
+func (r ApiDiscoverNetworkV1Request) Execute() (*DiscoverNetworkResponseV1, *http.Response, error) {
+ return r.ApiService.DiscoverNetworkV1Execute(r)
+}
+
+/*
+DiscoverNetworkV1 Refresh Fabric network structure in the database through discovery.
+
+ @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
+ @return ApiDiscoverNetworkV1Request
+*/
+func (a *DefaultApiService) DiscoverNetworkV1(ctx context.Context) ApiDiscoverNetworkV1Request {
+ return ApiDiscoverNetworkV1Request{
+ ApiService: a,
+ ctx: ctx,
+ }
+}
+
+// Execute executes the request
+// @return DiscoverNetworkResponseV1
+func (a *DefaultApiService) DiscoverNetworkV1Execute(r ApiDiscoverNetworkV1Request) (*DiscoverNetworkResponseV1, *http.Response, error) {
+ var (
+ localVarHTTPMethod = http.MethodPost
+ localVarPostBody interface{}
+ formFiles []formFile
+ localVarReturnValue *DiscoverNetworkResponseV1
+ )
+
+ localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DefaultApiService.DiscoverNetworkV1")
+ if err != nil {
+ return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
+ }
+
+ localVarPath := localBasePath + "/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network"
+
+ localVarHeaderParams := make(map[string]string)
+ localVarQueryParams := url.Values{}
+ localVarFormParams := url.Values{}
+
+ // to determine the Content-Type header
+ localVarHTTPContentTypes := []string{}
+
+ // set Content-Type header
+ localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
+ if localVarHTTPContentType != "" {
+ localVarHeaderParams["Content-Type"] = localVarHTTPContentType
+ }
+
+ // to determine the Accept header
+ localVarHTTPHeaderAccepts := []string{"application/json"}
+
+ // set Accept header
+ localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
+ if localVarHTTPHeaderAccept != "" {
+ localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
+ }
+ req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
+ if err != nil {
+ return localVarReturnValue, nil, err
+ }
+
+ localVarHTTPResponse, err := a.client.callAPI(req)
+ if err != nil || localVarHTTPResponse == nil {
+ return localVarReturnValue, localVarHTTPResponse, err
+ }
+
+ localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
+ localVarHTTPResponse.Body.Close()
+ localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
+ if err != nil {
+ return localVarReturnValue, localVarHTTPResponse, err
+ }
+
+ if localVarHTTPResponse.StatusCode >= 300 {
+ newErr := &GenericOpenAPIError{
+ body: localVarBody,
+ error: localVarHTTPResponse.Status,
+ }
+ if localVarHTTPResponse.StatusCode == 500 {
+ var v ErrorExceptionResponseV1
+ err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+ if err != nil {
+ newErr.error = err.Error()
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+ newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
+ newErr.model = v
+ }
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+
+ err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+ if err != nil {
+ newErr := &GenericOpenAPIError{
+ body: localVarBody,
+ error: err.Error(),
+ }
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+
+ return localVarReturnValue, localVarHTTPResponse, nil
+}
+
type ApiGetStatusV1Request struct {
ctx context.Context
ApiService *DefaultApiService
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/model_discover_network_response_v1.go b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/model_discover_network_response_v1.go
new file mode 100644
index 0000000000..aa92eb1153
--- /dev/null
+++ b/packages/cactus-plugin-persistence-fabric/src/main/go/generated/openapi/go-client/model_discover_network_response_v1.go
@@ -0,0 +1,144 @@
+/*
+Hyperledger Cactus Plugin - Persistence Fabric
+
+Synchronizes state of an fabric ledger into a DB that can later be viewed in GUI
+
+API version: 2.1.0
+*/
+
+// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
+
+package cactus-plugin-persistence-fabric
+
+import (
+ "encoding/json"
+)
+
+// checks if the DiscoverNetworkResponseV1 type satisfies the MappedNullable interface at compile time
+var _ MappedNullable = &DiscoverNetworkResponseV1{}
+
+// DiscoverNetworkResponseV1 struct for DiscoverNetworkResponseV1
+type DiscoverNetworkResponseV1 struct {
+ Status bool `json:"status"`
+ Message string `json:"message"`
+}
+
+// NewDiscoverNetworkResponseV1 instantiates a new DiscoverNetworkResponseV1 object
+// This constructor will assign default values to properties that have it defined,
+// and makes sure properties required by API are set, but the set of arguments
+// will change when the set of required properties is changed
+func NewDiscoverNetworkResponseV1(status bool, message string) *DiscoverNetworkResponseV1 {
+ this := DiscoverNetworkResponseV1{}
+ this.Status = status
+ this.Message = message
+ return &this
+}
+
+// NewDiscoverNetworkResponseV1WithDefaults instantiates a new DiscoverNetworkResponseV1 object
+// This constructor will only assign default values to properties that have it defined,
+// but it doesn't guarantee that properties required by API are set
+func NewDiscoverNetworkResponseV1WithDefaults() *DiscoverNetworkResponseV1 {
+ this := DiscoverNetworkResponseV1{}
+ return &this
+}
+
+// GetStatus returns the Status field value
+func (o *DiscoverNetworkResponseV1) GetStatus() bool {
+ if o == nil {
+ var ret bool
+ return ret
+ }
+
+ return o.Status
+}
+
+// GetStatusOk returns a tuple with the Status field value
+// and a boolean to check if the value has been set.
+func (o *DiscoverNetworkResponseV1) GetStatusOk() (*bool, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.Status, true
+}
+
+// SetStatus sets field value
+func (o *DiscoverNetworkResponseV1) SetStatus(v bool) {
+ o.Status = v
+}
+
+// GetMessage returns the Message field value
+func (o *DiscoverNetworkResponseV1) GetMessage() string {
+ if o == nil {
+ var ret string
+ return ret
+ }
+
+ return o.Message
+}
+
+// GetMessageOk returns a tuple with the Message field value
+// and a boolean to check if the value has been set.
+func (o *DiscoverNetworkResponseV1) GetMessageOk() (*string, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.Message, true
+}
+
+// SetMessage sets field value
+func (o *DiscoverNetworkResponseV1) SetMessage(v string) {
+ o.Message = v
+}
+
+func (o DiscoverNetworkResponseV1) MarshalJSON() ([]byte, error) {
+ toSerialize,err := o.ToMap()
+ if err != nil {
+ return []byte{}, err
+ }
+ return json.Marshal(toSerialize)
+}
+
+func (o DiscoverNetworkResponseV1) ToMap() (map[string]interface{}, error) {
+ toSerialize := map[string]interface{}{}
+ toSerialize["status"] = o.Status
+ toSerialize["message"] = o.Message
+ return toSerialize, nil
+}
+
+type NullableDiscoverNetworkResponseV1 struct {
+ value *DiscoverNetworkResponseV1
+ isSet bool
+}
+
+func (v NullableDiscoverNetworkResponseV1) Get() *DiscoverNetworkResponseV1 {
+ return v.value
+}
+
+func (v *NullableDiscoverNetworkResponseV1) Set(val *DiscoverNetworkResponseV1) {
+ v.value = val
+ v.isSet = true
+}
+
+func (v NullableDiscoverNetworkResponseV1) IsSet() bool {
+ return v.isSet
+}
+
+func (v *NullableDiscoverNetworkResponseV1) Unset() {
+ v.value = nil
+ v.isSet = false
+}
+
+func NewNullableDiscoverNetworkResponseV1(val *DiscoverNetworkResponseV1) *NullableDiscoverNetworkResponseV1 {
+ return &NullableDiscoverNetworkResponseV1{value: val, isSet: true}
+}
+
+func (v NullableDiscoverNetworkResponseV1) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.value)
+}
+
+func (v *NullableDiscoverNetworkResponseV1) UnmarshalJSON(src []byte) error {
+ v.isSet = true
+ return json.Unmarshal(src, &v.value)
+}
+
+
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.json b/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.json
index a0438776ed..0e505e4998 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.json
+++ b/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.json
@@ -73,6 +73,20 @@
}
}
},
+ "DiscoverNetworkResponseV1": {
+ "type": "object",
+ "required": ["status", "message"],
+ "properties": {
+ "status": {
+ "type": "boolean",
+ "nullable": false
+ },
+ "message": {
+ "type": "string",
+ "nullable": false
+ }
+ }
+ },
"ErrorExceptionResponseV1": {
"type": "object",
"required": ["message", "error"],
@@ -124,6 +138,41 @@
}
}
}
+ },
+ "/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network": {
+ "post": {
+ "operationId": "discoverNetworkV1",
+ "summary": "Refresh Fabric network structure in the database through discovery.",
+ "x-hyperledger-cacti": {
+ "http": {
+ "verbLowerCase": "post",
+ "path": "/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network"
+ }
+ },
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DiscoverNetworkResponseV1"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorExceptionResponseV1"
+ }
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.tpl.json b/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.tpl.json
index a0438776ed..b3eb37a447 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.tpl.json
+++ b/packages/cactus-plugin-persistence-fabric/src/main/json/openapi.tpl.json
@@ -14,7 +14,10 @@
"TrackedOperationV1": {
"description": "Persistence plugin operation that is tracked and returned in status report.",
"type": "object",
- "required": ["startAt", "operation"],
+ "required": [
+ "startAt",
+ "operation"
+ ],
"properties": {
"startAt": {
"type": "string",
@@ -73,9 +76,29 @@
}
}
},
+ "DiscoverNetworkResponseV1": {
+ "type": "object",
+ "required": [
+ "status",
+ "message"
+ ],
+ "properties": {
+ "status": {
+ "type": "boolean",
+ "nullable": false
+ },
+ "message": {
+ "type": "string",
+ "nullable": false
+ }
+ }
+ },
"ErrorExceptionResponseV1": {
"type": "object",
- "required": ["message", "error"],
+ "required": [
+ "message",
+ "error"
+ ],
"properties": {
"message": {
"type": "string",
@@ -124,6 +147,41 @@
}
}
}
+ },
+ "/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network": {
+ "post": {
+ "operationId": "discoverNetworkV1",
+ "summary": "Refresh Fabric network structure in the database through discovery.",
+ "x-hyperledger-cacti": {
+ "http": {
+ "verbLowerCase": "post",
+ "path": "/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network"
+ }
+ },
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DiscoverNetworkResponseV1"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorExceptionResponseV1"
+ }
+ }
+ }
+ }
+ }
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/sql/schema.sql b/packages/cactus-plugin-persistence-fabric/src/main/sql/schema.sql
index 56930d05aa..aca76e6f1a 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/sql/schema.sql
+++ b/packages/cactus-plugin-persistence-fabric/src/main/sql/schema.sql
@@ -1,7 +1,7 @@
--- Clean start:
--- DROP SCHEMA fabric CASCADE;
-CREATE SCHEMA fabric;
+CREATE SCHEMA IF NOT EXISTS fabric;
ALTER SCHEMA fabric OWNER TO postgres;
@@ -152,6 +152,75 @@ ALTER TABLE fabric.transaction_action_endorsement OWNER TO postgres;
ALTER TABLE ONLY fabric.transaction_action_endorsement
ADD CONSTRAINT transaction_action_endorsements_pkey PRIMARY KEY (id);
+-- Table: fabric.discovery_msp
+
+-- DROP TABLE IF EXISTS fabric.discovery_msp;
+
+CREATE TABLE IF NOT EXISTS fabric.discovery_msp
+(
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
+ mspid text COLLATE pg_catalog."default" NOT NULL,
+ name text COLLATE pg_catalog."default" NOT NULL,
+ organizational_unit_identifiers text COLLATE pg_catalog."default" NOT NULL,
+ admins text COLLATE pg_catalog."default" NOT NULL,
+ CONSTRAINT discovery_msp_pkey PRIMARY KEY (id)
+);
+
+ALTER TABLE IF EXISTS fabric.discovery_msp
+ OWNER to postgres;
+
+GRANT ALL ON TABLE fabric.discovery_msp TO anon;
+GRANT ALL ON TABLE fabric.discovery_msp TO authenticated;
+GRANT ALL ON TABLE fabric.discovery_msp TO postgres;
+GRANT ALL ON TABLE fabric.discovery_msp TO service_role;
+
+-- Table: fabric.discovery_orderers
+
+-- DROP TABLE IF EXISTS fabric.discovery_orderers;
+
+CREATE TABLE IF NOT EXISTS fabric.discovery_orderers
+(
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
+ name text COLLATE pg_catalog."default" NOT NULL,
+ host text COLLATE pg_catalog."default" NOT NULL,
+ port integer NOT NULL,
+ discovery_msp_id uuid NOT NULL,
+ CONSTRAINT discovery_orderers_pkey PRIMARY KEY (id),
+ CONSTRAINT discovery_orderers_discovery_msp_id_fkey FOREIGN KEY (discovery_msp_id) REFERENCES fabric.discovery_msp(id)
+);
+
+ALTER TABLE IF EXISTS fabric.discovery_orderers
+ OWNER to postgres;
+
+GRANT ALL ON TABLE fabric.discovery_orderers TO anon;
+GRANT ALL ON TABLE fabric.discovery_orderers TO authenticated;
+GRANT ALL ON TABLE fabric.discovery_orderers TO postgres;
+GRANT ALL ON TABLE fabric.discovery_orderers TO service_role;
+
+-- Table: fabric.discovery_peers
+
+-- DROP TABLE IF EXISTS fabric.discovery_peers;
+
+CREATE TABLE IF NOT EXISTS fabric.discovery_peers
+(
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
+ name text COLLATE pg_catalog."default" NOT NULL,
+ endpoint text COLLATE pg_catalog."default" NOT NULL,
+ ledger_height BIGINT NOT NULL,
+ chaincodes text COLLATE pg_catalog."default" NOT NULL,
+ discovery_msp_id uuid NOT NULL,
+ CONSTRAINT discovery_peers_pkey PRIMARY KEY (id),
+ CONSTRAINT discovery_peers_discovery_msp_id_fkey FOREIGN KEY (discovery_msp_id) REFERENCES fabric.discovery_msp(id)
+);
+
+ALTER TABLE IF EXISTS fabric.discovery_peers
+ OWNER to postgres;
+
+GRANT ALL ON TABLE fabric.discovery_peers TO anon;
+GRANT ALL ON TABLE fabric.discovery_peers TO authenticated;
+GRANT ALL ON TABLE fabric.discovery_peers TO postgres;
+GRANT ALL ON TABLE fabric.discovery_peers TO service_role;
+
-- FUNCTION: fabric.get_missing_blocks_in_range(integer, integer)
-- DROP FUNCTION IF EXISTS fabric.get_missing_blocks_in_range(integer, integer);
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/typescript/db-client/db-client.ts b/packages/cactus-plugin-persistence-fabric/src/main/typescript/db-client/db-client.ts
index 11c5ffb7c8..b98b975a84 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/typescript/db-client/db-client.ts
+++ b/packages/cactus-plugin-persistence-fabric/src/main/typescript/db-client/db-client.ts
@@ -18,6 +18,10 @@ import {
FullBlockTransactionActionV1,
FullBlockTransactionEndorsementV1,
FullBlockTransactionEventV1,
+ GetDiscoveryResultsResponseV1,
+ GetDiscoveryResultsResponseV1MspsValue,
+ GetDiscoveryResultsResponseV1OrderersValueEndpointsInner,
+ GetDiscoveryResultsResponseV1PeersByMSPValuePeersInner,
} from "@hyperledger/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/api";
import { Database as DatabaseSchemaType } from "./database.types";
@@ -500,4 +504,145 @@ export default class PostgresDatabaseClient {
return queryResponse.rows;
}
+
+ /**
+ * Insert discovered MSP to the database.
+ */
+ private async insertDiscoveryMsp(
+ msp: GetDiscoveryResultsResponseV1MspsValue,
+ ): Promise {
+ this.log.debug(`Insert to fabric.discovery_msp MspID ${msp.id})`);
+
+ const txInsertResponse = await this.client.query(
+ `INSERT INTO
+ fabric.discovery_msp("mspid", "name", "organizational_unit_identifiers", "admins")
+ VALUES ($1, $2, $3, $4)
+ RETURNING id;`,
+ [
+ msp.id,
+ msp.name,
+ JSON.stringify(msp.organizationalUnitIdentifiers),
+ msp.admins,
+ ],
+ );
+ if (txInsertResponse.rowCount !== 1) {
+ throw new Error(`MSP ${msp.id} was not inserted into the DB`);
+ }
+
+ return txInsertResponse.rows[0].id;
+ }
+
+ /**
+ * Insert discovered orderer to the database.
+ */
+ private async insertDiscoveryOrderer(
+ discoveryMSPId: string,
+ orderer: GetDiscoveryResultsResponseV1OrderersValueEndpointsInner,
+ ): Promise {
+ this.log.debug(
+ `Insert to fabric.discovery_orderers orderer ${orderer.name})`,
+ );
+
+ const txInsertResponse = await this.client.query(
+ `INSERT INTO
+ fabric.discovery_orderers("name", "host", "port", "discovery_msp_id")
+ VALUES ($1, $2, $3, $4)
+ RETURNING id;`,
+ [orderer.name, orderer.host, orderer.port, discoveryMSPId],
+ );
+ if (txInsertResponse.rowCount !== 1) {
+ throw new Error(`Orderer ${orderer.name} was not inserted into the DB`);
+ }
+
+ return txInsertResponse.rows[0].id;
+ }
+
+ /**
+ * Insert discovered peer to the database.
+ */
+ private async insertDiscoveryPeer(
+ discoveryMSPId: string,
+ peer: GetDiscoveryResultsResponseV1PeersByMSPValuePeersInner,
+ ): Promise {
+ this.log.debug(`Insert to fabric.discovery_peers peer ${peer.name})`);
+
+ const txInsertResponse = await this.client.query(
+ `INSERT INTO
+ fabric.discovery_peers("name", "endpoint", "ledger_height", "chaincodes", "discovery_msp_id")
+ VALUES ($1, $2, $3, $4, $5)
+ RETURNING id;`,
+ [
+ peer.name,
+ peer.endpoint,
+ peer.ledgerHeight,
+ JSON.stringify(peer.chaincodes),
+ discoveryMSPId,
+ ],
+ );
+ if (txInsertResponse.rowCount !== 1) {
+ throw new Error(`Peer ${peer.name} was not inserted into the DB`);
+ }
+
+ return txInsertResponse.rows[0].id;
+ }
+
+ /**
+ * Insert fabric discovery results to the database.
+ * @param discoveryResults response from getDiscoveryResults endpoint of fabric connector.
+ */
+ public async insertDiscoveryResults(
+ discoveryResults: GetDiscoveryResultsResponseV1,
+ ): Promise {
+ this.assertConnected();
+
+ this.log.debug("Insert discovery results started");
+
+ try {
+ await this.client.query("BEGIN");
+
+ const discoveryMSPIds = new Map();
+
+ // Insert MSPs
+ for (const msp of Object.values(discoveryResults.msps)) {
+ const discoveryMSPId = await this.insertDiscoveryMsp(msp);
+ discoveryMSPIds.set(msp.id, discoveryMSPId);
+ }
+
+ // Insert Orderers
+ for (const mspId of Object.keys(discoveryResults.orderers)) {
+ for (const orderer of discoveryResults.orderers[mspId].endpoints) {
+ const discoveryMSPId = discoveryMSPIds.get(mspId);
+ if (!discoveryMSPId) {
+ this.log.warn(
+ `Unexpected Error! Could not find ${discoveryMSPId} in MSP inserted to the database`,
+ );
+ continue;
+ }
+ await this.insertDiscoveryOrderer(discoveryMSPId, orderer);
+ }
+ }
+
+ // Insert Peers
+ for (const mspId of Object.keys(discoveryResults.peersByMSP)) {
+ for (const peer of discoveryResults.peersByMSP[mspId].peers) {
+ const discoveryMSPId = discoveryMSPIds.get(mspId);
+ if (!discoveryMSPId) {
+ this.log.warn(
+ `Unexpected Error! Could not find ${discoveryMSPId} in MSP inserted to the database`,
+ );
+ continue;
+ }
+ await this.insertDiscoveryPeer(discoveryMSPId, peer);
+ }
+ }
+
+ await this.client.query("COMMIT");
+ } catch (err: unknown) {
+ await this.client.query("ROLLBACK");
+ this.log.warn("insertDiscoveryResults() exception:", err);
+ throw new Error(
+ "Could not insert discovery results into the database - transaction reverted",
+ );
+ }
+ }
}
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-persistence-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts
index 76733ba783..049b408cfc 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts
+++ b/packages/cactus-plugin-persistence-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts
@@ -23,6 +23,25 @@ import type { RequestArgs } from './base';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError } from './base';
+/**
+ *
+ * @export
+ * @interface DiscoverNetworkResponseV1
+ */
+export interface DiscoverNetworkResponseV1 {
+ /**
+ *
+ * @type {boolean}
+ * @memberof DiscoverNetworkResponseV1
+ */
+ 'status': boolean;
+ /**
+ *
+ * @type {string}
+ * @memberof DiscoverNetworkResponseV1
+ */
+ 'message': string;
+}
/**
*
* @export
@@ -111,6 +130,36 @@ export interface TrackedOperationV1 {
*/
export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
return {
+ /**
+ *
+ * @summary Refresh Fabric network structure in the database through discovery.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ discoverNetworkV1: async (options: AxiosRequestConfig = {}): Promise => {
+ const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network`;
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
/**
*
* @summary Get the status of persistence plugin for fabric
@@ -151,6 +200,16 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati
export const DefaultApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
return {
+ /**
+ *
+ * @summary Refresh Fabric network structure in the database through discovery.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async discoverNetworkV1(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.discoverNetworkV1(options);
+ return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+ },
/**
*
* @summary Get the status of persistence plugin for fabric
@@ -171,6 +230,15 @@ export const DefaultApiFp = function(configuration?: Configuration) {
export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = DefaultApiFp(configuration)
return {
+ /**
+ *
+ * @summary Refresh Fabric network structure in the database through discovery.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ discoverNetworkV1(options?: any): AxiosPromise {
+ return localVarFp.discoverNetworkV1(options).then((request) => request(axios, basePath));
+ },
/**
*
* @summary Get the status of persistence plugin for fabric
@@ -190,6 +258,17 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa
* @extends {BaseAPI}
*/
export class DefaultApi extends BaseAPI {
+ /**
+ *
+ * @summary Refresh Fabric network structure in the database through discovery.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof DefaultApi
+ */
+ public discoverNetworkV1(options?: AxiosRequestConfig) {
+ return DefaultApiFp(this.configuration).discoverNetworkV1(options).then((request) => request(this.axios, this.basePath));
+ }
+
/**
*
* @summary Get the status of persistence plugin for fabric
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/typescript/plugin-persistence-fabric.ts b/packages/cactus-plugin-persistence-fabric/src/main/typescript/plugin-persistence-fabric.ts
index 9857561734..fe07ce3511 100644
--- a/packages/cactus-plugin-persistence-fabric/src/main/typescript/plugin-persistence-fabric.ts
+++ b/packages/cactus-plugin-persistence-fabric/src/main/typescript/plugin-persistence-fabric.ts
@@ -30,6 +30,7 @@ import {
import OAS from "../json/openapi.json";
import { StatusEndpointV1 } from "./web-services/status-endpoint-v1";
+import { DiscoverNetworkEndpointV1 } from "./web-services/discover-network-endpoint-v1";
import PostgresDatabaseClient from "./db-client/db-client";
import {
StatusResponseV1,
@@ -369,6 +370,13 @@ export class PluginPersistenceFabric
});
endpoints.push(endpoint);
}
+ {
+ const endpoint = new DiscoverNetworkEndpointV1({
+ connector: this,
+ logLevel: this.options.logLevel,
+ });
+ endpoints.push(endpoint);
+ }
this.endpoints = endpoints;
log.info(`Instantiated web services for plugin ${pkgName} OK`, {
@@ -407,6 +415,9 @@ export class PluginPersistenceFabric
// Synchronize the current DB state
this.lastSeenBlock = await this.syncAll();
+ // Update fabric network structure
+ await this.discoverNetwork();
+
const blocksObservable = this.apiClient.watchBlocksV1({
channelName: this.channelName,
gatewayOptions: this.gatewayOptions,
@@ -531,4 +542,33 @@ export class PluginPersistenceFabric
this.removeTrackedOperation(operationId);
}
}
+
+ /**
+ * Synchronize current ledger structure (discovery results) with the database.
+ * Discovery should be enabled on the conenctor for this method to work.
+ * Any errors are ignored (i.e. this discovery is optional), but warning message will be printed.
+ */
+ public async discoverNetwork() {
+ const operationId = uuidv4();
+ this.addTrackedOperation(operationId, "discoverNetwork");
+
+ try {
+ this.log.info("discoverNetwork() started...");
+
+ const discoveryResultsResponse =
+ await this.apiClient.getDiscoveryResultsV1({
+ channelName: this.channelName,
+ gatewayOptions: this.gatewayOptions,
+ });
+
+ const discoveryResults = discoveryResultsResponse.data;
+
+ await this.dbClient.insertDiscoveryResults(discoveryResults);
+ this.log.info("Fabric network updated.");
+ } catch (err) {
+ this.log.warn("Could not update discovery results:", err);
+ } finally {
+ this.removeTrackedOperation(operationId);
+ }
+ }
}
diff --git a/packages/cactus-plugin-persistence-fabric/src/main/typescript/web-services/discover-network-endpoint-v1.ts b/packages/cactus-plugin-persistence-fabric/src/main/typescript/web-services/discover-network-endpoint-v1.ts
new file mode 100644
index 0000000000..eb02c8c332
--- /dev/null
+++ b/packages/cactus-plugin-persistence-fabric/src/main/typescript/web-services/discover-network-endpoint-v1.ts
@@ -0,0 +1,110 @@
+/**
+ * OpenAPI endpoint (POST) for refreshing network structure in the database.
+ */
+
+import {
+ Logger,
+ Checks,
+ LogLevelDesc,
+ LoggerProvider,
+ IAsyncProvider,
+} from "@hyperledger/cactus-common";
+import type {
+ IEndpointAuthzOptions,
+ IExpressRequestHandler,
+ IWebServiceEndpoint,
+} from "@hyperledger/cactus-core-api";
+import {
+ handleRestEndpointException,
+ registerWebServiceEndpoint,
+} from "@hyperledger/cactus-core";
+
+import { PluginPersistenceFabric } from "../plugin-persistence-fabric";
+import OAS from "../../json/openapi.json";
+
+import type { Express, Request, Response } from "express";
+
+export interface IDiscoverNetworkEndpointV1Options {
+ logLevel?: LogLevelDesc;
+ connector: PluginPersistenceFabric;
+}
+
+/**
+ * OpenAPI endpoint (GET) for reading status of the persistence plugin.
+ */
+export class DiscoverNetworkEndpointV1 implements IWebServiceEndpoint {
+ public static readonly CLASS_NAME = "DiscoverNetworkEndpointV1";
+
+ private readonly log: Logger;
+
+ public get className(): string {
+ return DiscoverNetworkEndpointV1.CLASS_NAME;
+ }
+
+ constructor(public readonly options: IDiscoverNetworkEndpointV1Options) {
+ const fnTag = `${this.className}#constructor()`;
+ Checks.truthy(options, `${fnTag} arg options`);
+ Checks.truthy(options.connector, `${fnTag} arg options.connector`);
+
+ const level = this.options.logLevel || "INFO";
+ const label = this.className;
+ this.log = LoggerProvider.getOrCreate({ level, label });
+ }
+
+ public getOasPath(): any {
+ return OAS.paths[
+ "/api/v1/plugins/@hyperledger/cactus-plugin-persistence-fabric/discover-network"
+ ];
+ }
+
+ public getPath(): string {
+ const apiPath = this.getOasPath();
+ return apiPath.post["x-hyperledger-cacti"].http.path;
+ }
+
+ public getVerbLowerCase(): string {
+ const apiPath = this.getOasPath();
+ return apiPath.post["x-hyperledger-cacti"].http.verbLowerCase;
+ }
+
+ public getOperationId(): string {
+ return this.getOasPath().get.operationId;
+ }
+
+ getAuthorizationOptionsProvider(): IAsyncProvider {
+ // TODO: make this an injectable dependency in the constructor
+ return {
+ get: async () => ({
+ isProtected: true,
+ requiredRoles: [],
+ }),
+ };
+ }
+
+ public async registerExpress(
+ expressApp: Express,
+ ): Promise {
+ await registerWebServiceEndpoint(expressApp, this);
+ return this;
+ }
+
+ public getExpressRequestHandler(): IExpressRequestHandler {
+ return this.handleRequest.bind(this);
+ }
+
+ public async handleRequest(_req: Request, res: Response): Promise {
+ const reqTag = `${this.getVerbLowerCase()} - ${this.getPath()}`;
+ this.log.debug(reqTag);
+
+ try {
+ await this.options.connector.discoverNetwork();
+ res.status(200).json({
+ status: true,
+ message: "Discovery done.",
+ });
+ } catch (ex) {
+ const errorMsg = `Crash while serving ${reqTag}`;
+ handleRestEndpointException({ errorMsg, log: this.log, error: ex, res });
+ }
+ }
+}
diff --git a/packages/cactus-plugin-persistence-fabric/src/test/sql/insert-test-data.sql b/packages/cactus-plugin-persistence-fabric/src/test/sql/insert-test-data.sql
index f61fc68623..8bdb6a0c87 100644
--- a/packages/cactus-plugin-persistence-fabric/src/test/sql/insert-test-data.sql
+++ b/packages/cactus-plugin-persistence-fabric/src/test/sql/insert-test-data.sql
@@ -548,6 +548,115 @@ j8Fxno3p3EAmocwmZyu4wxnVmqfKdhs=
'
);
+--
+-- Data for Name: discovery_msp; Type: TABLE DATA; Schema: fabric; Owner: postgres
+--
+INSERT INTO
+ fabric.discovery_msp (
+ id,
+ mspid,
+ name,
+ organizational_unit_identifiers,
+ admins
+ )
+VALUES
+ (
+ '75ecbf61-5c81-4928-a2c3-316c136610bf',
+ 'OrdererMSP',
+ 'OrdererMSP',
+ '[]',
+ ''
+ );
+
+INSERT INTO
+ fabric.discovery_msp (
+ id,
+ mspid,
+ name,
+ organizational_unit_identifiers,
+ admins
+ )
+VALUES
+ (
+ '38f053a5-f3f4-49fc-96a1-6d0dacc21837',
+ 'Org1MSP',
+ 'Org1MSP',
+ '[]',
+ ''
+ );
+
+INSERT INTO
+ fabric.discovery_msp (
+ id,
+ mspid,
+ name,
+ organizational_unit_identifiers,
+ admins
+ )
+VALUES
+ (
+ 'acd8eab1-59a0-4a89-a4f4-4d222ed2c3f2',
+ 'Org2MSP',
+ 'Org2MSP',
+ '[]',
+ ''
+ );
+
+--
+-- Data for Name: discovery_orderers; Type: TABLE DATA; Schema: fabric; Owner: postgres
+--
+INSERT INTO
+ fabric.discovery_orderers (id, name, host, port, discovery_msp_id)
+VALUES
+ (
+ 'd165280d-93c1-4710-9829-88da847b6431',
+ 'orderer.example.com:7050',
+ 'orderer.example.com',
+ 7050,
+ '75ecbf61-5c81-4928-a2c3-316c136610bf'
+ );
+
+--
+-- Data for Name: discovery_peers; Type: TABLE DATA; Schema: fabric; Owner: postgres
+--
+INSERT INTO
+ fabric.discovery_peers (
+ id,
+ name,
+ endpoint,
+ ledger_height,
+ chaincodes,
+ discovery_msp_id
+ )
+VALUES
+ (
+ '9819add6-c50d-467f-8fe8-eb1c4089ba9a',
+ 'peer0.org1.example.com:7051',
+ 'peer0.org1.example.com:7051',
+ 7,
+ '[{"name":"basic","version":"1"},{"name":"_lifecycle","version":"1"}]',
+ '38f053a5-f3f4-49fc-96a1-6d0dacc21837'
+ );
+
+INSERT INTO
+ fabric.discovery_peers (
+ id,
+ name,
+ endpoint,
+ ledger_height,
+ chaincodes,
+ discovery_msp_id
+ )
+VALUES
+ (
+ 'a3969e81-cb5b-4b99-be9c-4ca7e9384130',
+ 'peer0.org2.example.com:9051',
+ 'peer0.org2.example.com:9051',
+ 7,
+ '[{"name":"basic","version":"1"},{"name":"_lifecycle","version":"1"}]',
+ 'acd8eab1-59a0-4a89-a4f4-4d222ed2c3f2'
+ );
+
--
-- Data for Name: transaction; Type: TABLE DATA; Schema: fabric; Owner: postgres
--
diff --git a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabrc-postgresql-db-client.test.ts b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabrc-postgresql-db-client.test.ts
index 0885997c4e..71d089651f 100644
--- a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabrc-postgresql-db-client.test.ts
+++ b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabrc-postgresql-db-client.test.ts
@@ -25,7 +25,11 @@ import {
import PostgresDatabaseClient from "../../../main/typescript/db-client/db-client";
import "jest-extended";
-import { invalidSampleBlock, sampleBlock } from "./sample-block";
+import {
+ invalidSampleBlock,
+ sampleBlock,
+ sampleDiscoveryResults,
+} from "./sample-data";
// Logger setup
const log: Logger = LoggerProvider.getOrCreate({
@@ -98,6 +102,27 @@ describe("Fabric persistence PostgreSQL PostgresDatabaseClient tests", () => {
return response.rows;
}
+ async function getDiscoveryMSPs() {
+ const response = await dbClient.client.query(
+ "SELECT * FROM fabric.discovery_msp",
+ );
+ return response.rows;
+ }
+
+ async function getDiscoveryPeers() {
+ const response = await dbClient.client.query(
+ "SELECT p.*, m.mspid FROM fabric.discovery_peers p JOIN fabric.discovery_msp m ON p.discovery_msp_id = m.id;",
+ );
+ return response.rows;
+ }
+
+ async function getDiscoveryOrderers() {
+ const response = await dbClient.client.query(
+ "SELECT o.*, m.mspid FROM fabric.discovery_orderers o JOIN fabric.discovery_msp m ON o.discovery_msp_id = m.id;",
+ );
+ return response.rows;
+ }
+
//////////////////////////////////
// Environment Setup
//////////////////////////////////
@@ -153,6 +178,9 @@ describe("Fabric persistence PostgreSQL PostgresDatabaseClient tests", () => {
"transaction",
"transaction_action",
"transaction_action_endorsement",
+ "discovery_msp",
+ "discovery_orderers",
+ "discovery_peers",
].sort(),
);
@@ -377,4 +405,38 @@ describe("Fabric persistence PostgreSQL PostgresDatabaseClient tests", () => {
.sort();
expect(missingBlocksNumbers).toEqual([1, 2, 4, 5]);
});
+
+ test("insertDiscoveryResults updates ledger structure", async () => {
+ await dbClient.insertDiscoveryResults(sampleDiscoveryResults);
+
+ // Assert MSPs
+ const dbMsps = await getDiscoveryMSPs();
+ expect(dbMsps.length).toEqual(3);
+ for (const msp of dbMsps) {
+ expect(msp.mspid).toBeTruthy();
+ expect(msp.name).toBeTruthy();
+ }
+
+ // Assert Peers
+ const dbPeers = await getDiscoveryPeers();
+ expect(dbPeers.length).toEqual(2);
+ for (const peer of dbPeers) {
+ expect(peer.name).toBeTruthy();
+ expect(peer.endpoint).toBeTruthy();
+ expect(peer.ledger_height).toBeTruthy();
+ expect(peer.chaincodes).toBeTruthy();
+ expect(peer.discovery_msp_id).toBeTruthy();
+ expect(peer.mspid).toBeTruthy();
+ }
+
+ // Assert Orderers
+ const dbOrderers = await getDiscoveryOrderers();
+ expect(dbOrderers.length).toEqual(1);
+ const dbOrderer = dbOrderers[0];
+ expect(dbOrderer.name).toBeTruthy();
+ expect(dbOrderer.host).toBeTruthy();
+ expect(dbOrderer.port).toBeTruthy();
+ expect(dbOrderer.discovery_msp_id).toBeTruthy();
+ expect(dbOrderer.mspid).toBeTruthy();
+ });
});
diff --git a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabric-functional.test.ts b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabric-functional.test.ts
index 94f77b6531..161a4462f4 100644
--- a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabric-functional.test.ts
+++ b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/persistence-fabric-functional.test.ts
@@ -420,4 +420,53 @@ describe("Fabric persistence plugin tests", () => {
},
testTimeout,
);
+
+ test(
+ "Discovery network pushes current ledger structure to the database",
+ async () => {
+ await persistence.discoverNetwork();
+
+ const allInsertCalls = (
+ dbClientInstance.insertDiscoveryResults as jest.Mock
+ ).mock.calls;
+ expect(allInsertCalls.length).toBe(1);
+ const discoveryInsertArg = allInsertCalls[0][0];
+
+ // Assert required fields provided
+ expect(Object.keys(discoveryInsertArg.msps).length).toBeGreaterThan(0);
+ expect(Object.keys(discoveryInsertArg.orderers).length).toBeGreaterThan(
+ 0,
+ );
+ expect(Object.keys(discoveryInsertArg.peersByMSP).length).toBeGreaterThan(
+ 0,
+ );
+ expect(discoveryInsertArg.timestamp).toBeTruthy();
+ },
+ testTimeout,
+ );
+
+ test(
+ "Network discovery is called when starting block monitoring",
+ async () => {
+ try {
+ await new Promise((resolve, reject) => {
+ (
+ dbClientInstance.getMissingBlocksInRange as jest.Mock
+ ).mockReturnValue([]);
+
+ (
+ dbClientInstance.insertDiscoveryResults as jest.Mock
+ ).mockImplementation((discoveryResults) => resolve(discoveryResults));
+
+ persistence.startMonitor((err) => {
+ reject(err);
+ });
+ log.debug("Persistence plugin block monitoring started.");
+ });
+ } finally {
+ persistence.stopMonitor();
+ }
+ },
+ testTimeout,
+ );
});
diff --git a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/sample-block.ts b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/sample-block.ts
deleted file mode 100644
index b474e0d55e..0000000000
--- a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/sample-block.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-export const sampleBlock = {
- blockNumber: 3,
- blockHash:
- "0xe6656aa10d9f73fde8db5b0ce6bba9a2bc3118c72ef9d69b53b9f7c512139d60",
- previousBlockHash:
- "0xf8c0f8c4d4ae2f3c2140a1e63d940734d27549fa8829e1c5c994bcc3182f0caa",
- transactionCount: 1,
- cactiTransactionsEvents: [
- {
- hash: "4affb3661c2a8075e52e8e6826e1768616bb1f8c588b1baa54368a3996a54de8",
- channelId: "mychannel",
- timestamp: "2024-06-10T10:55:26.036Z",
- protocolVersion: 0,
- transactionType: "ENDORSER_TRANSACTION",
- epoch: 0,
- actions: [
- {
- functionName: "MyFunctionName",
- functionArgs: ["foo", "bar"],
- chaincodeId: "myChaincode",
- creator: {
- mspid: "Org1MSP",
- cert: {
- serialNumber: "16C8C9A05A2B7EFA6ED794F28A2FBCE6DED1C86C",
- subject:
- "C=US\nST=North Carolina\nO=Hyperledger\nOU=admin\nCN=org1admin",
- issuer:
- "C=US\nST=North Carolina\nL=Durham\nO=org1.example.com\nCN=ca.org1.example.com",
- subjectAltName: "DNS:9071369d9d11",
- validFrom: "Jun 10 10:50:00 2024 GMT",
- validTo: "Jun 10 10:55:00 2025 GMT",
- pem: "-----BEGIN CERTIFICATE-----\nMIICqTCCAlCgAwIBAgIUFsjJoForfvpu15Tyii+85t7RyGwwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjQwNjEwMTA1MDAwWhcNMjUwNjEwMTA1NTAw\nWjBgMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV\nBAoTC0h5cGVybGVkZ2VyMQ4wDAYDVQQLEwVhZG1pbjESMBAGA1UEAxMJb3JnMWFk\nbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEaCjVDW8X3Fpa7lXTrjNACJG\nmslK1ppx9uzh9Fqk2lLN7GxcJSi2hcIyTK9+udwbRynDHl1HgMG/fLBfqrkCNKOB\n1zCB1DAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUTw/b\nSs21vEgoQbb2wnwXF4DkCTEwHwYDVR0jBBgwFoAUgN29gMPVb3dfnq0ngxTg67qy\niQkwFwYDVR0RBBAwDoIMOTA3MTM2OWQ5ZDExMFsGCCoDBAUGBwgBBE97ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMWFk\nbWluIiwiaGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIGzNQ3Ut\niHpsKZzzIadYTY7TlC7FliD+XI89FyzM2RqoAiALJ2yU42wNnfrRuByQQN9cHz1j\nArKZknDfP6HYxUS0RQ==\n-----END CERTIFICATE-----\n",
- },
- },
- endorsements: [
- {
- signer: {
- mspid: "Org1MSP",
- cert: {
- serialNumber: "3D697828B3244EDC75A95CCC30FC5013B904F6E5",
- subject:
- "C=US\nST=North Carolina\nO=Hyperledger\nOU=peer\nCN=peer0",
- issuer:
- "C=US\nST=North Carolina\nL=Durham\nO=org1.example.com\nCN=ca.org1.example.com",
- subjectAltName: "DNS:9071369d9d11",
- validFrom: "Jun 10 10:50:00 2024 GMT",
- validTo: "Jun 10 10:55:00 2025 GMT",
- pem: "-----BEGIN CERTIFICATE-----\nMIICnzCCAkagAwIBAgIUPWl4KLMkTtx1qVzMMPxQE7kE9uUwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjQwNjEwMTA1MDAwWhcNMjUwNjEwMTA1NTAw\nWjBbMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV\nBAoTC0h5cGVybGVkZ2VyMQ0wCwYDVQQLEwRwZWVyMQ4wDAYDVQQDEwVwZWVyMDBZ\nMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOBN1m+Sd4tJgk7cj/2tjncS0DDaZrpB\nXScgGyyvFu7WvUNAX5huTiUcP6RPnfQ2op1fgaPvHwVWQ4sLwU3wYqSjgdIwgc8w\nDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOWzZpC41lih\n5kCb9Dhd/w626Ve7MB8GA1UdIwQYMBaAFIDdvYDD1W93X56tJ4MU4Ou6sokJMBcG\nA1UdEQQQMA6CDDkwNzEzNjlkOWQxMTBWBggqAwQFBgcIAQRKeyJhdHRycyI6eyJo\nZi5BZmZpbGlhdGlvbiI6IiIsImhmLkVucm9sbG1lbnRJRCI6InBlZXIwIiwiaGYu\nVHlwZSI6InBlZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgCNafIs0XRatMvyu1Mj62\n4LVXfIgyolfaFaOZaFtjJdYCIA4bciJH/vMOdbxoAbNr7B83P1GEfHLdmd2yy7D1\nVi3u\n-----END CERTIFICATE-----\n",
- },
- },
- signature:
- "0x304402205f576c57e2c29806c7636e6ed4d9b02e842ccbbd01dd333c8716efa927e74bac022079be4c059a36fba7ef9a767275e7d8e0f020a6898d930a9d9f2ab93a5e0d8a9b",
- },
- ],
- },
- ],
- },
- ],
-};
-
-export const invalidSampleBlock = {
- blockNumber: 3,
- blockHash:
- "0xe6656aa10d9f73fde8db5b0ce6bba9a2bc3118c72ef9d69b53b9f7c512139d60",
- previousBlockHash:
- "0xf8c0f8c4d4ae2f3c2140a1e63d940734d27549fa8829e1c5c994bcc3182f0caa",
- transactionCount: 1,
- cactiTransactionsEvents: [
- {
- hash: "4affb3661c2a8075e52e8e6826e1768616bb1f8c588b1baa54368a3996a54de8",
- channelId: "mychannel",
- timestamp: "2024-06-10T10:55:26.036Z",
- protocolVersion: 0,
- type: "ENDORSER_TRANSACTION",
- epoch: 0,
- actions: [
- {
- functionName: "MyFunctionName",
- functionArgs: ["foo", "bar"],
- chaincodeId: "myChaincode",
- creator: {
- mspid: "Org1MSP",
- cert: {
- serialNumber: "16C8C9A05A2B7EFA6ED794F28A2FBCE6DED1C86C",
- subject:
- "C=US\nST=North Carolina\nO=Hyperledger\nOU=admin\nCN=org1admin",
- issuer:
- "C=US\nST=North Carolina\nL=Durham\nO=org1.example.com\nCN=ca.org1.example.com",
- subjectAltName: "DNS:9071369d9d11",
- validFrom: "Jun 10 10:50:00 2024 GMT",
- validTo: "Jun 10 10:55:00 2025 GMT",
- pem: "-----BEGIN CERTIFICATE-----\nMIICqTCCAlCgAwIBAgIUFsjJoForfvpu15Tyii+85t7RyGwwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjQwNjEwMTA1MDAwWhcNMjUwNjEwMTA1NTAw\nWjBgMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV\nBAoTC0h5cGVybGVkZ2VyMQ4wDAYDVQQLEwVhZG1pbjESMBAGA1UEAxMJb3JnMWFk\nbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEaCjVDW8X3Fpa7lXTrjNACJG\nmslK1ppx9uzh9Fqk2lLN7GxcJSi2hcIyTK9+udwbRynDHl1HgMG/fLBfqrkCNKOB\n1zCB1DAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUTw/b\nSs21vEgoQbb2wnwXF4DkCTEwHwYDVR0jBBgwFoAUgN29gMPVb3dfnq0ngxTg67qy\niQkwFwYDVR0RBBAwDoIMOTA3MTM2OWQ5ZDExMFsGCCoDBAUGBwgBBE97ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMWFk\nbWluIiwiaGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIGzNQ3Ut\niHpsKZzzIadYTY7TlC7FliD+XI89FyzM2RqoAiALJ2yU42wNnfrRuByQQN9cHz1j\nArKZknDfP6HYxUS0RQ==\n-----END CERTIFICATE-----\n",
- },
- },
- endorsements: [
- {
- signer: {
- foo: "Org1MSP",
- },
- },
- ],
- },
- ],
- },
- ],
-};
diff --git a/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/sample-data.ts b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/sample-data.ts
new file mode 100644
index 0000000000..379420c8b5
--- /dev/null
+++ b/packages/cactus-plugin-persistence-fabric/src/test/typescript/integration/sample-data.ts
@@ -0,0 +1,209 @@
+export const sampleBlock = {
+ blockNumber: 3,
+ blockHash:
+ "0xe6656aa10d9f73fde8db5b0ce6bba9a2bc3118c72ef9d69b53b9f7c512139d60",
+ previousBlockHash:
+ "0xf8c0f8c4d4ae2f3c2140a1e63d940734d27549fa8829e1c5c994bcc3182f0caa",
+ transactionCount: 1,
+ cactiTransactionsEvents: [
+ {
+ hash: "4affb3661c2a8075e52e8e6826e1768616bb1f8c588b1baa54368a3996a54de8",
+ channelId: "mychannel",
+ timestamp: "2024-06-10T10:55:26.036Z",
+ protocolVersion: 0,
+ transactionType: "ENDORSER_TRANSACTION",
+ epoch: 0,
+ actions: [
+ {
+ functionName: "MyFunctionName",
+ functionArgs: ["foo", "bar"],
+ chaincodeId: "myChaincode",
+ creator: {
+ mspid: "Org1MSP",
+ cert: {
+ serialNumber: "16C8C9A05A2B7EFA6ED794F28A2FBCE6DED1C86C",
+ subject:
+ "C=US\nST=North Carolina\nO=Hyperledger\nOU=admin\nCN=org1admin",
+ issuer:
+ "C=US\nST=North Carolina\nL=Durham\nO=org1.example.com\nCN=ca.org1.example.com",
+ subjectAltName: "DNS:9071369d9d11",
+ validFrom: "Jun 10 10:50:00 2024 GMT",
+ validTo: "Jun 10 10:55:00 2025 GMT",
+ pem: "-----BEGIN CERTIFICATE-----\nMIICqTCCAlCgAwIBAgIUFsjJoForfvpu15Tyii+85t7RyGwwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjQwNjEwMTA1MDAwWhcNMjUwNjEwMTA1NTAw\nWjBgMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV\nBAoTC0h5cGVybGVkZ2VyMQ4wDAYDVQQLEwVhZG1pbjESMBAGA1UEAxMJb3JnMWFk\nbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEaCjVDW8X3Fpa7lXTrjNACJG\nmslK1ppx9uzh9Fqk2lLN7GxcJSi2hcIyTK9+udwbRynDHl1HgMG/fLBfqrkCNKOB\n1zCB1DAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUTw/b\nSs21vEgoQbb2wnwXF4DkCTEwHwYDVR0jBBgwFoAUgN29gMPVb3dfnq0ngxTg67qy\niQkwFwYDVR0RBBAwDoIMOTA3MTM2OWQ5ZDExMFsGCCoDBAUGBwgBBE97ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMWFk\nbWluIiwiaGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIGzNQ3Ut\niHpsKZzzIadYTY7TlC7FliD+XI89FyzM2RqoAiALJ2yU42wNnfrRuByQQN9cHz1j\nArKZknDfP6HYxUS0RQ==\n-----END CERTIFICATE-----\n",
+ },
+ },
+ endorsements: [
+ {
+ signer: {
+ mspid: "Org1MSP",
+ cert: {
+ serialNumber: "3D697828B3244EDC75A95CCC30FC5013B904F6E5",
+ subject:
+ "C=US\nST=North Carolina\nO=Hyperledger\nOU=peer\nCN=peer0",
+ issuer:
+ "C=US\nST=North Carolina\nL=Durham\nO=org1.example.com\nCN=ca.org1.example.com",
+ subjectAltName: "DNS:9071369d9d11",
+ validFrom: "Jun 10 10:50:00 2024 GMT",
+ validTo: "Jun 10 10:55:00 2025 GMT",
+ pem: "-----BEGIN CERTIFICATE-----\nMIICnzCCAkagAwIBAgIUPWl4KLMkTtx1qVzMMPxQE7kE9uUwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjQwNjEwMTA1MDAwWhcNMjUwNjEwMTA1NTAw\nWjBbMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV\nBAoTC0h5cGVybGVkZ2VyMQ0wCwYDVQQLEwRwZWVyMQ4wDAYDVQQDEwVwZWVyMDBZ\nMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOBN1m+Sd4tJgk7cj/2tjncS0DDaZrpB\nXScgGyyvFu7WvUNAX5huTiUcP6RPnfQ2op1fgaPvHwVWQ4sLwU3wYqSjgdIwgc8w\nDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOWzZpC41lih\n5kCb9Dhd/w626Ve7MB8GA1UdIwQYMBaAFIDdvYDD1W93X56tJ4MU4Ou6sokJMBcG\nA1UdEQQQMA6CDDkwNzEzNjlkOWQxMTBWBggqAwQFBgcIAQRKeyJhdHRycyI6eyJo\nZi5BZmZpbGlhdGlvbiI6IiIsImhmLkVucm9sbG1lbnRJRCI6InBlZXIwIiwiaGYu\nVHlwZSI6InBlZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgCNafIs0XRatMvyu1Mj62\n4LVXfIgyolfaFaOZaFtjJdYCIA4bciJH/vMOdbxoAbNr7B83P1GEfHLdmd2yy7D1\nVi3u\n-----END CERTIFICATE-----\n",
+ },
+ },
+ signature:
+ "0x304402205f576c57e2c29806c7636e6ed4d9b02e842ccbbd01dd333c8716efa927e74bac022079be4c059a36fba7ef9a767275e7d8e0f020a6898d930a9d9f2ab93a5e0d8a9b",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+};
+
+export const invalidSampleBlock = {
+ blockNumber: 3,
+ blockHash:
+ "0xe6656aa10d9f73fde8db5b0ce6bba9a2bc3118c72ef9d69b53b9f7c512139d60",
+ previousBlockHash:
+ "0xf8c0f8c4d4ae2f3c2140a1e63d940734d27549fa8829e1c5c994bcc3182f0caa",
+ transactionCount: 1,
+ cactiTransactionsEvents: [
+ {
+ hash: "4affb3661c2a8075e52e8e6826e1768616bb1f8c588b1baa54368a3996a54de8",
+ channelId: "mychannel",
+ timestamp: "2024-06-10T10:55:26.036Z",
+ protocolVersion: 0,
+ type: "ENDORSER_TRANSACTION",
+ epoch: 0,
+ actions: [
+ {
+ functionName: "MyFunctionName",
+ functionArgs: ["foo", "bar"],
+ chaincodeId: "myChaincode",
+ creator: {
+ mspid: "Org1MSP",
+ cert: {
+ serialNumber: "16C8C9A05A2B7EFA6ED794F28A2FBCE6DED1C86C",
+ subject:
+ "C=US\nST=North Carolina\nO=Hyperledger\nOU=admin\nCN=org1admin",
+ issuer:
+ "C=US\nST=North Carolina\nL=Durham\nO=org1.example.com\nCN=ca.org1.example.com",
+ subjectAltName: "DNS:9071369d9d11",
+ validFrom: "Jun 10 10:50:00 2024 GMT",
+ validTo: "Jun 10 10:55:00 2025 GMT",
+ pem: "-----BEGIN CERTIFICATE-----\nMIICqTCCAlCgAwIBAgIUFsjJoForfvpu15Tyii+85t7RyGwwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjQwNjEwMTA1MDAwWhcNMjUwNjEwMTA1NTAw\nWjBgMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV\nBAoTC0h5cGVybGVkZ2VyMQ4wDAYDVQQLEwVhZG1pbjESMBAGA1UEAxMJb3JnMWFk\nbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEaCjVDW8X3Fpa7lXTrjNACJG\nmslK1ppx9uzh9Fqk2lLN7GxcJSi2hcIyTK9+udwbRynDHl1HgMG/fLBfqrkCNKOB\n1zCB1DAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUTw/b\nSs21vEgoQbb2wnwXF4DkCTEwHwYDVR0jBBgwFoAUgN29gMPVb3dfnq0ngxTg67qy\niQkwFwYDVR0RBBAwDoIMOTA3MTM2OWQ5ZDExMFsGCCoDBAUGBwgBBE97ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMWFk\nbWluIiwiaGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIGzNQ3Ut\niHpsKZzzIadYTY7TlC7FliD+XI89FyzM2RqoAiALJ2yU42wNnfrRuByQQN9cHz1j\nArKZknDfP6HYxUS0RQ==\n-----END CERTIFICATE-----\n",
+ },
+ },
+ endorsements: [
+ {
+ signer: {
+ foo: "Org1MSP",
+ },
+ },
+ ],
+ },
+ ],
+ },
+ ],
+};
+
+export const sampleDiscoveryResults = {
+ msps: {
+ Org2MSP: {
+ id: "Org2MSP",
+ name: "Org2MSP",
+ organizationalUnitIdentifiers: [],
+ rootCerts:
+ "-----BEGIN CERTIFICATE-----\nMIICHjCCAcWgAwIBAgIUfFNit/ZNZY2SIbGN6ekejAdRoikwCgYIKoZIzj0EAwIw\nbDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\nc2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\nMi5leGFtcGxlLmNvbTAeFw0yNTA0MDIwODI2MDBaFw00MDAzMjkwODI2MDBaMGwx\nCzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\nZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARofvaM3udqgShD\njgunnP4hBLepJAdJJXVaF4gGwjGN7u0OJsUYefwoaZsIieJ+fJkpk+KWfV6esw5l\nopNQ7k0/o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\nBgNVHQ4EFgQUngIcE6RHSr5A0IcqEyqz6Gi27l4wCgYIKoZIzj0EAwIDRwAwRAIg\nWSvPOIUDa/rTJPRR9t54UzsY9mHHlxaTwFSTLTPuKdoCIG369U7uOHBCkSFiIe9s\nxQAnpvZCCd+l0XXJlx7h0a2M\n-----END CERTIFICATE-----\n",
+ intermediateCerts: "",
+ admins: "",
+ tlsRootCerts:
+ "-----BEGIN CERTIFICATE-----\nMIICHjCCAcWgAwIBAgIUfFNit/ZNZY2SIbGN6ekejAdRoikwCgYIKoZIzj0EAwIw\nbDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\nc2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\nMi5leGFtcGxlLmNvbTAeFw0yNTA0MDIwODI2MDBaFw00MDAzMjkwODI2MDBaMGwx\nCzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\nZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\nZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARofvaM3udqgShD\njgunnP4hBLepJAdJJXVaF4gGwjGN7u0OJsUYefwoaZsIieJ+fJkpk+KWfV6esw5l\nopNQ7k0/o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\nBgNVHQ4EFgQUngIcE6RHSr5A0IcqEyqz6Gi27l4wCgYIKoZIzj0EAwIDRwAwRAIg\nWSvPOIUDa/rTJPRR9t54UzsY9mHHlxaTwFSTLTPuKdoCIG369U7uOHBCkSFiIe9s\nxQAnpvZCCd+l0XXJlx7h0a2M\n-----END CERTIFICATE-----\n",
+ tlsIntermediateCerts: "",
+ },
+ OrdererMSP: {
+ id: "OrdererMSP",
+ name: "OrdererMSP",
+ organizationalUnitIdentifiers: [],
+ rootCerts:
+ "-----BEGIN CERTIFICATE-----\nMIICCjCCAbGgAwIBAgIUHxMC6sxNcaZZCyez3FqdrC2KbnUwCgYIKoZIzj0EAwIw\nYjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcg\nWW9yazEUMBIGA1UEChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1wbGUu\nY29tMB4XDTI1MDQwMjA4MjYwMFoXDTQwMDMyOTA4MjYwMFowYjELMAkGA1UEBhMC\nVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UE\nChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAEgSssN7HxPWwg2+vhERmNqt5jtmUn9dJpdm1nEBVY\nqRDEpnsssIo7O0riIeywxFnhXSPTDr83mHX5ROFLONh/CKNFMEMwDgYDVR0PAQH/\nBAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFDs3WE+sRoD6Gdh5\n9mzTpZ5RkOdGMAoGCCqGSM49BAMCA0cAMEQCIAjAssqpRqiuPjRwxWDvMYxx9kBy\nMZbalwUjZ+xwbyG4AiAyQuYy6rpCw/IczpJdqZAbwwkYrUYiJd1kecwwnXxu8w==\n-----END CERTIFICATE-----\n",
+ intermediateCerts: "",
+ admins: "",
+ tlsRootCerts:
+ "-----BEGIN CERTIFICATE-----\nMIICCjCCAbGgAwIBAgIUHxMC6sxNcaZZCyez3FqdrC2KbnUwCgYIKoZIzj0EAwIw\nYjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcg\nWW9yazEUMBIGA1UEChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1wbGUu\nY29tMB4XDTI1MDQwMjA4MjYwMFoXDTQwMDMyOTA4MjYwMFowYjELMAkGA1UEBhMC\nVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UE\nChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAEgSssN7HxPWwg2+vhERmNqt5jtmUn9dJpdm1nEBVY\nqRDEpnsssIo7O0riIeywxFnhXSPTDr83mHX5ROFLONh/CKNFMEMwDgYDVR0PAQH/\nBAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFDs3WE+sRoD6Gdh5\n9mzTpZ5RkOdGMAoGCCqGSM49BAMCA0cAMEQCIAjAssqpRqiuPjRwxWDvMYxx9kBy\nMZbalwUjZ+xwbyG4AiAyQuYy6rpCw/IczpJdqZAbwwkYrUYiJd1kecwwnXxu8w==\n-----END CERTIFICATE-----\n",
+ tlsIntermediateCerts: "",
+ },
+ Org1MSP: {
+ id: "Org1MSP",
+ name: "Org1MSP",
+ organizationalUnitIdentifiers: [],
+ rootCerts:
+ "-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIUKlBnHkZhAX6EvIRadEAc5fcVZdUwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjUwNDAyMDgyNjAwWhcNNDAwMzI5MDgyNjAw\nWjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\nBAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\nY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH/R\nyYrvRTkbEi1o/VRUMqi9WPfFh2ANpzgq+ax1OJufEpa6duDXNOPV7+jJ8jrZGSsG\ndB7HSVxmQ4YJM7dFcn+jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEBMB0GA1UdDgQWBBQpN+0sYu6en762EX2o1ls4QWjgfzAKBggqhkjOPQQD\nAgNHADBEAiB4tKn8Tv5h6cLy69UIT/kECozoWE8T41OQSism/nW8hAIgEMPR2sbU\nvu6ZKkeg4vmfDjqXl/A5e74Mwf+A0+FnooE=\n-----END CERTIFICATE-----\n",
+ intermediateCerts: "",
+ admins: "",
+ tlsRootCerts:
+ "-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIUKlBnHkZhAX6EvIRadEAc5fcVZdUwCgYIKoZIzj0EAwIw\ncDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\nEwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMjUwNDAyMDgyNjAwWhcNNDAwMzI5MDgyNjAw\nWjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\nBAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\nY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH/R\nyYrvRTkbEi1o/VRUMqi9WPfFh2ANpzgq+ax1OJufEpa6duDXNOPV7+jJ8jrZGSsG\ndB7HSVxmQ4YJM7dFcn+jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEBMB0GA1UdDgQWBBQpN+0sYu6en762EX2o1ls4QWjgfzAKBggqhkjOPQQD\nAgNHADBEAiB4tKn8Tv5h6cLy69UIT/kECozoWE8T41OQSism/nW8hAIgEMPR2sbU\nvu6ZKkeg4vmfDjqXl/A5e74Mwf+A0+FnooE=\n-----END CERTIFICATE-----\n",
+ tlsIntermediateCerts: "",
+ },
+ },
+ orderers: {
+ OrdererMSP: {
+ endpoints: [
+ {
+ host: "orderer.example.com",
+ port: 7050,
+ name: "orderer.example.com:7050",
+ },
+ ],
+ },
+ },
+ peersByMSP: {
+ Org2MSP: {
+ peers: [
+ {
+ mspid: "Org2MSP",
+ endpoint: "peer0.org2.example.com:9051",
+ name: "peer0.org2.example.com:9051",
+ ledgerHeight: 15,
+ chaincodes: [
+ {
+ name: "basic",
+ version: "1",
+ },
+ {
+ name: "copyAssetTrade",
+ version: "1",
+ },
+ {
+ name: "_lifecycle",
+ version: "1",
+ },
+ ],
+ },
+ ],
+ },
+ Org1MSP: {
+ peers: [
+ {
+ mspid: "Org1MSP",
+ endpoint: "peer0.org1.example.com:7051",
+ name: "peer0.org1.example.com:7051",
+ ledgerHeight: 15,
+ chaincodes: [
+ {
+ name: "basic",
+ version: "1",
+ },
+ {
+ name: "copyAssetTrade",
+ version: "1",
+ },
+ {
+ name: "_lifecycle",
+ version: "1",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ timestamp: 1743584187645,
+};
diff --git a/tools/docker/supabase-all-in-one/Dockerfile b/tools/docker/supabase-all-in-one/Dockerfile
index 955b2ba879..1526003d87 100644
--- a/tools/docker/supabase-all-in-one/Dockerfile
+++ b/tools/docker/supabase-all-in-one/Dockerfile
@@ -56,6 +56,8 @@ COPY ./src/healthcheck.sh /bin/healthcheck
RUN chmod +x /bin/healthcheck
HEALTHCHECK --interval=5s --timeout=5s --start-period=45s --retries=90 CMD /bin/healthcheck
+# Studio
+EXPOSE 3000
# Supabase
EXPOSE 8000
# Postgres
diff --git a/tools/docker/supabase-all-in-one/docker-compose.yml b/tools/docker/supabase-all-in-one/docker-compose.yml
index 4e2607e8fd..e700284312 100644
--- a/tools/docker/supabase-all-in-one/docker-compose.yml
+++ b/tools/docker/supabase-all-in-one/docker-compose.yml
@@ -12,4 +12,3 @@ services:
- "3000:3000" # Supabase Studio
- "8000:8000" # Supabase API
- "5432:5432" # Postgres
- network_mode: host