From ea7499c5f48866fdbf0092a6f3f60beb5dd5a227 Mon Sep 17 00:00:00 2001 From: JCNoguera <88061365+VmMad@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:13:44 +0100 Subject: [PATCH 01/12] fix(wallet): toast overlay connecting dapp buttons (#4243) --- apps/wallet/src/ui/app/shared/toaster/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/wallet/src/ui/app/shared/toaster/index.tsx b/apps/wallet/src/ui/app/shared/toaster/index.tsx index d5ff889a72c..47c7d8dcb64 100644 --- a/apps/wallet/src/ui/app/shared/toaster/index.tsx +++ b/apps/wallet/src/ui/app/shared/toaster/index.tsx @@ -37,8 +37,10 @@ function getBottomSpace(pathname: string, isMenuVisible: boolean, isBottomNavSpa '/accounts/manage', ].includes(pathname); - if (overlayWithActionButton || isBottomNavSpace) { - return '!bottom-16'; + const matchDynamicPaths = ['/dapp/connect'].some((path) => pathname.startsWith(path)); + + if (overlayWithActionButton || isBottomNavSpace || matchDynamicPaths) { + return '!bottom-20'; } return ''; From c010a5ddd47557df2c5bc0db80de0f4d6bb3963b Mon Sep 17 00:00:00 2001 From: JCNoguera <88061365+VmMad@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:39:24 +0100 Subject: [PATCH 02/12] fix(wallet, dashboard): use validator image when possible (#4247) * fix(wallet, dashboard): use validator image when possible * fix: remove unnecessary change * feat: add missing image in dashboard --- .../Dialogs/Staking/views/DetailsView.tsx | 2 +- .../components/Dialogs/Staking/views/Validator.tsx | 14 ++++++++++---- .../ui/app/staking/validators/ValidatorLogo.tsx | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/wallet-dashboard/components/Dialogs/Staking/views/DetailsView.tsx b/apps/wallet-dashboard/components/Dialogs/Staking/views/DetailsView.tsx index 79106443924..7e81f984e79 100644 --- a/apps/wallet-dashboard/components/Dialogs/Staking/views/DetailsView.tsx +++ b/apps/wallet-dashboard/components/Dialogs/Staking/views/DetailsView.tsx @@ -108,7 +108,7 @@ export function DetailsView({ @@ -47,7 +48,12 @@ export function Validator({ return ( - + {showAction && ( diff --git a/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx b/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx index dcb8954a274..bf8d05a97b6 100644 --- a/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx +++ b/apps/wallet/src/ui/app/staking/validators/ValidatorLogo.tsx @@ -82,7 +82,7 @@ export function ValidatorLogo({ Date: Wed, 27 Nov 2024 13:36:07 +0100 Subject: [PATCH 03/12] feat: rebrand toasts (#4261) Co-authored-by: Bran <52735957+brancoder@users.noreply.github.com> --- apps/wallet-dashboard/components/Toaster.tsx | 40 +++++++++++++++++++ apps/wallet-dashboard/components/index.ts | 1 + .../providers/AppProviders.tsx | 9 +---- 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 apps/wallet-dashboard/components/Toaster.tsx diff --git a/apps/wallet-dashboard/components/Toaster.tsx b/apps/wallet-dashboard/components/Toaster.tsx new file mode 100644 index 00000000000..12b29435158 --- /dev/null +++ b/apps/wallet-dashboard/components/Toaster.tsx @@ -0,0 +1,40 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import toast, { Toaster as ToasterLib, type ToastType, resolveValue } from 'react-hot-toast'; +import { Snackbar, SnackbarType } from '@iota/apps-ui-kit'; + +export type ToasterProps = { + bottomNavEnabled?: boolean; +}; + +export function Toaster() { + function getSnackbarType(type: ToastType): SnackbarType { + switch (type) { + case 'success': + return SnackbarType.Default; + case 'error': + return SnackbarType.Error; + case 'loading': + return SnackbarType.Default; + default: + return SnackbarType.Default; + } + } + + return ( + + {(t) => ( +
+ toast.dismiss(t.id)} + text={resolveValue(t.message, t)} + type={getSnackbarType(t.type)} + showClose + duration={t.duration} + /> +
+ )} +
+ ); +} diff --git a/apps/wallet-dashboard/components/index.ts b/apps/wallet-dashboard/components/index.ts index c1320cc7447..d35471140d9 100644 --- a/apps/wallet-dashboard/components/index.ts +++ b/apps/wallet-dashboard/components/index.ts @@ -23,3 +23,4 @@ export * from './ExplorerLink'; export * from './Dialogs'; export * from './ValidatorStakingData'; export * from './tiles'; +export * from './Toaster'; diff --git a/apps/wallet-dashboard/providers/AppProviders.tsx b/apps/wallet-dashboard/providers/AppProviders.tsx index 342a6fa6c34..69b2cebb513 100644 --- a/apps/wallet-dashboard/providers/AppProviders.tsx +++ b/apps/wallet-dashboard/providers/AppProviders.tsx @@ -3,7 +3,7 @@ 'use client'; -import { PopupProvider } from '@/components'; +import { PopupProvider, Toaster } from '@/components'; import { GrowthBookProvider } from '@growthbook/growthbook-react'; import { IotaClientProvider, lightTheme, darkTheme, WalletProvider } from '@iota/dapp-kit'; import { getAllNetworks, getDefaultNetwork } from '@iota/iota-sdk/client'; @@ -11,7 +11,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useState } from 'react'; import { growthbook } from '@/lib/utils'; import { Popup } from '@/components/Popup'; -import { Toaster } from 'react-hot-toast'; import { ThemeProvider } from '@iota/core'; growthbook.init(); @@ -40,11 +39,7 @@ export function AppProviders({ children }: React.PropsWithChildren) { {children} - + From 5c63706b638378d6a2d6b3c1f1ae2164c57a5e24 Mon Sep 17 00:00:00 2001 From: Panteleymonchuk Date: Wed, 27 Nov 2024 16:21:06 +0200 Subject: [PATCH 04/12] feat(dashboard): update activity page (#4251) * feat(dashboard): update activity page * fix(dashboard): update layout height --- .../app/(protected)/activity/page.tsx | 37 ++++++------------- .../app/(protected)/layout.tsx | 2 +- apps/wallet-dashboard/app/globals.css | 2 +- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/apps/wallet-dashboard/app/(protected)/activity/page.tsx b/apps/wallet-dashboard/app/(protected)/activity/page.tsx index 63a84224f75..14f4bc516da 100644 --- a/apps/wallet-dashboard/app/(protected)/activity/page.tsx +++ b/apps/wallet-dashboard/app/(protected)/activity/page.tsx @@ -4,34 +4,21 @@ 'use client'; import React from 'react'; -import { useCurrentAccount } from '@iota/dapp-kit'; -import { VirtualList, TransactionTile } from '@/components'; -import { useQueryTransactionsByAddress } from '@iota/core'; -import { getExtendedTransaction } from '@/lib/utils/transaction'; -import { IotaTransactionBlockResponse } from '@iota/iota-sdk/client'; +import { Panel, Title, TitleSize } from '@iota/apps-ui-kit'; +import { TransactionsList } from '@/components'; function ActivityPage(): JSX.Element { - const currentAccount = useCurrentAccount(); - const { data: transactions, error } = useQueryTransactionsByAddress(currentAccount?.address); - - if (error) { - return
{error?.message}
; - } - - const virtualItem = (rawTransaction: IotaTransactionBlockResponse): JSX.Element => { - const transaction = getExtendedTransaction(rawTransaction, currentAccount?.address || ''); - return ; - }; - return ( -
-

Your Activity

-
- 100} - render={virtualItem} - /> +
+
+ +
+ + </div> + <div className="px-sm pb-md pt-sm"> + <TransactionsList /> + </div> + </Panel> </div> </div> ); diff --git a/apps/wallet-dashboard/app/(protected)/layout.tsx b/apps/wallet-dashboard/app/(protected)/layout.tsx index 79f7a084546..2ba32059a9b 100644 --- a/apps/wallet-dashboard/app/(protected)/layout.tsx +++ b/apps/wallet-dashboard/app/(protected)/layout.tsx @@ -17,7 +17,7 @@ function DashboardLayout({ children }: PropsWithChildren): JSX.Element { }; return ( - <div className="h-full"> + <div className="min-h-full"> <div className="fixed left-0 top-0 z-50 h-full"> <Sidebar /> </div> diff --git a/apps/wallet-dashboard/app/globals.css b/apps/wallet-dashboard/app/globals.css index f4151e588f5..82c7527e111 100644 --- a/apps/wallet-dashboard/app/globals.css +++ b/apps/wallet-dashboard/app/globals.css @@ -6,7 +6,7 @@ html, body { - height: 100%; + min-height: 100%; @apply bg-gray-100 dark:bg-gray-900; @apply text-gray-900 dark:text-gray-100; } From de4df8e2274291d5365e545585a4fafe00515cc9 Mon Sep 17 00:00:00 2001 From: Marc Espin <mespinsanz@gmail.com> Date: Wed, 27 Nov 2024 17:20:59 +0100 Subject: [PATCH 05/12] docs(ts-sdk): Update outdated TS SDK Docs (#4255) * docs(ts-sdk): Update outdated TS SDK Docs * ' * use Network enum * fix usage of Network * fix reference of Network.Custom --- dapps/kiosk-cli/index.js | 4 ++-- .../kiosk/src/context/KioskClientContext.tsx | 5 +++-- .../developer/standards/wallet-standard.mdx | 6 +++--- .../ts-sdk/kiosk/advanced-examples.mdx | 4 ++-- .../kiosk/kiosk-client/introduction.mdx | 21 +++++++------------ .../kiosk-transaction/purchasing.mdx | 5 ++--- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/dapps/kiosk-cli/index.js b/dapps/kiosk-cli/index.js index a54976a9a9a..aff1f965b12 100644 --- a/dapps/kiosk-cli/index.js +++ b/dapps/kiosk-cli/index.js @@ -34,7 +34,7 @@ import { } from '@iota/iota-sdk/utils'; import { bcs } from '@iota/iota-sdk/bcs'; import { program } from 'commander'; -import { KIOSK_LISTING, KioskClient, KioskTransaction, Network } from '@iota/kiosk'; +import { KIOSK_LISTING, KioskClient, KioskTransaction } from '@iota/kiosk'; import { IotaClient, getFullnodeUrl } from '@iota/iota-sdk/client'; import { Ed25519Keypair } from '@iota/iota-sdk/keypairs/ed25519'; import { Transaction } from '@iota/iota-sdk/transactions'; @@ -49,7 +49,7 @@ const client = new IotaClient({ url: getFullnodeUrl('testnet') }); const kioskClient = new KioskClient({ client, - network: Network.TESTNET, + network: 'testnet', }); /** diff --git a/dapps/kiosk/src/context/KioskClientContext.tsx b/dapps/kiosk/src/context/KioskClientContext.tsx index e193465a553..1aa6339edfd 100644 --- a/dapps/kiosk/src/context/KioskClientContext.tsx +++ b/dapps/kiosk/src/context/KioskClientContext.tsx @@ -3,7 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 import { useIotaClient, useIotaClientContext } from '@iota/dapp-kit'; -import { KioskClient, Network } from '@iota/kiosk'; +import { NetworkId } from '@iota/iota-sdk/client'; +import { KioskClient } from '@iota/kiosk'; import { createContext, ReactNode, useContext, useMemo } from 'react'; export const KioskClientContext = createContext<KioskClient | undefined>(undefined); @@ -15,7 +16,7 @@ export function KioskClientProvider({ children }: { children: ReactNode }) { () => new KioskClient({ client: iotaClient, - network: network as Network, + network: network as NetworkId, }), [iotaClient, network], ); diff --git a/docs/content/developer/standards/wallet-standard.mdx b/docs/content/developer/standards/wallet-standard.mdx index 8cc9142dde4..4a529531af1 100644 --- a/docs/content/developer/standards/wallet-standard.mdx +++ b/docs/content/developer/standards/wallet-standard.mdx @@ -20,7 +20,7 @@ Create a class that represents your wallet. Use the `Wallet` interface from `@iota/wallet-standard` to help ensure your class adheres to the standard. ```tsx -import { IOTA_DEVNET_CHAIN, Wallet } from '@iota/wallet-standard'; +import { SUPPORTED_CHAINS, Wallet } from '@iota/wallet-standard'; class YourWallet implements Wallet { get version() { @@ -35,7 +35,7 @@ class YourWallet implements Wallet { } // Return the IOTA chains that your wallet supports. get chains() { - return [IOTA_DEVNET_CHAIN]; + return SUPPORTED_CHAINS; } } ``` @@ -152,7 +152,7 @@ class YourWallet implements Wallet { address: walletAccount.iotaAddress, publicKey: walletAccount.pubkey, // The IOTA chains that your wallet supports. - chains: [IOTA_DEVNET_CHAIN], + chains: [SUPPORTED_CHAINS], // The features that this account supports. This can be a subset of the wallet's supported features. // These features must exist on the wallet as well. features: [ diff --git a/docs/content/references/ts-sdk/kiosk/advanced-examples.mdx b/docs/content/references/ts-sdk/kiosk/advanced-examples.mdx index 181ec1ed41d..1948d65c4f1 100644 --- a/docs/content/references/ts-sdk/kiosk/advanced-examples.mdx +++ b/docs/content/references/ts-sdk/kiosk/advanced-examples.mdx @@ -12,9 +12,9 @@ const otherType = `${packageId}::other_module::OtherStruct<${packageId}::other_c // initialize a kioskClient. const kioskClient = new KioskClient({ client: new IotaClient({ - url: getFullnodeUrl('testnet'), + url: getFullnodeUrl(Network.Testnet), }), - network: Network.TESTNET, + network: Network.Testnet, }); ``` diff --git a/docs/content/references/ts-sdk/kiosk/kiosk-client/introduction.mdx b/docs/content/references/ts-sdk/kiosk/kiosk-client/introduction.mdx index 73bea1b8fce..e52f56bc105 100644 --- a/docs/content/references/ts-sdk/kiosk/kiosk-client/introduction.mdx +++ b/docs/content/references/ts-sdk/kiosk/kiosk-client/introduction.mdx @@ -7,38 +7,33 @@ Kiosk Client is the base for all Kiosk SDK functionality. ## Creating a kiosk client -You can follow the example to create a `KioskClient`. The client currently supports `MAINNET` and -`TESTNET`. View next section for usage in other networks. - -_IOTA Kiosk rules and extensions are not supported in Devnet due to network wipes (that would -require constantly changing the package IDs)._ - +You can follow the example to create a `KioskClient`. View next section for usage in custom networks. ```typescript -import { KioskClient, Network } from '@iota/kiosk'; -import { getFullnodeUrl, IotaClient } from '@iota/iota-sdk/client'; +import { KioskClient } from '@iota/kiosk'; +import { getFullnodeUrl, IotaClient, Network } from '@iota/iota-sdk/client'; // We need a IOTA Client. You can re-use the IotaClient of your project // (it's not recommended to create a new one). -const client = new IotaClient({ url: getFullnodeUrl('testnet') }); +const client = new IotaClient({ url: getFullnodeUrl(Network.Testnet) }); // Now we can use it to create a kiosk Client. const kioskClient = new KioskClient({ client, - network: Network.TESTNET, + network: Network.Testnet, }); ``` -### Using KioskClient on devnet or localnet +### Using KioskClient on custom networks -To use all the functionality of Kiosk SDK outside of `MAINNET` and `TESTNET`, use `Network.CUSTOM` +To use all the functionality of Kiosk SDK outside of official networks, use `Network.Custom` as the network, and pass the `packageIds` for the rules and extensions you want to use. ```typescript // constructing it for custom network use. const kioskClient = new KioskClient({ client, - network: Network.CUSTOM, + network: Network.Custom, packageIds: { kioskLockRulePackageId: '0x...', royaltyRulePackageId: '0x...', diff --git a/docs/content/references/ts-sdk/kiosk/kiosk-client/kiosk-transaction/purchasing.mdx b/docs/content/references/ts-sdk/kiosk/kiosk-client/kiosk-transaction/purchasing.mdx index 0e2492241ce..771150f2592 100644 --- a/docs/content/references/ts-sdk/kiosk/kiosk-client/kiosk-transaction/purchasing.mdx +++ b/docs/content/references/ts-sdk/kiosk/kiosk-client/kiosk-transaction/purchasing.mdx @@ -1,9 +1,8 @@ # Purchasing from a kiosk One of the base functionalities of the SDK is a seamless purchasing flow, allowing for ease of rules -resolving (hiding away the calls). The SDK supports all four rules by default, and works for -`TESTNET` and `MAINNET`. To support other networks, -[follow the instructions in the Introduction](../introduction#using-kioskclient-on-devnet-or-localnet). +resolving (hiding away the calls). To use custom networks, +[follow the instructions in the Introduction](../introduction#using-kioskclient-on-custom-networks). ## How to purchase From 7f082f2e820436f99e2af03c2e2902592686a2c1 Mon Sep 17 00:00:00 2001 From: evavirseda <evirseda@boxfish.studio> Date: Wed, 27 Nov 2024 19:15:25 +0100 Subject: [PATCH 06/12] feat(wallet): change delete account action to destructive color (#4253) --- apps/wallet/src/ui/app/pages/accounts/manage/RemoveDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wallet/src/ui/app/pages/accounts/manage/RemoveDialog.tsx b/apps/wallet/src/ui/app/pages/accounts/manage/RemoveDialog.tsx index e657642946d..807ef298573 100644 --- a/apps/wallet/src/ui/app/pages/accounts/manage/RemoveDialog.tsx +++ b/apps/wallet/src/ui/app/pages/accounts/manage/RemoveDialog.tsx @@ -59,7 +59,7 @@ export function RemoveDialog({ isOpen, setOpen, accountID }: RemoveDialogProps) /> <Button fullWidth - type={ButtonType.Primary} + type={ButtonType.Destructive} text="Remove" onClick={handleRemove} /> From 1dd90acf929d1663a78ab6a1ddc968d05bc5772b Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:30:22 +0100 Subject: [PATCH 07/12] feat(iota): don't require key generation for client.yaml if there is already one (#3978) * feat(iota): don't require key generation for client.yaml if there is already one * print if existing address will be used as active address * Update crates/iota/src/iota_commands.rs Co-authored-by: Thibault Martinez <thibault@iota.org> --------- Co-authored-by: Thibault Martinez <thibault@iota.org> --- crates/iota/src/iota_commands.rs | 39 +++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/crates/iota/src/iota_commands.rs b/crates/iota/src/iota_commands.rs index b4eb64d0724..54cad050dae 100644 --- a/crates/iota/src/iota_commands.rs +++ b/crates/iota/src/iota_commands.rs @@ -1201,29 +1201,36 @@ async fn prompt_if_no_config( .unwrap_or(&iota_config_dir()?) .join(IOTA_KEYSTORE_FILENAME); let mut keystore = Keystore::from(FileBasedKeystore::new(&keystore_path)?); - let key_scheme = if accept_defaults { - SignatureScheme::ED25519 + // Get an existing address or generate a new one + let active_address = if let Some(existing_address) = keystore.addresses().first() { + println!("Using existing address {existing_address} as active address."); + *existing_address } else { + let key_scheme = if accept_defaults { + SignatureScheme::ED25519 + } else { + println!( + "Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):" + ); + match SignatureScheme::from_flag(read_line()?.trim()) { + Ok(s) => s, + Err(e) => return Err(anyhow!("{e}")), + } + }; + let (new_address, phrase, scheme) = + keystore.generate_and_add_new_key(key_scheme, None, None, None)?; + let alias = keystore.get_alias_by_address(&new_address)?; println!( - "Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):" + "Generated new keypair and alias for address with scheme {:?} [{alias}: {new_address}]", + scheme.to_string() ); - match SignatureScheme::from_flag(read_line()?.trim()) { - Ok(s) => s, - Err(e) => return Err(anyhow!("{e}")), - } + println!("Secret Recovery Phrase : [{phrase}]"); + new_address }; - let (new_address, phrase, scheme) = - keystore.generate_and_add_new_key(key_scheme, None, None, None)?; - let alias = keystore.get_alias_by_address(&new_address)?; - println!( - "Generated new keypair and alias for address with scheme {:?} [{alias}: {new_address}]", - scheme.to_string() - ); - println!("Secret Recovery Phrase : [{phrase}]"); let alias = env.alias().clone(); IotaClientConfig::new(keystore) .with_envs([env]) - .with_active_address(new_address) + .with_active_address(active_address) .with_active_env(alias) .persisted(wallet_conf_path) .save()?; From 64bca645258c3b13572557806791caa79d254c58 Mon Sep 17 00:00:00 2001 From: Samuel Rufinatscha <samuel.rufinatscha@iota.org> Date: Thu, 28 Nov 2024 12:01:51 +0100 Subject: [PATCH 08/12] Review iota-graphql test coverage (#4135) * documentation: review iota-graphql test coverage * documentation: reference the transactional test runner * fix: refer tests.rs module * fix: coverage for dynamic queries * fix: coverage for filter options WIP * fix: restructure coverage * docs: Add missing queries * fix: location paths * fix: format * fix: add missing filter options * fix: remove link * fix: graphql highlights --- crates/iota-graphql-e2e-tests/README.md | 8 + .../mutation/executeTransactionBlock.md | 118 +++++++++ .../coverage/query/address.md | 191 ++++++++++++++ .../coverage/query/availableRange.md | 43 ++++ .../coverage/query/chainIdentifier.md | 16 ++ .../coverage/query/checkpoint.md | 69 ++++++ .../coverage/query/checkpoints.md | 96 ++++++++ .../coverage/query/coinMetadata.md | 45 ++++ .../coverage/query/coins.md | 156 ++++++++++++ .../coverage/query/dryRunTransactionBlock.md | 90 +++++++ .../coverage/query/epoch.md | 107 ++++++++ .../coverage/query/events.md | 49 ++++ .../coverage/query/latestPackage.md | 232 ++++++++++++++++++ .../coverage/query/object.md | 165 +++++++++++++ .../coverage/query/objects.md | 187 ++++++++++++++ .../coverage/query/owner.md | 156 ++++++++++++ .../coverage/query/package.md | 232 ++++++++++++++++++ .../coverage/query/packages.md | 230 +++++++++++++++++ .../coverage/query/protocolConfig.md | 59 +++++ .../coverage/query/serviceConfig.md | 37 +++ .../coverage/query/transactionBlock.md | 74 ++++++ .../coverage/query/transactionBlocks.md | 175 +++++++++++++ .../coverage/query/type.md | 28 +++ crates/iota-graphql-rpc/README.md | 11 + 24 files changed, 2574 insertions(+) create mode 100644 crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/address.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/availableRange.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/coins.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/epoch.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/events.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/object.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/objects.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/owner.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/package.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/packages.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md create mode 100644 crates/iota-graphql-e2e-tests/coverage/query/type.md diff --git a/crates/iota-graphql-e2e-tests/README.md b/crates/iota-graphql-e2e-tests/README.md index 4e0c24eee8a..a0001d1c739 100644 --- a/crates/iota-graphql-e2e-tests/README.md +++ b/crates/iota-graphql-e2e-tests/README.md @@ -1,6 +1,14 @@ End-to-end tests for GraphQL service, built on top of the transactional test runner. +# Testing through the transactional test runner + +This crate specifically tests GraphQL queries in an e2e manner against the Indexer database. +The tests are executed through the [transactional test runner](../iota-transactional-test-runner), mediated by the [test.rs](tests/tests.rs) module. + +Each test is defined in a `.move` file, which contains various statements that are executed in a transactional manner. +In addition to the `.move` file, there is a corresponding `.exp` file that contains the expected output of the transactional test. + # Local Set-up These tests require a running instance of the `postgres` service, with a diff --git a/crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md b/crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md new file mode 100644 index 00000000000..708215005ff --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/mutation/executeTransactionBlock.md @@ -0,0 +1,118 @@ +Query: `executeTransactionBlock` + +```graphql +mutation { + executeTransactionBlock(txBytes: $tx, signatures: $sigs) { + effects { + transactionBlock { + digest + } + status + lamportVersion + errors + dependencies { + edges { + node { + digest + bcs + } + } + } + gasEffects { + __typename + gasObject { + digest + storageRebate + bcs + } + gasSummary { + computationCost + computationCostBurned + storageCost + storageRebate + nonRefundableStorageFee + } + } + unchangedSharedObjects { + edges { + node { + __typename + } + } + } + objectChanges { + edges { + node { + idCreated + idDeleted + } + } + } + balanceChanges { + edges { + node { + amount + } + } + } + events { + edges { + node { + timestamp + } + } + } + timestamp + epoch { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + checkpoint { + previousCheckpointDigest + networkTotalTransactions + } + bcs + } + errors + } +} +``` + +tested by [crates/iota-graphql-rpc/tests/e2e_tests.rs](../../../iota-graphql-rpc/tests/e2e_tests.rs): + +```graphql +{ + executeTransactionBlock(txBytes: $tx, signatures: $sigs) { + effects { + transactionBlock { + digest + } + } + errors + } +} +``` + +tested by [crates/iota-graphql-rpc/tests/e2e_tests.rs](../../../iota-graphql-rpc/tests/e2e_tests.rs): + +```graphql +mutation { + executeTransactionBlock(txBytes: "{}", signatures: "{}") { + effects { + status + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/address.md b/crates/iota-graphql-e2e-tests/coverage/query/address.md new file mode 100644 index 00000000000..7cc2ff3aa0e --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/address.md @@ -0,0 +1,191 @@ +Query: `address` + +```graphql +{ + address(address: "0x1") { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/owned_objects.move](../../../iota-graphql-e2e-tests/tests/call/owned_objects.move): + +```graphql +//# run-graphql +{ + address(address: "0x42") { + objects { + edges { + node { + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move](../../../iota-graphql-e2e-tests/tests/transaction_block_effects/balance_changes.move): + +```graphql +//# run-graphql +{ + address(address: "@{C}") { + transactionBlocks(last: 1) { + nodes { + effects { + balanceChanges { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + edges { + node { + amount + } + cursor + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/coins.move](../../../iota-graphql-e2e-tests/tests/consistency/coins.move): + +```graphql +//# run-graphql +{ + queryCoins: coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + owner { + ... on AddressOwner { + owner { + address + coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + contents { + json + } + } + } + } + } + } + } + contents { + json + } + } + } + } + addressCoinsA: address(address: "@{A}") { + coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + contents { + json + } + } + } + } + } + addressCoinsB: address(address: "@{B}") { + coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { + contents { + json + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/staked_iota.move](../../../iota-graphql-e2e-tests/tests/consistency/staked_iota.move): + +```graphql +//# run-graphql +{ + address(address: "@{C}") { + stakedIotas { + edges { + cursor + node { + principal + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/availableRange.md b/crates/iota-graphql-e2e-tests/coverage/query/availableRange.md new file mode 100644 index 00000000000..5b76a865112 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/availableRange.md @@ -0,0 +1,43 @@ +Query: `availableRange` + +```graphql +{ + availableRange { + first { + digest + } + last { + digest + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/available_range/available_range.move](../../../iota-graphql-e2e-tests/tests/available_range/available_range.move): + +```graphql +//# run-graphql +{ + availableRange { + first { + digest + sequenceNumber + } + last { + digest + sequenceNumber + } + } + + first: checkpoint(id: { sequenceNumber: 0 } ) { + digest + sequenceNumber + } + + last: checkpoint { + digest + sequenceNumber + } +} +``` + diff --git a/crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md b/crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md new file mode 100644 index 00000000000..9dda9821f3e --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/chainIdentifier.md @@ -0,0 +1,16 @@ +Query: `chainIdentifier` + +```graphql +{ + chainIdentifier +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/epoch/chain_identifier.move](../../../iota-graphql-e2e-tests/tests/epoch/chain_identifier.move): + +```graphql +//# run-graphql +{ +chainIdentifier +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md b/crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md new file mode 100644 index 00000000000..278b5a5d8fc --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/checkpoint.md @@ -0,0 +1,69 @@ +Query: `checkpoint` + +```graphql +{ + checkpoint(id: null) { + digest + sequenceNumber + timestamp + validatorSignatures + previousCheckpointDigest + networkTotalTransactions + rollingGasSummary { + computationCost + computationCostBurned + storageCost + storageRebate + nonRefundableStorageFee + } + epoch { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/simple.move](../../../iota-graphql-e2e-tests/tests/call/simple.move): + +```graphql +//# run-graphql +{ + checkpoint { + sequenceNumber + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transactions/at_checkpoint.move](../../../iota-graphql-e2e-tests/tests/transactions/at_checkpoint.move): + +```graphql +//# run-graphql +{ # Via a checkpoint query + c0: checkpoint(id: { sequenceNumber: 0 }) { transactionBlocks { nodes { ...Tx } } } + c1: checkpoint(id: { sequenceNumber: 1 }) { transactionBlocks { nodes { ...Tx } } } + c2: checkpoint(id: { sequenceNumber: 2 }) { transactionBlocks { nodes { ...Tx } } } + c3: checkpoint(id: { sequenceNumber: 3 }) { transactionBlocks { nodes { ...Tx } } } + c4: checkpoint(id: { sequenceNumber: 4 }) { transactionBlocks { nodes { ...Tx } } } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md b/crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md new file mode 100644 index 00000000000..35e1d963e78 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/checkpoints.md @@ -0,0 +1,96 @@ +Query: `checkpoints` + +```graphql +{ + checkpoints(after: null, first: null, last: null, before: null) { + edges { + node { + digest + sequenceNumber + timestamp + validatorSignatures + previousCheckpointDigest + networkTotalTransactions + rollingGasSummary { + computationCost + computationCostBurned + storageCost + storageRebate + nonRefundableStorageFee + } + epoch { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/limits/output_node_estimation.move](../../../iota-graphql-e2e-tests/tests/limits/output_node_estimation.move): + +```graphql +//# run-graphql --show-usage +# build on previous example with nested connection +{ + checkpoints { # 1 + nodes { # 1 + transactionBlocks { # 20 + edges { # 20 + txns: node { # 400 + digest # 400 + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move](../../../iota-graphql-e2e-tests/tests/consistency/checkpoints/transaction_blocks.move): + +```graphql +{ + checkpoints { + nodes { + sequenceNumber + transactionBlocks(filter: { signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects(last: 1) { + edges { + cursor + } + } + } + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md b/crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md new file mode 100644 index 00000000000..40324539394 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/coinMetadata.md @@ -0,0 +1,45 @@ +Query: `coinMetadata` + +```graphql +{ + coinMetadata(coinType: "@{test}::fake::FAKE") { + digest + storageRebate + bcs + decimals + name + symbol + description + iconUrl + supply + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/coin_metadata.move](../../../iota-graphql-e2e-tests/tests/call/coin_metadata.move): + +```graphql +//# run-graphql +{ + coinMetadata(coinType: "@{test}::fake::FAKE") { + decimals + name + symbol + description + iconUrl + supply + } +} + +//# run-graphql +{ + coinMetadata(coinType: "@{test}::fake::FAKE") { + decimals + name + symbol + description + iconUrl + supply + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/coins.md b/crates/iota-graphql-e2e-tests/coverage/query/coins.md new file mode 100644 index 00000000000..c1034e2a691 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/coins.md @@ -0,0 +1,156 @@ +Query: `type` + +```graphql +{ + coins(first: null, last: null, after: null) { + edges { + node { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + contents { + __typename + data + } + display { + value + error + } + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicFields { + edges { + node { + __typename + } + } + } + coinBalance + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/objects/coin.move](../../../iota-graphql-e2e-tests/tests/objects/coin.move): + +```graphql +//# run-graphql +fragment C on Coin { + coinBalance + contents { type { repr } } +} + +{ + iotaCoins: coins { + edges { + cursor + node { ...C } + } + } + + fakeCoins: coins(type: "@{P0}::fake::FAKE") { + edges { + cursor + node { ...C } + } + } + + address(address: "@{A}") { + coins { + edges { + cursor + node { ...C } + } + } + + allBalances: balances { + edges { + cursor + node { + coinType { repr } + coinObjectCount + totalBalance + } + } + } + + firstBalance: balances(first: 1) { + edges { cursor } + } + + lastBalance: balances(last: 1) { + edges { cursor } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md b/crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md new file mode 100644 index 00000000000..c02bea1a742 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/dryRunTransactionBlock.md @@ -0,0 +1,90 @@ +Query: `dryRunTransactionBlock` + +```graphql +{ + dryRunTransactionBlock( + txBytes: "AAIAIC3Pg7fIBNN95RZluYu1Ll8icKxoO/oGYoEAfLP0szGAAAjoAwAAAAAAAAICAAEBAQABAQIAAAEAAA==" + txMeta: {} + ) { + transaction { + digest + sender { + address + } + gasInput { + gasSponsor { + address + } + gasPayment { + edges { + node { + digest + storageRebate + bcs + } + } + } + gasPrice + gasBudget + } + } + error + results { + mutatedReferences { + input { + __typename + ... on Input { + ix + } + ... on Result { + cmd + ix + } + } + type { + repr + } + bcs + } + returnValues { + type { + repr + signature + layout + abilities + } + bcs + } + } + } +} +``` + +tested by [crates/iota-graphql-rpc/tests/e2e_tests.rs](../../../iota-graphql-rpc/tests/e2e_tests.rs): + +```graphql +{ + dryRunTransactionBlock(txBytes: $tx, txMeta: {}) { + results { + mutatedReferences { + input { + __typename + } + } + } + transaction { + digest + sender { + address + } + gasInput { + gasSponsor { + address + } + gasPrice + } + } + error + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/epoch.md b/crates/iota-graphql-e2e-tests/coverage/query/epoch.md new file mode 100644 index 00000000000..cd5f8245498 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/epoch.md @@ -0,0 +1,107 @@ +Query: `epoch` + +```graphql +{ + epoch(id: 1) { + epochId + referenceGasPrice + validatorSet { + totalStake + pendingActiveValidatorsId + pendingActiveValidatorsSize + stakingPoolMappingsId + stakingPoolMappingsSize + inactivePoolsId + inactivePoolsSize + validatorCandidatesId + validatorCandidatesSize + } + startTimestamp + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + protocolConfigs { + __typename + } + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + checkpoints { + edges { + node { + previousCheckpointDigest + networkTotalTransactions + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/validator/validator.move](../../../iota-graphql-e2e-tests/tests/validator/validator.move): + +```graphql +{ + epoch(id: 1) { + validatorSet { + activeValidators { + nodes { + name + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move](../../../iota-graphql-e2e-tests/tests/consistency/epochs/checkpoints.move): + +```graphql +//# run-graphql --cursors {"s":3,"c":4} {"s":7,"c":8} {"s":9,"c":10} +# View checkpoints before the last checkpoint in each epoch, from the perspective of the first +# checkpoint in the next epoch. +{ + checkpoint { + sequenceNumber + } + epoch_0: epoch(id: 0) { + epochId + checkpoints(before: "@{cursor_0}") { + nodes { + sequenceNumber + } + } + } + epoch_1: epoch(id: 1) { + epochId + checkpoints(before: "@{cursor_1}") { + nodes { + sequenceNumber + } + } + } + epoch_2: epoch(id: 2) { + epochId + checkpoints(before: "@{cursor_2}") { + nodes { + sequenceNumber + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/events.md b/crates/iota-graphql-e2e-tests/coverage/query/events.md new file mode 100644 index 00000000000..ea0100eb520 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/events.md @@ -0,0 +1,49 @@ +Query: `events` + +```graphql +{ + events(first: null, last: null, after: null, before: null, filter: null) { + edges { + node { + __typename + data + timestamp + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/event_connection/no_filter.move](../../../iota-graphql-e2e-tests/tests/event_connection/no_filter.move): + +```graphql +//# run-graphql +{ + events { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + nodes { + json + } + } +} + +//# run-graphql --cursors {"tx":2,"e":19,"c":1} +{ + events(after: "@{cursor_0}") { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + nodes { + json + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md b/crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md new file mode 100644 index 00000000000..f6ccf36ae32 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/latestPackage.md @@ -0,0 +1,232 @@ +Query: `latestPackage` + +```graphql +{ + latestPackage(address: "0x1") { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + packageVersions { + edges { + node { + digest + storageRebate + bcs + moduleBcs + } + } + } + latestPackage { + digest + storageRebate + bcs + moduleBcs + } + module(name: "address") { + bytes + disassembly + } + modules { + edges { + node { + name + package { + digest + storageRebate + bcs + moduleBcs + } + datatype(name: "Char") { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + datatypes { + edges { + node { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + } + } + __typename + fileFormatVersion + bytes + disassembly + } + } + } + linkage { + version + __typename + } + typeOrigins { + __typename + } + moduleBcs + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/packages/versioning.move](../../../iota-graphql-e2e-tests/tests/packages/versioning.move): + +```graphql +//# run-graphql +{ + latestPackage(address: "@{P0}") { + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + firstPackage: package(address: "@{P0}", version: 1) { + address + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + packages(first: 10) { + nodes { + address + version + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/object.md b/crates/iota-graphql-e2e-tests/coverage/query/object.md new file mode 100644 index 00000000000..62b2c246845 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/object.md @@ -0,0 +1,165 @@ +Query: `object` + +```graphql +{ + object(address: "0x1") { + address + objects { + edges { + node { + digest + } + } + } + balance { + coinType { + repr + signature + layout + abilities + } + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + } + } + } + coins { + edges { + node { + digest + } + } + } + stakedIotas { + edges { + node { + digest + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + name { + bcs + } + } + dynamicFields { + edges { + node { + name { + __typename + } + } + } + } + asMoveObject { + digest + } + asMovePackage { + digest + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/owned_objects.move](../../../iota-graphql-e2e-tests/tests/call/owned_objects.move): + +```graphql +//# run-graphql +{ + object(address: "0x42") { + objects { + edges { + node { + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transactions/random.move](../../../iota-graphql-e2e-tests/tests/transactions/random.move): + +```graphql +//# run-graphql +{ + object(address: "0x8") { + address + version + asMoveObject { + contents { + type { repr } + json + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move](../../../iota-graphql-e2e-tests/tests/call/dynamic_fields.move): + +```graphql +//# run-graphql +{ + object(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + __typename + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/objects.md b/crates/iota-graphql-e2e-tests/coverage/query/objects.md new file mode 100644 index 00000000000..b48d531f62a --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/objects.md @@ -0,0 +1,187 @@ +Query: `objects` + +```graphql +{ + objects(first: null, last: null, after: null, filter: null) { + edges { + node { + address + objects { + edges { + node { + digest + } + } + } + balance { + coinType { + repr + signature + layout + abilities + } + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + } + } + } + coins { + edges { + node { + digest + } + } + } + stakedIotas { + edges { + node { + digest + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmMQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + name { + bcs + } + } + dynamicFields { + edges { + node { + name { + __typename + } + } + } + } + asMoveObject { + digest + } + asMovePackage { + digest + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move](../../../iota-graphql-e2e-tests/tests/consistency/performance/many_objects.move): + +```graphql +//# run-graphql +{ + last_2: objects(last: 2, filter: {type: "@{Test}"}) { + nodes { + version + asMoveObject { + owner { + ... on AddressOwner { + owner { + address + } + } + } + contents { + json + type { + repr + } + } + } + } + } + last_4_objs_owned_by_A: address(address: "@{A}") { + objects(last: 4) { + nodes { + owner { + ... on AddressOwner { + owner { + address + } + } + } + contents { + json + type { + repr + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/objects_pagination.move](../../../iota-graphql-e2e-tests/tests/consistency/objects_pagination.move): + +```graphql +//# run-graphql --cursors @{obj_6_0,2} +{ + before_obj_6_0_at_checkpoint_2: objects(filter: {type: "@{Test}"}, before: "@{cursor_0}") { + nodes { + version + asMoveObject { + contents { + type { + repr + } + json + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/coverage/query/objects.md](../../../iota-graphql-e2e-tests/coverage/query/objects.md): + +```graphql +//# run-graphql +{ + objects(filter: {type: "0x2::coin"}) { + edges { + node { + asMoveObject { + contents { + type { + repr + } + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/owner.md b/crates/iota-graphql-e2e-tests/coverage/query/owner.md new file mode 100644 index 00000000000..4c7236775b3 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/owner.md @@ -0,0 +1,156 @@ +Query: `owner` + +```graphql +{ + owner(address: "0x1", rootVersion: null) { + address + objects { + edges { + node { + address + } + } + } + balance { + coinType { + repr + signature + layout + abilities + } + coinObjectCount + totalBalance + } + coins { + edges { + node { + balance { + coinObjectCount + totalBalance + } + } + } + } + stakedIotas { + edges { + node { + digest + } + } + } + asAddress { + address + } + asObject { + digest + } + dynamicField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicObjectField( + name: {type: "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs: "A2RmNQ=="} + ) { + __typename + } + dynamicFields { + edges { + node { + __typename + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/owned_objects.move](../../../iota-graphql-e2e-tests/tests/call/owned_objects.move): + +```graphql +//# run-graphql +{ + owner(address: "0x42") { + objects { + edges { + node { + owner { + __typename + ... on AddressOwner { + owner { + address + } + } + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/dynamic_fields.move](../../../iota-graphql-e2e-tests/tests/call/dynamic_fields.move): + +```graphql +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicFields { + nodes { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveObject { + __typename + } + ... on MoveValue { + bcs + data + __typename + } + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { + name { + type { + repr + } + data + bcs + } + value { + ... on MoveValue { + __typename + bcs + data + } + } + } + } +} + +//# run-graphql +{ + owner(address: "@{obj_2_0}") { + dynamicObjectField(name: {type: "u64", bcs: "AAAAAAAAAAA="}) { + value { + ... on MoveObject { + __typename + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/package.md b/crates/iota-graphql-e2e-tests/coverage/query/package.md new file mode 100644 index 00000000000..00d014d1da7 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/package.md @@ -0,0 +1,232 @@ +Query: `package` + +```graphql +{ + package(address: "0x1") { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + packageVersions { + edges { + node { + digest + storageRebate + bcs + moduleBcs + } + } + } + latestPackage { + digest + storageRebate + bcs + moduleBcs + } + module(name: "address") { + bytes + disassembly + } + modules { + edges { + node { + name + package { + digest + storageRebate + bcs + moduleBcs + } + datatype(name: "Char") { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + datatypes { + edges { + node { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + } + } + __typename + fileFormatVersion + bytes + disassembly + } + } + } + linkage { + version + __typename + } + typeOrigins { + __typename + } + moduleBcs + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/packages/versioning.move](../../../iota-graphql-e2e-tests/tests/packages/versioning.move): + +```graphql +//# run-graphql +{ + latestPackage(address: "@{P0}") { + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + firstPackage: package(address: "@{P0}", version: 1) { + address + version + module(name: "m") { + functions { nodes { name } } + } + + packageVersions { + nodes { + address + version + } + } + } + + packages(first: 10) { + nodes { + address + version + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/packages.md b/crates/iota-graphql-e2e-tests/coverage/query/packages.md new file mode 100644 index 00000000000..04d1dfbf6df --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/packages.md @@ -0,0 +1,230 @@ +Query: `package` + +```graphql +{ + packages(first: null, last: 5, after: null, filter: null) { + edges { + node { + address + objects { + edges { + node { + digest + storageRebate + bcs + } + } + } + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + coins { + edges { + node { + digest + storageRebate + bcs + coinBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + version + status + digest + owner { + __typename + } + previousTransactionBlock { + digest + bcs + } + storageRebate + receivedTransactionBlocks { + edges { + node { + digest + bcs + } + } + } + bcs + packageVersions { + edges { + node { + digest + storageRebate + bcs + moduleBcs + } + } + } + latestPackage { + digest + storageRebate + bcs + moduleBcs + } + module(name: "address") { + bytes + disassembly + } + modules { + edges { + node { + name + package { + digest + storageRebate + bcs + moduleBcs + } + datatype(name: "Char") { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + datatypes { + edges { + node { + abilities + asMoveEnum { + abilities + name + variants { + name + __typename + } + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + asMoveStruct { + abilities + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + name + __typename + typeParameters { + isPhantom + __typename + constraints + } + } + } + } + __typename + fileFormatVersion + bytes + disassembly + } + } + } + linkage { + version + __typename + } + typeOrigins { + __typename + } + moduleBcs + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/packages/versioning.move](../../../iota-graphql-e2e-tests/tests/packages/versioning.move): + +```graphql +//# run-graphql +{ # Querying packages with checkpoint bounds + before: packages(first: 10, filter: { beforeCheckpoint: 1 }) { + nodes { + address + version + previousTransactionBlock { + effects { checkpoint { sequenceNumber } } + } + } + } + + after: packages(first: 10, filter: { afterCheckpoint: 1 }) { + nodes { + address + version + previousTransactionBlock { + effects { checkpoint { sequenceNumber } } + } + } + } + + between: packages(first: 10, filter: { afterCheckpoint: 1, beforeCheckpoint: 3 }) { + nodes { + address + version + previousTransactionBlock { + effects { checkpoint { sequenceNumber } } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md b/crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md new file mode 100644 index 00000000000..876ae677796 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/protocolConfig.md @@ -0,0 +1,59 @@ +Query: `protocolConfig` + +```graphql +{ + protocolConfig(protocolVersion: 1) { + protocolVersion + featureFlags { + key + value + __typename + } + configs { + key + value + __typename + } + config(key: "address_from_bytes_cost_base") { + key + value + __typename + } + featureFlag(key: "bridge") { + key + value + __typename + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/epoch/protocol_configs.move](../../../iota-graphql-e2e-tests/tests/epoch/protocol_configs.move): + +```graphql +//# run-graphql +{ + protocolConfig { + protocolVersion + config(key: "max_move_identifier_len") { + value + } + featureFlag(key: "bridge") { + value + } + } +} + +//# run-graphql +{ + protocolConfig(protocolVersion: 1) { + protocolVersion + config(key: "max_move_identifier_len") { + value + } + featureFlag(key: "bridge") { + value + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md b/crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md new file mode 100644 index 00000000000..97960565217 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/serviceConfig.md @@ -0,0 +1,37 @@ +Query: `serviceConfig` + +```graphql +{ + serviceConfig { + isEnabled(feature:COINS) + availableVersions + enabledFeatures + maxQueryDepth + maxQueryNodes + maxOutputNodes + maxDbQueryCost + defaultPageSize + maxPageSize + mutationTimeoutMs + requestTimeoutMs + maxQueryPayloadSize + maxTypeArgumentDepth + maxTypeArgumentWidth + maxTypeNodes + maxMoveValueDepth + maxTransactionIds + maxScanLimit + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/call/simple.move](../../../iota-graphql-e2e-tests/tests/call/simple.move): + +```graphql +//# run-graphql +{ + serviceConfig { + availableVersions + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md new file mode 100644 index 00000000000..1273c8687c8 --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlock.md @@ -0,0 +1,74 @@ +Query: `transactionBlock` + +```graphql +{ + transactionBlock(digest: "63X49x2QuuYNduExZWoJjfXut3s3WDWZ7Tr7nXJu32ZT") { + digest + sender { + address + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } + gasInput { + gasPrice + gasBudget + } + kind { + __typename + } + signatures + effects { + status + errors + timestamp + } + expiration { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + bcs + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md new file mode 100644 index 00000000000..3fff42b23aa --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/transactionBlocks.md @@ -0,0 +1,175 @@ +Query: `transactionBlocks` + +```graphql +{ + transactionBlocks(first: null, last: null, after: null, scanLimit: null) { + edges { + node { + digest + sender { + address + balance { + coinObjectCount + totalBalance + } + balances { + edges { + node { + coinObjectCount + totalBalance + } + } + } + stakedIotas { + edges { + node { + digest + storageRebate + bcs + poolId + principal + estimatedReward + } + } + } + transactionBlocks { + edges { + node { + digest + bcs + } + } + } + } + gasInput { + gasPrice + gasBudget + } + kind { + __typename + } + signatures + effects { + status + errors + timestamp + } + expiration { + referenceGasPrice + endTimestamp + totalCheckpoints + totalTransactions + totalGasFees + totalStakeRewards + fundSize + netInflow + fundInflow + fundOutflow + systemStateVersion + iotaTotalSupply + iotaTreasuryCapId + liveObjectSetDigest + } + bcs + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/balances.move](../../../iota-graphql-e2e-tests/tests/consistency/balances.move): + +```graphql +//# run-graphql --cursors {"c":2,"t":1,"i":false} +# Emulating viewing transaction blocks at checkpoint 2. Fake coin balance should be 700. +{ + transactionBlocks(first: 1, after: "@{cursor_0}", filter: {signAddress: "@{A}"}) { + nodes { + sender { + fakeCoinBalance: balance(type: "@{P0}::fake::FAKE") { + totalBalance + } + allBalances: balances { + nodes { + coinType { + repr + } + coinObjectCount + totalBalance + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move](../../../iota-graphql-e2e-tests/tests/transaction_block_effects/object_changes.move): + +```graphql +//# run-graphql +{ + transactionBlocks(first: 1) { + nodes { + effects { + objectChanges { + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + edges { + cursor + } + } + } + } + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move](../../../iota-graphql-e2e-tests/tests/consistency/epochs/transaction_blocks.move): + +```graphql +//# run-graphql --cursors {"t":5,"i":false,"c":6} +# Verify that with a cursor, we are locked into a view as if we were at the checkpoint stored in +# the cursor. Compare against `without_cursor`, which should show the latest state at the actual +# latest checkpoint. There should only be 1 transaction block in the `with_cursor` query, but +# multiple in the second +{ + checkpoint { + sequenceNumber + } + with_cursor: transactionBlocks(after: "@{cursor_0}", filter: {signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects { + edges { + cursor + } + } + } + } + } + } + without_cursor: transactionBlocks(filter: {signAddress: "@{A}"}) { + edges { + cursor + node { + digest + sender { + objects { + edges { + cursor + } + } + } + } + } + } +} +``` diff --git a/crates/iota-graphql-e2e-tests/coverage/query/type.md b/crates/iota-graphql-e2e-tests/coverage/query/type.md new file mode 100644 index 00000000000..72155a597bf --- /dev/null +++ b/crates/iota-graphql-e2e-tests/coverage/query/type.md @@ -0,0 +1,28 @@ +Query: `type` + +```graphql +{ + type(type: "vector<u64>") { + repr + signature + layout + abilities + __typename + } +} +``` + +tested by [crates/iota-graphql-e2e-tests/coverage/query/type.md](../../../iota-graphql-e2e-tests/coverage/query/type.md): + +```graphql +//# run-graphql +# Happy path -- primitive type with generic parameter + +{ + type(type: "vector<u64>") { + repr + signature + layout + } +} +``` diff --git a/crates/iota-graphql-rpc/README.md b/crates/iota-graphql-rpc/README.md index 55ee84500fb..c7dadc63929 100644 --- a/crates/iota-graphql-rpc/README.md +++ b/crates/iota-graphql-rpc/README.md @@ -125,6 +125,9 @@ To run it with the `iota start` subcommand, switch to the root directory of the ## Running tests +The crate provides test coverage for server functionality, covering client validation, query validation, reading and writing data, query limits, and health checks. +For query tests, please see the `iota-graphql-e2e-tests` crate. + To run the tests, a running postgres database is required. To do so, follow the [Indexer database setup](../iota-indexer/README.md#database-setup) to set up a database. @@ -136,3 +139,11 @@ cargo nextest run -p iota-graphql-rpc --features pg_integration --no-fail-fast - To check for compatibility with json-rpc `pnpm --filter @iota/graphql-transport test:e2e` + +## To re-generate the GraphQL schema after code changes + +In order to re-generate the GraphQL schema ([schema.graphql](schema.graphql)), run the following command: + +```sh +cargo run --bin iota-graphql-rpc generate-schema +``` From f9aa341004b77253800f64e5a4debcb4fc2f8b83 Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Thu, 28 Nov 2024 13:10:27 +0100 Subject: [PATCH 09/12] feat(CI): add Move IDE Tests workflow (#4226) * feat(CI): add Move IDE Tests workflow * don't run move-ide-test if draft * Address review comments * Run on any change in external crates, fix test command * Rename diff output to isExternalCrates --- .github/actions/diffs/action.yml | 5 + .github/workflows/_move_ide.yml | 96 +++++++++++++++++++ .github/workflows/hierarchy.yml | 10 ++ .../editors/code/scripts/create.sh | 23 +++-- 4 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/_move_ide.yml diff --git a/.github/actions/diffs/action.yml b/.github/actions/diffs/action.yml index 4e6922ba60f..ac54e779fdd 100644 --- a/.github/actions/diffs/action.yml +++ b/.github/actions/diffs/action.yml @@ -10,6 +10,9 @@ outputs: isMove: description: True when changes happened to the Move code value: "${{ steps.diff.outputs.isMove }}" + isExternalCrates: + description: True when changes happened in external crates + value: "${{ steps.diff.outputs.isExternalCrates }}" isReleaseNotesEligible: description: True when changes happened in Release Notes eligible paths value: "${{ steps.diff.outputs.isReleaseNotesEligible }}" @@ -56,6 +59,8 @@ runs: - "examples/**" - "iota_programmability/**" - ".github/workflows/_move_tests.yml" + isExternalCrates: + - "external-crates/move/crates/**" isReleaseNotesEligible: - "consensus/**" - "crates/**" diff --git a/.github/workflows/_move_ide.yml b/.github/workflows/_move_ide.yml new file mode 100644 index 00000000000..5878489c9aa --- /dev/null +++ b/.github/workflows/_move_ide.yml @@ -0,0 +1,96 @@ +name: Move IDE + +on: workflow_call + +concurrency: + group: move-ide-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + move-auto-formatter-test: + name: Move Auto-formatter Test + runs-on: [self-hosted] + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # Pin v4.1.1 + with: + ref: ${{ github.event.inputs.iota_repo_ref || github.ref }} + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # pin@v4.0.2 + with: + node-version: "20" + + - name: Install dependencies + working-directory: ./external-crates/move/crates/move-analyzer/prettier-plugin + run: npm install && npm i web-tree-sitter + + - name: Run npm test + working-directory: ./external-crates/move/crates/move-analyzer/prettier-plugin + shell: bash + run: npm run test + + move-ide-test: + name: Move IDE Test + runs-on: [self-hosted] + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # Pin v4.1.1 + with: + ref: ${{ github.event.inputs.iota_repo_ref || github.ref }} + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # pin@v4.0.2 + with: + node-version: "20" + + - name: Install dependencies and start Xvfb (emulate a display so VS Code can be started) + working-directory: ./external-crates/move/crates/move-analyzer/editors/code + run: | + sudo apt install libgtk-3-0 -y + sudo apt-get install -y xvfb x11-apps x11-xkb-utils libx11-6 libx11-xcb1 + set -eux + # Start server + /usr/bin/Xvfb :99 -screen 0 1024x768x24 & + sleep 1 + ps aux | grep Xvfb --color=always | grep -v grep + sudo add-apt-repository ppa:kisak/kisak-mesa -y + sudo apt update + sudo apt upgrade -y + npm install && npm install --save-dev @types/node @types/semver + + - name: Build move-analyzer + run: | + cargo build --bin move-analyzer + mkdir -p ~/.iota/bin + cp ./target/debug/move-analyzer* ~/.iota/bin + + - name: Run npm test + working-directory: ./external-crates/move/crates/move-analyzer/editors/code + shell: bash + run: npm run pretest && DISPLAY=:99.0 npm run test + + move-vscode-extension-build: + name: Move VSCode extension build + runs-on: [self-hosted] + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # Pin v4.1.1 + with: + ref: ${{ github.event.inputs.iota_repo_ref || github.ref }} + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # pin@v4.0.2 + with: + node-version: "20" + + - name: Install dependencies + working-directory: ./external-crates/move/crates/move-analyzer/editors/code + run: npm install && npm install --save-dev @types/node @types/semver + + - name: Build VSCode extension + working-directory: ./external-crates/move/crates/move-analyzer/editors/code + run: npm run package diff --git a/.github/workflows/hierarchy.yml b/.github/workflows/hierarchy.yml index 88862232da1..6456b3e033a 100644 --- a/.github/workflows/hierarchy.yml +++ b/.github/workflows/hierarchy.yml @@ -22,6 +22,7 @@ jobs: isMove: ${{ steps.diff.outputs.isMove }} isDoc: ${{ steps.diff.outputs.isDoc }} isReleaseNotesEligible: ${{ steps.diff.outputs.isReleaseNotesEligible }} + isExternalCrates: ${{ steps.diff.outputs.isExternalCrates }} isWallet: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), 'iota-wallet')) }} isExplorer: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), 'iota-explorer')) }} isTypescriptSDK: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), '@iota/iota-sdk')) }} @@ -148,3 +149,12 @@ jobs: - typos uses: ./.github/workflows/_ledgernano.yml secrets: inherit + + move-ide: + if: (!cancelled() && !failure()) && needs.diff.outputs.isExternalCrates == 'true' && github.event.pull_request.draft == false + needs: + - diff + - dprint-format + - license-check + - typos + uses: ./.github/workflows/_move_ide.yml diff --git a/external-crates/move/crates/move-analyzer/editors/code/scripts/create.sh b/external-crates/move/crates/move-analyzer/editors/code/scripts/create.sh index a63c8adc9fa..f94940ab8fa 100755 --- a/external-crates/move/crates/move-analyzer/editors/code/scripts/create.sh +++ b/external-crates/move/crates/move-analyzer/editors/code/scripts/create.sh @@ -43,9 +43,8 @@ do fi done -# these will have to change if we want a different network/version -NETWORK="alphanet" -VERSION="0.4.0" +# these will have to change if we want a different version +VERSION="0.7.2-rc" # a map from os version identifiers in Iota's binary distribution to os version identifiers # representing VSCode's target platforms used for creating platform-specific plugin distributions @@ -55,7 +54,7 @@ SUPPORTED_OS[macos-arm64]=darwin-arm64 SUPPORTED_OS[linux-x86_64]=linux-x64 #SUPPORTED_OS[windows-x86_64]=win32-x64 -TMP_DIR=$( mktemp -d -t vscode-create ) +TMP_DIR=$( mktemp -d -t vscode-createXXX ) trap "clean_tmp_dir $TMP_DIR" EXIT LANG_SERVER_DIR="language-server" @@ -64,21 +63,21 @@ rm -rf $LANG_SERVER_DIR mkdir $LANG_SERVER_DIR for DIST_OS VSCODE_OS in "${(@kv)SUPPORTED_OS}"; do - # Iota distribution identifier - IOTA_DISTRO=$NETWORK"-v"$VERSION - # name of the Iota distribution archive file, for example iota-testnet-v1.0.0-macos-arm64.tgz - IOTA_ARCHIVE="iota-"$IOTA_DISTRO"-"$DIST_OS".tgz" + # IOTA distribution identifier + IOTA_VERSION="v"$VERSION + # name of the Iota distribution archive file, for example iota-v1.0.0-macos-arm64.tgz + IOTA_ARCHIVE="iota-"$IOTA_VERSION"-"$DIST_OS".tgz" # a path to downloaded Iota archive IOTA_ARCHIVE_PATH=$TMP_DIR"/"$IOTA_ARCHIVE - # download Iota archive file to a given location and uncompress it - curl https://github.com/iotaledger/iota/releases/download/"$IOTA_DISTRO"/"$IOTA_ARCHIVE" -L -o $IOTA_ARCHIVE_PATH + # download IOTA archive file to a given location and uncompress it + curl https://github.com/iotaledger/iota/releases/download/"$IOTA_VERSION"/"$IOTA_ARCHIVE" -L -o $IOTA_ARCHIVE_PATH tar -xf $IOTA_ARCHIVE_PATH --directory $TMP_DIR # names of the move-analyzer binary, both the one becoming part of the extension ($SERVER_BIN) # and the one in the Iota archive ($ARCHIVE_SERVER_BIN) SERVER_BIN="move-analyzer" - ARCHIVE_SERVER_BIN=$SERVER_BIN"-"$DIST_OS + ARCHIVE_SERVER_BIN=$SERVER_BIN if [[ "$DIST_OS" == *"windows"* ]]; then SERVER_BIN="$SERVER_BIN".exe ARCHIVE_SERVER_BIN="$ARCHIVE_SERVER_BIN".exe @@ -86,7 +85,7 @@ for DIST_OS VSCODE_OS in "${(@kv)SUPPORTED_OS}"; do # copy move-analyzer binary to the appropriate location where it's picked up when bundling the # extension - SRC_SERVER_BIN_LOC=$TMP_DIR"/external-crates/move/target/release/"$ARCHIVE_SERVER_BIN + SRC_SERVER_BIN_LOC=$TMP_DIR"/"$ARCHIVE_SERVER_BIN DST_SERVER_BIN_LOC=$LANG_SERVER_DIR"/"$SERVER_BIN cp $SRC_SERVER_BIN_LOC $DST_SERVER_BIN_LOC From 3ff8bf8927182923f01b239d2ced84280f48bb3a Mon Sep 17 00:00:00 2001 From: Samuel Rufinatscha <samuel.rufinatscha@iota.org> Date: Thu, 28 Nov 2024 14:33:46 +0100 Subject: [PATCH 10/12] [iota-faucet] Enable the use of batched mode on faucet (#4110) * fix: Pass at least one coin to the faucet batch queue * fix: Clippy * fix: Rework split point * fix: Enable `batch_enabled` flag for existing batch tests * fix: Add test_faucet_batch_concurrent_requests test * fix: Fix comment * fix: Remove wrong comment --- .../iota-faucet/src/faucet/simple_faucet.rs | 36 ++- crates/iota/tests/cli_tests.rs | 270 +++++++++++++++++- 2 files changed, 293 insertions(+), 13 deletions(-) diff --git a/crates/iota-faucet/src/faucet/simple_faucet.rs b/crates/iota-faucet/src/faucet/simple_faucet.rs index 1a168c35c48..eafb50d4a4a 100644 --- a/crates/iota-faucet/src/faucet/simple_faucet.rs +++ b/crates/iota-faucet/src/faucet/simple_faucet.rs @@ -119,6 +119,11 @@ impl SimpleFaucet { .map(|q| GasCoin::try_from(&q.1).unwrap()) .filter(|coin| coin.0.balance.value() >= (config.amount * config.num_coins as u64)) .collect::<Vec<GasCoin>>(); + + if coins.is_empty() { + return Err(FaucetError::NoGasCoinAvailable); + } + let metrics = FaucetMetrics::new(prometheus_registry); let wal = WriteAheadLog::open(wal_path); @@ -131,16 +136,19 @@ impl SimpleFaucet { config.max_request_queue_length as usize, ); - // This is to handle the case where there is only 1 coin, we want it to go to - // the normal queue - let split_point = if coins.len() > 10 { - coins.len() / 2 + // Split the coins eventually into two pools: one for the gas pool and one for + // the batch pool. The batch pool will only be populated if the batch feature is + // enabled. + let split_point = if config.batch_enabled { + if coins.len() > 1 { + 1 // At least one coin goes to the gas pool the rest to the batch pool + } else { + 0 // Only one coin available, all coins go to the batch pool. This is safe as we have already checked above that `coins` is not empty. + } } else { - coins.len() + coins.len() // All coins go to the gas pool if batch is disabled }; - // Put half of the coins in the old faucet impl queue, and put half in the other - // queue for batch coins. In the test cases we create an account with 5 - // coins so we just let this run with a minimum of 5 coins + for (coins_processed, coin) in coins.iter().enumerate() { let coin_id = *coin.id(); if let Some(write_ahead_log::Entry { @@ -946,6 +954,7 @@ impl Faucet for SimpleFaucet { { return Err(FaucetError::BatchSendQueueFull); } + let mut task_map = self.task_id_cache.lock().await; task_map.insert( id, @@ -1035,6 +1044,7 @@ pub async fn batch_transfer_gases( "Batch transfer attempted of size: {:?}", total_requests ); let total_iota_needed: u64 = requests.iter().flat_map(|(_, _, amounts)| amounts).sum(); + // This loop is utilized to grab a coin that is large enough for the request loop { let gas_coin_response = faucet @@ -1292,7 +1302,10 @@ mod tests { #[tokio::test] async fn test_batch_transfer_interface() { let test_cluster = TestClusterBuilder::new().build().await; - let config: FaucetConfig = Default::default(); + let config: FaucetConfig = FaucetConfig { + batch_enabled: true, + ..Default::default() + }; let coin_amount = config.amount; let prom_registry = Registry::new(); let tmp = tempfile::tempdir().unwrap(); @@ -1892,7 +1905,10 @@ mod tests { #[tokio::test] async fn test_amounts_transferred_on_batch() { let test_cluster = TestClusterBuilder::new().build().await; - let config: FaucetConfig = Default::default(); + let config: FaucetConfig = FaucetConfig { + batch_enabled: true, + ..Default::default() + }; let address = test_cluster.get_address_0(); let mut context = test_cluster.wallet; let gas_coins = context diff --git a/crates/iota/tests/cli_tests.rs b/crates/iota/tests/cli_tests.rs index 3f75f606082..aaded6cecdb 100644 --- a/crates/iota/tests/cli_tests.rs +++ b/crates/iota/tests/cli_tests.rs @@ -55,8 +55,8 @@ use iota_test_transaction_builder::batch_make_transfer_transactions; use iota_types::{ base_types::{IotaAddress, ObjectID}, crypto::{ - Ed25519IotaSignature, IotaKeyPair, IotaSignatureInner, Secp256k1IotaSignature, - SignatureScheme, get_key_pair, + AccountKeyPair, Ed25519IotaSignature, IotaKeyPair, IotaSignatureInner, + Secp256k1IotaSignature, SignatureScheme, get_key_pair, }, error::IotaObjectResponseError, gas_coin::GasCoin, @@ -4168,8 +4168,10 @@ async fn test_faucet() -> Result<(), anyhow::Error> { let wallet_config = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG); let mut context = WalletContext::new(&wallet_config, None, None)?; + let (address, _): (_, AccountKeyPair) = get_key_pair(); + let faucet_result = IotaClientCommands::Faucet { - address: None, + address: Some(KeyIdentity::Address(address)), url: Some("http://127.0.0.1:5003/gas".to_string()), } .execute(&mut context) @@ -4180,6 +4182,268 @@ async fn test_faucet() -> Result<(), anyhow::Error> { unreachable!("Invalid response"); }; + sleep(Duration::from_secs(5)).await; + + let gas_objects_after = context + .get_gas_objects_owned_by_address(address, None) + .await + .unwrap() + .len(); + assert_eq!(gas_objects_after, 1); + + Ok(()) +} + +#[sim_test] +async fn test_faucet_batch() -> Result<(), anyhow::Error> { + let test_cluster = TestClusterBuilder::new() + .with_fullnode_rpc_port(9000) + .build() + .await; + + let context = test_cluster.wallet; + + let tmp = tempfile::tempdir().unwrap(); + let prom_registry = prometheus::Registry::new(); + let config = iota_faucet::FaucetConfig { + batch_enabled: true, + ..Default::default() + }; + + let prometheus_registry = prometheus::Registry::new(); + let app_state = std::sync::Arc::new(iota_faucet::AppState { + faucet: iota_faucet::SimpleFaucet::new( + context, + &prometheus_registry, + &tmp.path().join("faucet.wal"), + config.clone(), + ) + .await + .unwrap(), + config, + }); + tokio::spawn(async move { iota_faucet::start_faucet(app_state, 10, &prom_registry).await }); + + // Wait for the faucet to be up + sleep(Duration::from_secs(1)).await; + let wallet_config = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG); + let mut context = WalletContext::new(&wallet_config, None, None)?; + + let (address_1, _): (_, AccountKeyPair) = get_key_pair(); + let (address_2, _): (_, AccountKeyPair) = get_key_pair(); + let (address_3, _): (_, AccountKeyPair) = get_key_pair(); + + assert_ne!(address_1, address_2); + assert_ne!(address_1, address_3); + assert_ne!(address_2, address_3); + + for address in [address_1, address_2, address_3].iter() { + let gas_objects_after = context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(); + assert_eq!(gas_objects_after, 0); + } + + for address in [address_1, address_2, address_3].iter() { + let faucet_result = IotaClientCommands::Faucet { + address: Some(KeyIdentity::Address(*address)), + url: Some("http://127.0.0.1:5003/v1/gas".to_string()), + } + .execute(&mut context) + .await?; + + if let IotaClientCommandResult::NoOutput = faucet_result { + } else { + unreachable!("Invalid response"); + }; + } + + // we need to wait a minimum of 10 seconds for gathering the batch + some time + // for transaction to be sequenced + sleep(Duration::from_secs(15)).await; + + for address in [address_1, address_2, address_3].iter() { + let gas_objects_after = context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(); + assert_eq!(gas_objects_after, 1); + } + + // try with a new batch + let (address_4, _): (_, AccountKeyPair) = get_key_pair(); + let (address_5, _): (_, AccountKeyPair) = get_key_pair(); + let (address_6, _): (_, AccountKeyPair) = get_key_pair(); + + assert_ne!(address_4, address_5); + assert_ne!(address_4, address_6); + assert_ne!(address_5, address_6); + + for address in [address_4, address_5, address_6].iter() { + let gas_objects_after = context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(); + assert_eq!(gas_objects_after, 0); + } + + for address in [address_4, address_5, address_6].iter() { + let faucet_result = IotaClientCommands::Faucet { + address: Some(KeyIdentity::Address(*address)), + url: Some("http://127.0.0.1:5003/v1/gas".to_string()), + } + .execute(&mut context) + .await?; + + if let IotaClientCommandResult::NoOutput = faucet_result { + } else { + unreachable!("Invalid response"); + }; + } + + // we need to wait a minimum of 10 seconds for gathering the batch + some time + // for transaction to be sequenced + sleep(Duration::from_secs(15)).await; + + for address in [address_4, address_5, address_6].iter() { + let gas_objects_after = context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(); + assert_eq!(gas_objects_after, 1); + } + + Ok(()) +} + +#[sim_test] +async fn test_faucet_batch_concurrent_requests() -> Result<(), anyhow::Error> { + let test_cluster = TestClusterBuilder::new() + .with_fullnode_rpc_port(9000) + .build() + .await; + + let context = test_cluster.wallet; + + let tmp = tempfile::tempdir().unwrap(); + let prom_registry = prometheus::Registry::new(); + let config = iota_faucet::FaucetConfig { + batch_enabled: true, + ..Default::default() + }; + + let prometheus_registry = prometheus::Registry::new(); + let app_state = std::sync::Arc::new(iota_faucet::AppState { + faucet: iota_faucet::SimpleFaucet::new( + context, + &prometheus_registry, + &tmp.path().join("faucet.wal"), + config.clone(), + ) + .await + .unwrap(), + config, + }); + tokio::spawn(async move { iota_faucet::start_faucet(app_state, 10, &prom_registry).await }); + + // Wait for the faucet to be up + sleep(Duration::from_secs(1)).await; + + let wallet_config = test_cluster.swarm.dir().join(IOTA_CLIENT_CONFIG); + let context = WalletContext::new(&wallet_config, None, None)?; // Use immutable context + + // Generate multiple addresses + let addresses: Vec<_> = (0..6) + .map(|_| get_key_pair::<AccountKeyPair>().0) + .collect::<Vec<IotaAddress>>(); + + // Ensure all addresses have zero gas objects initially + for address in &addresses { + assert_eq!( + context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(), + 0 + ); + } + + // First batch: send faucet requests concurrently for all addresses + let first_batch_results: Vec<_> = futures::future::join_all(addresses.iter().map(|address| { + let wallet_config = wallet_config.clone(); + async move { + let mut context = WalletContext::new(&wallet_config, None, None)?; // Use mutable context (for faucet requests) + IotaClientCommands::Faucet { + address: Some(KeyIdentity::Address(*address)), + url: Some("http://127.0.0.1:5003/v1/gas".to_string()), + } + .execute(&mut context) + .await + } + })) + .await; + + // Ensure all results are `NoOutput` indicating requests were batched + for result in first_batch_results { + assert!(matches!(result, Ok(IotaClientCommandResult::NoOutput))); + } + + // Wait for the first batch to complete + sleep(Duration::from_secs(15)).await; + + // Validate gas objects after the first batch + for address in &addresses { + assert_eq!( + context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(), + 1 + ); + } + + // Second batch: send faucet requests again for all addresses + let second_batch_results: Vec<_> = futures::future::join_all(addresses.iter().map(|address| { + let wallet_config = wallet_config.clone(); + async move { + let mut context = WalletContext::new(&wallet_config, None, None)?; // Use mutable context + IotaClientCommands::Faucet { + address: Some(KeyIdentity::Address(*address)), + url: Some("http://127.0.0.1:5003/v1/gas".to_string()), + } + .execute(&mut context) + .await + } + })) + .await; + + // Ensure all results are `NoOutput` for the second batch + for result in second_batch_results { + assert!(matches!(result, Ok(IotaClientCommandResult::NoOutput))); + } + + // Wait for the second batch to complete + sleep(Duration::from_secs(15)).await; + + // Validate gas objects after the second batch + for address in &addresses { + assert_eq!( + context + .get_gas_objects_owned_by_address(*address, None) + .await + .unwrap() + .len(), + 2 + ); + } + Ok(()) } From b627c887c0a23ae6dacbcd42b4a00d2a2f2c724d Mon Sep 17 00:00:00 2001 From: Samuel Rufinatscha <samuel.rufinatscha@iota.org> Date: Thu, 28 Nov 2024 15:09:18 +0100 Subject: [PATCH 11/12] Fix `StructTag` conversion for `iotax_queryEvents` Indexer-RPC method (#4289) * fix: convert the struct tag into a complete canonical string in order for the indexer's `MoveEventType` filter to work * fix: clippy --- crates/iota-indexer/src/indexer_reader.rs | 3 +- .../tests/rpc-tests/indexer_api.rs | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/crates/iota-indexer/src/indexer_reader.rs b/crates/iota-indexer/src/indexer_reader.rs index 3915588184f..1fa26c1969c 100644 --- a/crates/iota-indexer/src/indexer_reader.rs +++ b/crates/iota-indexer/src/indexer_reader.rs @@ -1161,7 +1161,8 @@ impl<U: R2D2Connection> IndexerReader<U> { ) } EventFilter::MoveEventType(struct_tag) => { - format!("event_type = '{}'", struct_tag) + let formatted_struct_tag = struct_tag.to_canonical_string(true); + format!("event_type = '{formatted_struct_tag}'") } EventFilter::MoveEventModule { package, module } => { let package_module_prefix = format!("{}::{}", package.to_hex_literal(), module); diff --git a/crates/iota-indexer/tests/rpc-tests/indexer_api.rs b/crates/iota-indexer/tests/rpc-tests/indexer_api.rs index c830f7ae7a7..49f4e35ff80 100644 --- a/crates/iota-indexer/tests/rpc-tests/indexer_api.rs +++ b/crates/iota-indexer/tests/rpc-tests/indexer_api.rs @@ -185,6 +185,38 @@ fn query_events_supported_events() { }); } +#[test] +fn query_validator_epoch_info_event() { + let ApiTestSetup { + runtime, + store, + client, + cluster, + } = ApiTestSetup::get_or_init(); + + runtime.block_on(async move { + indexer_wait_for_checkpoint(store, 1).await; + + cluster.force_new_epoch().await; + + let result = client.query_events(EventFilter::MoveEventType("0x0000000000000000000000000000000000000000000000000000000000000003::validator_set::ValidatorEpochInfoEventV1".parse().unwrap()), None, None, None).await; + assert!(result.is_ok()); + assert!(!result.unwrap().data.is_empty()); + + let result = client.query_events(EventFilter::MoveEventType("0x3::validator_set::ValidatorEpochInfoEventV1".parse().unwrap()), None, None, None).await; + assert!(result.is_ok()); + assert!(!result.unwrap().data.is_empty()); + + let result = client.query_events(EventFilter::MoveEventType("0x0003::validator_set::ValidatorEpochInfoEventV1".parse().unwrap()), None, None, None).await; + assert!(result.is_ok()); + assert!(!result.unwrap().data.is_empty()); + + let result = client.query_events(EventFilter::MoveEventType("0x1::validator_set::ValidatorEpochInfoEventV1".parse().unwrap()), None, None, None).await; + assert!(result.is_ok()); + assert!(result.unwrap().data.is_empty()); + }); +} + #[test] fn test_get_owned_objects() -> Result<(), anyhow::Error> { let ApiTestSetup { From baed3f70db2b26d1617489f2987ec95b85d5cd1b Mon Sep 17 00:00:00 2001 From: Thibault Martinez <thibault@iota.org> Date: Thu, 28 Nov 2024 15:43:38 +0100 Subject: [PATCH 12/12] chore(*): bump rust toolchain to 1.82 (#4235) --- crates/iota-graphql-rpc-client/src/response.rs | 2 ++ crates/iota-graphql-rpc-client/src/simple_client.rs | 2 +- crates/iota-replay/src/data_fetcher.rs | 6 ++++-- crates/iota-replay/src/types.rs | 2 +- crates/iota-source-validation/src/error.rs | 4 ++-- crates/iota-source-validation/src/lib.rs | 6 +++--- rust-toolchain.toml | 2 +- scripts/generate_files/Dockerfile | 2 +- 8 files changed, 15 insertions(+), 11 deletions(-) diff --git a/crates/iota-graphql-rpc-client/src/response.rs b/crates/iota-graphql-rpc-client/src/response.rs index 2100a1aac94..40c24e93cf8 100644 --- a/crates/iota-graphql-rpc-client/src/response.rs +++ b/crates/iota-graphql-rpc-client/src/response.rs @@ -40,6 +40,7 @@ impl GraphqlResponse { }) } + #[allow(clippy::result_large_err)] pub fn graphql_version(&self) -> Result<String, ClientError> { Ok(self .headers @@ -90,6 +91,7 @@ impl GraphqlResponse { self.full_response.errors.clone() } + #[allow(clippy::result_large_err)] pub fn usage(&self) -> Result<Option<BTreeMap<String, u64>>, ClientError> { Ok(match self.full_response.extensions.get("usage").cloned() { Some(Value::Object(obj)) => Some( diff --git a/crates/iota-graphql-rpc-client/src/simple_client.rs b/crates/iota-graphql-rpc-client/src/simple_client.rs index 852ece48b8c..f78f8ca3753 100644 --- a/crates/iota-graphql-rpc-client/src/simple_client.rs +++ b/crates/iota-graphql-rpc-client/src/simple_client.rs @@ -117,7 +117,7 @@ impl SimpleClient { } } -#[allow(clippy::type_complexity)] +#[allow(clippy::type_complexity, clippy::result_large_err)] pub fn resolve_variables( vars: &[GraphqlQueryVariable], ) -> Result<(BTreeMap<String, String>, BTreeMap<String, Value>), ClientError> { diff --git a/crates/iota-replay/src/data_fetcher.rs b/crates/iota-replay/src/data_fetcher.rs index 4bf7a73d398..70749a03dbe 100644 --- a/crates/iota-replay/src/data_fetcher.rs +++ b/crates/iota-replay/src/data_fetcher.rs @@ -522,7 +522,7 @@ impl DataFetcher for RemoteFetcher { u64::from_str(&w["reference_gas_price"].to_string().replace('\"', "")).unwrap() } else { return Err(ReplayEngineError::UnexpectedEventFormat { - event: event.clone(), + event: Box::new(event.clone()), }); }; @@ -639,7 +639,9 @@ pub fn extract_epoch_and_version(ev: IotaEvent) -> Result<(u64, u64), ReplayEngi return Ok((epoch, version)); } - Err(ReplayEngineError::UnexpectedEventFormat { event: ev }) + Err(ReplayEngineError::UnexpectedEventFormat { + event: Box::new(ev), + }) } #[derive(Clone)] diff --git a/crates/iota-replay/src/types.rs b/crates/iota-replay/src/types.rs index 993868020a6..05c90fffe71 100644 --- a/crates/iota-replay/src/types.rs +++ b/crates/iota-replay/src/types.rs @@ -166,7 +166,7 @@ pub enum ReplayEngineError { InvalidEpochChangeTx { epoch: u64 }, #[error("Unexpected event format {:#?}", event)] - UnexpectedEventFormat { event: IotaEvent }, + UnexpectedEventFormat { event: Box<IotaEvent> }, #[error("Unable to find event for epoch {epoch}")] EventNotFound { epoch: u64 }, diff --git a/crates/iota-source-validation/src/error.rs b/crates/iota-source-validation/src/error.rs index 36cb79955fb..c9060245b5e 100644 --- a/crates/iota-source-validation/src/error.rs +++ b/crates/iota-source-validation/src/error.rs @@ -49,8 +49,8 @@ pub enum Error { module: Symbol, }, - #[error("Dependency ID contains a Iota object, not a Move package: {0}")] - ObjectFoundWhenPackageExpected(ObjectID, IotaRawMoveObject), + #[error("Dependency ID contains a Iota object, not a Move package: {}", .0.0)] + ObjectFoundWhenPackageExpected(Box<(ObjectID, IotaRawMoveObject)>), #[error("Could not deserialize on-chain dependency {address}::{module}.")] OnChainDependencyDeserializationError { diff --git a/crates/iota-source-validation/src/lib.rs b/crates/iota-source-validation/src/lib.rs index 38009f1fe89..18a3942c7cc 100644 --- a/crates/iota-source-validation/src/lib.rs +++ b/crates/iota-source-validation/src/lib.rs @@ -414,9 +414,9 @@ impl<'a> BytecodeSourceVerifier<'a> { match obj { IotaRawData::Package(pkg) => Ok(pkg), - IotaRawData::MoveObject(move_obj) => { - Err(Error::ObjectFoundWhenPackageExpected(obj_id, move_obj)) - } + IotaRawData::MoveObject(move_obj) => Err(Error::ObjectFoundWhenPackageExpected( + Box::new((obj_id, move_obj)), + )), } } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4cef0b738ff..76fcadb5b32 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.81" +channel = "1.82" diff --git a/scripts/generate_files/Dockerfile b/scripts/generate_files/Dockerfile index 7b832715976..334aa855498 100644 --- a/scripts/generate_files/Dockerfile +++ b/scripts/generate_files/Dockerfile @@ -1,7 +1,7 @@ FROM node:20-bookworm # Accept a build argument for the Rust version -ARG RUST_VERSION=1.81 +ARG RUST_VERSION=1.82 # Get USER_ID from build-args ARG USER_ID=1000