Skip to content

Commit

Permalink
Weights V2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
niklabh authored and github-actions[bot] committed Mar 27, 2023
1 parent ba21cfe commit aeb17bf
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 55 deletions.
2 changes: 1 addition & 1 deletion packages/page-contracts/src/Codes/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function Upload ({ onClose }: Props): React.ReactElement {
try {
contract = code && contractAbi?.constructors[constructorIndex]?.method && value
? code.tx[contractAbi.constructors[constructorIndex].method]({
gasLimit: weight.weight,
gasLimit: weight.isWeightV2 ? weight.weightV2 : weight.weight,
storageDepositLimit: null,
value: contractAbi?.constructors[constructorIndex].isPayable ? value : undefined
}, ...params)
Expand Down
49 changes: 36 additions & 13 deletions packages/page-contracts/src/Contracts/Call.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import type { SubmittableExtrinsic } from '@polkadot/api/types';
import type { ContractPromise } from '@polkadot/api-contract';
import type { ContractCallOutcome } from '@polkadot/api-contract/types';
import type { CallResult } from './types.js';
import type { WeightV2 } from '@polkadot/types/interfaces';
import type { CallResult } from './types';

import React, { useCallback, useEffect, useState } from 'react';

import { Button, Dropdown, Expander, InputAddress, InputBalance, Modal, styled, Toggle, TxButton } from '@polkadot/react-components';
import { useAccountId, useDebounce, useFormField, useToggle } from '@polkadot/react-hooks';
import { convertWeight } from '@polkadot/react-hooks/useWeight';
import { useAccountId, useApi, useDebounce, useFormField, useToggle } from '@polkadot/react-hooks';
import { Available } from '@polkadot/react-query';
import { BN, BN_ONE, BN_ZERO } from '@polkadot/util';

Expand All @@ -33,9 +33,11 @@ const MAX_CALL_WEIGHT = new BN(5_000_000_000_000).isub(BN_ONE);

function Call ({ className = '', contract, messageIndex, onCallResult, onChangeMessage, onClose }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const message = contract.abi.messages[messageIndex];
const [accountId, setAccountId] = useAccountId();
const [estimatedWeight, setEstimatedWeight] = useState<BN | null>(null);
const [estimatedWeightV2, setEstimatedWeightV2] = useState<WeightV2 | null>(null);
const [value, isValueValid, setValue] = useFormField<BN>(BN_ZERO);
const [outcomes, setOutcomes] = useState<CallResult[]>([]);
const [execTx, setExecTx] = useState<SubmittableExtrinsic<'promise'> | null>(null);
Expand All @@ -47,14 +49,18 @@ function Call ({ className = '', contract, messageIndex, onCallResult, onChangeM

useEffect((): void => {
setEstimatedWeight(null);
setEstimatedWeightV2(null);
setParams([]);
}, [contract, messageIndex]);

useEffect((): void => {
value && message.isMutating && setExecTx((): SubmittableExtrinsic<'promise'> | null => {
try {
return contract.tx[message.method]({ gasLimit: weight.weight, storageDepositLimit: null, value: message.isPayable ? value : 0 }, ...params);
} catch {
return contract.tx[message.method](
{ gasLimit: weight.isWeightV2 ? weight.weightV2 : weight.weight, storageDepositLimit: null, value: message.isPayable ? value : 0 },
...params
);
} catch (error) {
return null;
}
});
Expand All @@ -67,13 +73,26 @@ function Call ({ className = '', contract, messageIndex, onCallResult, onChangeM

contract
.query[message.method](accountId, { gasLimit: -1, storageDepositLimit: null, value: message.isPayable ? dbValue : 0 }, ...dbParams)
.then(({ gasRequired, result }) => setEstimatedWeight(
result.isOk
? convertWeight(gasRequired).v1Weight
: null
))
.catch(() => setEstimatedWeight(null));
}, [accountId, contract, message, dbParams, dbValue]);
.then(({ gasRequired, result }) => {
if (weight.isWeightV2) {
setEstimatedWeightV2(
result.isOk
? api.registry.createType('WeightV2', gasRequired)
: null
);
} else {
setEstimatedWeight(
result.isOk
? gasRequired
: null
);
}
})
.catch(() => {
setEstimatedWeight(null);
setEstimatedWeightV2(null);
});
}, [api, accountId, contract, message, dbParams, dbValue, weight.isWeightV2]);

const _onSubmitRpc = useCallback(
(): void => {
Expand All @@ -82,7 +101,11 @@ function Call ({ className = '', contract, messageIndex, onCallResult, onChangeM
}

contract
.query[message.method](accountId, { gasLimit: weight.isEmpty ? -1 : weight.weight, storageDepositLimit: null, value: message.isPayable ? value : 0 }, ...params)
.query[message.method](
accountId,
{ gasLimit: weight.isWeightV2 ? weight.weightV2 : weight.isEmpty ? -1 : weight.weight, storageDepositLimit: null, value: message.isPayable ? value : 0 },
...params
)
.then((result): void => {
setOutcomes([{
...result,
Expand Down
2 changes: 1 addition & 1 deletion packages/page-contracts/src/Contracts/Deploy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function Deploy ({ codeHash, constructorIndex = 0, onClose, setConstructorIndex
if (blueprint && contractAbi?.constructors[constructorIndex]?.method) {
try {
return blueprint.tx[contractAbi.constructors[constructorIndex].method]({
gasLimit: weight.weight,
gasLimit: weight.isWeightV2 ? weight.weightV2 : weight.weight,
salt: withSalt
? salt
: null,
Expand Down
154 changes: 118 additions & 36 deletions packages/page-contracts/src/shared/InputMegaGas.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
// Copyright 2017-2023 @polkadot/app-contracts authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { WeightV2 } from '@polkadot/types/interfaces';
import type { BN } from '@polkadot/util';
import type { UseWeight } from '../types.js';

import React, { useEffect, useMemo, useState } from 'react';

import { InputNumber, styled, Toggle } from '@polkadot/react-components';
import { InputNumber, Toggle } from '@polkadot/react-components';
import { BN_MILLION, BN_ONE, BN_ZERO } from '@polkadot/util';

import { useTranslation } from '../translate.js';

interface Props {
className?: string;
estimatedWeight?: BN | null;
estimatedWeight?: BN
estimatedWeightV2?: WeightV2;
help: React.ReactNode;
isCall?: boolean;
weight: UseWeight;
}

function InputMegaGas ({ className, estimatedWeight, isCall, weight: { executionTime, isValid, megaGas, percentage, setIsEmpty, setMegaGas } }: Props): React.ReactElement<Props> {
function InputMegaGas ({ className,
estimatedWeight,
estimatedWeightV2,
help,
isCall,
weight: { executionTime,
isValid,
isWeightV2,
megaGas,
megaRefTime,
percentage,
proofSize,
setIsEmpty,
setMegaGas,
setMegaRefTime,
setProofSize } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [withEstimate, setWithEstimate] = useState(true);

Expand All @@ -29,54 +47,118 @@ function InputMegaGas ({ className, estimatedWeight, isCall, weight: { execution
[estimatedWeight]
);

const estimatedMgRefTime = useMemo(
() => estimatedWeightV2
? estimatedWeightV2.refTime.toBn().div(BN_MILLION).iadd(BN_ONE)
: null,
[estimatedWeightV2]
);

const estimatedProofSize = useMemo(
() => estimatedWeightV2
? estimatedWeightV2.proofSize.toBn()
: null,
[estimatedWeightV2]
);

useEffect((): void => {
withEstimate && estimatedMg && setMegaGas(estimatedMg);
}, [estimatedMg, setMegaGas, withEstimate]);

useEffect((): void => {
withEstimate && estimatedMgRefTime && setMegaRefTime(estimatedMgRefTime);
}, [estimatedMgRefTime, setMegaRefTime, withEstimate]);

useEffect((): void => {
withEstimate && estimatedProofSize && setProofSize(estimatedProofSize);
}, [estimatedProofSize, setProofSize, withEstimate]);

useEffect((): void => {
setIsEmpty(withEstimate && !!isCall);
}, [isCall, setIsEmpty, withEstimate]);

const isDisabled = !!estimatedMg && withEstimate;

return (
<StyledDiv className={className}>
<InputNumber
defaultValue={estimatedMg && isDisabled ? estimatedMg.toString() : undefined}
isDisabled={isDisabled}
isError={!isValid}
isZeroable={isCall}
label={
estimatedMg && (isCall ? !withEstimate : true)
? t<string>('max gas allowed (M, {{estimatedMg}} estimated)', { replace: { estimatedMg: estimatedMg.toString() } })
: t<string>('max gas allowed (M)')
}
labelExtra={(estimatedWeight || isCall) && (
<Toggle
<div className={className}>
{isWeightV2
? <>
<InputNumber
defaultValue={estimatedMgRefTime && isDisabled ? estimatedMgRefTime.toString() : undefined}
isDisabled={isDisabled}
isError={!isValid}
isZeroable={isCall}
label={
estimatedMgRefTime && (isCall ? !withEstimate : true)
? t<string>('max RefTime allowed (M, {{estimatedRefTime}} estimated)', { replace: { estimatedMgRefTime: estimatedMgRefTime.toString() } })
: t<string>('max RefTime allowed (M)')
}
onChange={isDisabled ? undefined : setMegaRefTime}
value={isDisabled ? undefined : ((isCall && withEstimate) ? BN_ZERO : megaRefTime)}
>
{(estimatedWeightV2 || isCall) && (
<Toggle
label={
isCall
? t<string>('max read gas')
: t<string>('use estimated gas')
}
onChange={setWithEstimate}
value={withEstimate}
/>
)}
</InputNumber>
<InputNumber
defaultValue={estimatedProofSize && isDisabled ? estimatedProofSize.toString() : undefined}
isDisabled={isDisabled}
isError={!isValid}
isZeroable={isCall}
label={
isCall
? t<string>('max read gas')
: t<string>('use estimated gas')
estimatedProofSize && (isCall ? !withEstimate : true)
? t<string>('max ProofSize allowed ({{estimatedProofSize}} estimated)', { replace: { estimatedProofSize: estimatedProofSize.toString() } })
: t<string>('max ProofSize allowed')
}
onChange={setWithEstimate}
value={withEstimate}
onChange={isDisabled ? undefined : setProofSize}
value={isDisabled ? undefined : ((isCall && withEstimate) ? BN_ZERO : proofSize)}
/>
)}
onChange={isDisabled ? undefined : setMegaGas}
value={isDisabled ? undefined : ((isCall && withEstimate) ? BN_ZERO : megaGas)}
/>
<div className='contracts--InputMegaGas-meter'>
{t<string>('{{executionTime}}s execution time', { replace: { executionTime: executionTime.toFixed(3) } })}{', '}
{t<string>('{{percentage}}% of block weight', { replace: { percentage: percentage.toFixed(2) } })}
</div>
</StyledDiv>
<div className='contracts--Input-meter'>
{t<string>('{{executionTime}}s execution time', { replace: { executionTime: executionTime.toFixed(3) } })}{', '}
{t<string>('{{percentage}}% of block weight', { replace: { percentage: percentage.toFixed(2) } })}
</div>
</>
: <>
<InputNumber
defaultValue={estimatedMg && isDisabled ? estimatedMg.toString() : undefined}
isDisabled={isDisabled}
isError={!isValid}
isZeroable={isCall}
label={
estimatedMg && (isCall ? !withEstimate : true)
? t<string>('max gas allowed (M, {{estimatedMg}} estimated)', { replace: { estimatedMg: estimatedMg.toString() } })
: t<string>('max gas allowed (M)')
}
onChange={isDisabled ? undefined : setMegaGas}
value={isDisabled ? undefined : ((isCall && withEstimate) ? BN_ZERO : megaGas)}
>
{(estimatedWeight || isCall) && (
<Toggle
label={
isCall
? t<string>('max read gas')
: t<string>('use estimated gas')
}
onChange={setWithEstimate}
value={withEstimate}
/>
)}
</InputNumber>
<div className='contracts--Input-meter'>
{t<string>('{{executionTime}}s execution time', { replace: { executionTime: executionTime.toFixed(3) } })}{', '}
{t<string>('{{percentage}}% of block weight', { replace: { percentage: percentage.toFixed(2) } })}
</div>
</>}
</div>
);
}

const StyledDiv = styled.div`
.contracts--InputMegaGas-meter {
text-align: right;
}
`;

export default React.memo(InputMegaGas);
7 changes: 7 additions & 0 deletions packages/page-contracts/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import type { Abi } from '@polkadot/api-contract';
import type { WeightV2 } from '@polkadot/types/interfaces';
import type { BN } from '@polkadot/util';

export interface CodeJson {
Expand Down Expand Up @@ -29,9 +30,15 @@ export interface UseWeight {
executionTime: number;
isEmpty: boolean;
isValid: boolean;
isWeightV2: boolean;
megaGas: BN;
megaRefTime: BN;
proofSize: BN;
percentage: number;
setIsEmpty: React.Dispatch<boolean>
setMegaGas: React.Dispatch<BN | undefined>;
setMegaRefTime: React.Dispatch<BN | undefined>;
setProofSize: React.Dispatch<BN | undefined>;
weight: BN;
weightV2: WeightV2;
}
Loading

0 comments on commit aeb17bf

Please sign in to comment.