Create wrapper to handle failed txs
This commit is contained in:
parent
3d9aedeb7e
commit
a47dda4fbc
@ -15,7 +15,7 @@ import {
|
||||
ApplicationDeploymentRemovalRequest
|
||||
} from './entity/Deployment';
|
||||
import { AppDeploymentRecord, AppDeploymentRemovalRecord, AuctionParams, DeployerRecord } from './types';
|
||||
import { getConfig, getRepoDetails, sleep } from './utils';
|
||||
import { getConfig, getRepoDetails, registryTransactionWithRetry, sleep } from './utils';
|
||||
|
||||
const log = debug('snowball:registry');
|
||||
|
||||
@ -108,14 +108,16 @@ export class Registry {
|
||||
|
||||
const fee = parseGasAndFees(this.registryConfig.fee.gas, this.registryConfig.fee.fees);
|
||||
|
||||
const result = await this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationRecord,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
const result = await registryTransactionWithRetry(() =>
|
||||
this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationRecord,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
log(`Published application record ${result.id}`);
|
||||
@ -126,33 +128,39 @@ export class Registry {
|
||||
log(`Setting name: ${lrn} for record ID: ${result.id}`);
|
||||
|
||||
await sleep(SLEEP_DURATION);
|
||||
await this.registry.setName(
|
||||
{
|
||||
cid: result.id,
|
||||
lrn
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
await registryTransactionWithRetry(() =>
|
||||
this.registry.setName(
|
||||
{
|
||||
cid: result.id,
|
||||
lrn
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
await sleep(SLEEP_DURATION);
|
||||
await this.registry.setName(
|
||||
{
|
||||
cid: result.id,
|
||||
lrn: `${lrn}@${applicationRecord.app_version}`
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
await registryTransactionWithRetry(() =>
|
||||
this.registry.setName(
|
||||
{
|
||||
cid: result.id,
|
||||
lrn: `${lrn}@${applicationRecord.app_version}`
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
await sleep(SLEEP_DURATION);
|
||||
await this.registry.setName(
|
||||
{
|
||||
cid: result.id,
|
||||
lrn: `${lrn}@${applicationRecord.repository_ref}`
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
await registryTransactionWithRetry(() =>
|
||||
this.registry.setName(
|
||||
{
|
||||
cid: result.id,
|
||||
lrn: `${lrn}@${applicationRecord.repository_ref}`
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
@ -183,19 +191,21 @@ export class Registry {
|
||||
const auctionConfig = config.auction;
|
||||
|
||||
const fee = parseGasAndFees(this.registryConfig.fee.gas, this.registryConfig.fee.fees);
|
||||
const auctionResult = await this.registry.createProviderAuction(
|
||||
{
|
||||
commitFee: auctionConfig.commitFee,
|
||||
commitsDuration: auctionConfig.commitsDuration,
|
||||
revealFee: auctionConfig.revealFee,
|
||||
revealsDuration: auctionConfig.revealsDuration,
|
||||
denom: auctionConfig.denom,
|
||||
maxPrice: auctionParams.maxPrice,
|
||||
numProviders: auctionParams.numProviders,
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
const auctionResult = await registryTransactionWithRetry(() =>
|
||||
this.registry.createProviderAuction(
|
||||
{
|
||||
commitFee: auctionConfig.commitFee,
|
||||
commitsDuration: auctionConfig.commitsDuration,
|
||||
revealFee: auctionConfig.revealFee,
|
||||
revealsDuration: auctionConfig.revealsDuration,
|
||||
denom: auctionConfig.denom,
|
||||
maxPrice: auctionParams.maxPrice,
|
||||
numProviders: auctionParams.numProviders,
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
if (!auctionResult.auction) {
|
||||
throw new Error('Error creating auction');
|
||||
@ -208,14 +218,16 @@ export class Registry {
|
||||
type: APP_DEPLOYMENT_AUCTION_RECORD_TYPE,
|
||||
};
|
||||
|
||||
const result = await this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationDeploymentAuction,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
const result = await registryTransactionWithRetry(() =>
|
||||
this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationDeploymentAuction,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
log(`Application deployment auction created: ${auctionResult.auction.id}`);
|
||||
@ -274,14 +286,16 @@ export class Registry {
|
||||
|
||||
const fee = parseGasAndFees(this.registryConfig.fee.gas, this.registryConfig.fee.fees);
|
||||
|
||||
const result = await this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationDeploymentRequest,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
const result = await registryTransactionWithRetry(() =>
|
||||
this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationDeploymentRequest,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
log(`Application deployment request record published: ${result.id}`);
|
||||
@ -322,12 +336,14 @@ export class Registry {
|
||||
auctionId: string
|
||||
): Promise<any> {
|
||||
const fee = parseGasAndFees(this.registryConfig.fee.gas, this.registryConfig.fee.fees);
|
||||
const auction = await this.registry.releaseFunds(
|
||||
{
|
||||
auctionId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
const auction = await registryTransactionWithRetry(() =>
|
||||
this.registry.releaseFunds(
|
||||
{
|
||||
auctionId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
return auction;
|
||||
@ -424,14 +440,16 @@ export class Registry {
|
||||
|
||||
const fee = parseGasAndFees(this.registryConfig.fee.gas, this.registryConfig.fee.fees);
|
||||
|
||||
const result = await this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationDeploymentRemovalRequest,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
const result = await registryTransactionWithRetry(() =>
|
||||
this.registry.setRecord(
|
||||
{
|
||||
privateKey: this.registryConfig.privateKey,
|
||||
record: applicationDeploymentRemovalRequest,
|
||||
bondId: this.registryConfig.bondId
|
||||
},
|
||||
this.registryConfig.privateKey,
|
||||
fee
|
||||
)
|
||||
);
|
||||
|
||||
log(`Application deployment removal request record published: ${result.id}`);
|
||||
|
@ -120,3 +120,24 @@ export const getRepoDetails = async (
|
||||
repoUrl
|
||||
};
|
||||
}
|
||||
|
||||
// Wrapper method for registry txs to retry once if 'account sequence mismatch' occurs
|
||||
export const registryTransactionWithRetry = async (
|
||||
txMethod: () => Promise<any>
|
||||
): Promise<any> => {
|
||||
try {
|
||||
return await txMethod();
|
||||
} catch (error: any) {
|
||||
if (!error.message.includes('account sequence mismatch')) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.error(`Transaction failed due to account sequence mismatch. Retrying...`);
|
||||
|
||||
try {
|
||||
return await txMethod();
|
||||
} catch (retryError: any) {
|
||||
throw new Error(`Transaction failed again after retry: ${retryError.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
import ConfirmDialog, {
|
||||
ConfirmDialogProps,
|
||||
} from 'components/shared/ConfirmDialog';
|
||||
import { ArrowRightCircleFilledIcon, LoadingIcon } from 'components/shared/CustomIcon';
|
||||
import {
|
||||
ArrowRightCircleFilledIcon,
|
||||
LoadingIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
|
||||
interface DeleteDeploymentDialogProps extends ConfirmDialogProps {
|
||||
isConfirmButtonLoading?: boolean;
|
||||
@ -20,7 +23,11 @@ export const DeleteDeploymentDialog = ({
|
||||
dialogTitle="Delete deployment?"
|
||||
handleCancel={handleCancel}
|
||||
open={open}
|
||||
confirmButtonTitle={isConfirmButtonLoading ? "Deleting deployment" : "Yes, delete deployment"}
|
||||
confirmButtonTitle={
|
||||
isConfirmButtonLoading
|
||||
? 'Deleting deployment'
|
||||
: 'Yes, delete deployment'
|
||||
}
|
||||
handleConfirm={handleConfirm}
|
||||
confirmButtonProps={{
|
||||
variant: 'danger',
|
||||
|
@ -3,7 +3,11 @@ import { useForm, Controller } from 'react-hook-form';
|
||||
import { FormProvider, FieldValues } from 'react-hook-form';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useMediaQuery } from 'usehooks-ts';
|
||||
import { AddEnvironmentVariableInput, AuctionParams, Deployer } from 'gql-client';
|
||||
import {
|
||||
AddEnvironmentVariableInput,
|
||||
AuctionParams,
|
||||
Deployer,
|
||||
} from 'gql-client';
|
||||
|
||||
import { Select, MenuItem, FormControl, FormHelperText } from '@mui/material';
|
||||
|
||||
@ -156,32 +160,32 @@ const Configure = () => {
|
||||
if (templateId) {
|
||||
createFormData.option === 'Auction'
|
||||
? navigate(
|
||||
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
||||
)
|
||||
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
||||
)
|
||||
: navigate(
|
||||
`/${orgSlug}/projects/create/template/deploy?projectId=${projectId}&templateId=${templateId}`,
|
||||
);
|
||||
`/${orgSlug}/projects/create/template/deploy?projectId=${projectId}&templateId=${templateId}`,
|
||||
);
|
||||
} else {
|
||||
createFormData.option === 'Auction'
|
||||
? navigate(
|
||||
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
||||
)
|
||||
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
||||
)
|
||||
: navigate(
|
||||
`/${orgSlug}/projects/create/deploy?projectId=${projectId}`,
|
||||
);
|
||||
`/${orgSlug}/projects/create/deploy?projectId=${projectId}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
[client, createProject, dismiss, toast],
|
||||
);
|
||||
|
||||
const fetchDeployers = useCallback(async () => {
|
||||
const res = await client.getDeployers()
|
||||
setDeployers(res.deployers)
|
||||
}, [client])
|
||||
const res = await client.getDeployers();
|
||||
setDeployers(res.deployers);
|
||||
}, [client]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDeployers()
|
||||
}, [])
|
||||
fetchDeployers();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="space-y-7 px-4 py-6">
|
||||
@ -209,7 +213,7 @@ const Configure = () => {
|
||||
<Select
|
||||
value={value}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
size='small'
|
||||
size="small"
|
||||
displayEmpty
|
||||
>
|
||||
<MenuItem value="LRN">Deployer LRN</MenuItem>
|
||||
@ -240,15 +244,22 @@ const Configure = () => {
|
||||
value={value}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
displayEmpty
|
||||
size='small'
|
||||
size="small"
|
||||
>
|
||||
{deployers.map((deployer) => (
|
||||
<MenuItem key={deployer.deployerLrn} value={deployer.deployerLrn}>
|
||||
<MenuItem
|
||||
key={deployer.deployerLrn}
|
||||
value={deployer.deployerLrn}
|
||||
>
|
||||
{deployer.deployerLrn}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{fieldState.error && <FormHelperText>{fieldState.error.message}</FormHelperText>}
|
||||
{fieldState.error && (
|
||||
<FormHelperText>
|
||||
{fieldState.error.message}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
@ -185,8 +185,8 @@ const DeploymentDetailsCard = ({
|
||||
type="orange"
|
||||
initials={getInitials(deployment.createdBy.name ?? '')}
|
||||
className="lg:size-5 2xl:size-6"
|
||||
// TODO: Add avatarUrl
|
||||
// imageSrc={deployment.createdBy.avatarUrl}
|
||||
// TODO: Add avatarUrl
|
||||
// imageSrc={deployment.createdBy.avatarUrl}
|
||||
></Avatar>
|
||||
</div>
|
||||
<OverflownText
|
||||
|
@ -105,7 +105,6 @@ export const AuctionCard = ({ project }: { project: Project }) => {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex justify-between items-center mt-1">
|
||||
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
||||
Auction Status
|
||||
|
@ -132,7 +132,7 @@ export const project: Project = {
|
||||
deployerApiUrl: 'https://webapp-deployer-api.example.com',
|
||||
deployerId: 'bafyreicrtgmkir4evvvysxdqxddf2ftdq2wrzuodgvwnxr4rmubi4obdfu',
|
||||
deployerLrn: 'lrn://deployer.apps.snowballtools.com ',
|
||||
}
|
||||
},
|
||||
],
|
||||
webhooks: ['beepboop'],
|
||||
icon: 'Icon',
|
||||
|
Loading…
Reference in New Issue
Block a user