Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WeightsV2 support for contracts pallet #8538

Merged
merged 7 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/apps/public/locales/en/app-contracts.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"Save": "Save",
"The code is not recognized as being in valid WASM format": "The code is not recognized as being in valid WASM format",
"The codeHash is not a valid hex hash": "The codeHash is not a valid hex hash",
"The maximum amount of gas to use for this contract call. If the call requires more, it will fail.": "The maximum amount of gas to use for this contract call. If the call requires more, it will fail.",
"The value is not in a valid address format": "The value is not in a valid address format",
"This operation does not impact the associated on-chain code or any of its contracts.": "This operation does not impact the associated on-chain code or any of its contracts.",
"This operation does not remove the uploaded code WASM and ABI from the chain, nor any deployed contracts. The forget operation only limits your access to the code on this browser.": "This operation does not remove the uploaded code WASM and ABI from the chain, nor any deployed contracts. The forget operation only limits your access to the code on this browser.",
Expand All @@ -52,6 +53,10 @@
"deployment constructor": "deployment constructor",
"exec": "exec",
"json for either ABI or .contract bundle": "json for either ABI or .contract bundle",
"max ProofSize allowed": "max ProofSize allowed",
"max ProofSize allowed ({{estimatedProofSize}} estimated)": "max ProofSize allowed ({{estimatedProofSize}} estimated)",
"max RefTime allowed (M)": "max RefTime allowed (M)",
"max RefTime allowed (M, {{estimatedRefTime}} estimated)": "max RefTime allowed (M, {{estimatedRefTime}} estimated)",
"max gas allowed (M)": "max gas allowed (M)",
"max gas allowed (M, {{estimatedMg}} estimated)": "max gas allowed (M, {{estimatedMg}} estimated)",
"max read gas": "max read gas",
Expand Down
49 changes: 34 additions & 15 deletions packages/page-contracts/src/Codes/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,42 @@ function Upload ({ onClose }: Props): React.ReactElement {
}, [abiName, setName]);

useEffect((): void => {
let contract: SubmittableExtrinsic<'promise'> | null = null;
let error: string | null = null;

try {
contract = code && contractAbi?.constructors[constructorIndex]?.method && value
? code.tx[contractAbi.constructors[constructorIndex].method]({
gasLimit: weight.weight,
storageDepositLimit: null,
value: contractAbi?.constructors[constructorIndex].isPayable ? value : undefined
}, ...params)
: null;
} catch (e) {
error = (e as Error).message;
async function dryRun () {
let contract: SubmittableExtrinsic<'promise'> | null = null;
let error: string | null = null;

try {
if (code && contractAbi?.constructors[constructorIndex]?.method && value && accountId) {
const dryRunParams: Parameters<typeof api.call.contractsApi.instantiate> =
[
accountId,
contractAbi?.constructors[constructorIndex].isPayable
? api.registry.createType('Balance', value)
: api.registry.createType('Balance', BN_ZERO),
weight.weightV2,
null,
{ Upload: api.registry.createType('Raw', wasm) },
contractAbi?.constructors[constructorIndex]?.toU8a(params),
''
];

const dryRunResult = await api.call.contractsApi.instantiate(...dryRunParams);

contract = code.tx[contractAbi.constructors[constructorIndex].method]({
gasLimit: dryRunResult.gasRequired,
storageDepositLimit: dryRunResult.storageDeposit.isCharge ? dryRunResult.storageDeposit.asCharge : null,
value: contractAbi?.constructors[constructorIndex].isPayable ? value : undefined
}, ...params);
}
} catch (e) {
error = (e as Error).message;
}

setUploadTx(() => [contract, error]);
}

setUploadTx(() => [contract, error]);
}, [code, contractAbi, constructorIndex, value, params, weight]);
dryRun().catch((e) => console.error(e));
}, [accountId, wasm, api, code, contractAbi, constructorIndex, value, params, weight]);

const _onAddWasm = useCallback(
(wasm: Uint8Array, name: string): void => {
Expand Down
88 changes: 71 additions & 17 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 { WeightV2 } from '@polkadot/types/interfaces';
import type { CallResult } from './types.js';

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,18 +49,46 @@ 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 null;
async function dryRun () {
if (accountId && value && message.isMutating) {
const dryRunParams: Parameters<typeof api.call.contractsApi.call> =
[
accountId,
contract.address,
message.isPayable
? api.registry.createType('Balance', value)
: api.registry.createType('Balance', BN_ZERO),
weight.weightV2,
null,
message.toU8a(params)
];

const dryRunResult = await api.call.contractsApi.call(...dryRunParams);

setExecTx((): SubmittableExtrinsic<'promise'> | null => {
try {
return contract.tx[message.method](
{
gasLimit: dryRunResult.gasRequired,
storageDepositLimit: dryRunResult.storageDeposit.isCharge ? dryRunResult.storageDeposit.asCharge : null,
value: message.isPayable ? value : 0
},
...params
);
} catch {
return null;
}
});
}
});
}, [accountId, contract, message, value, weight, params]);
}

dryRun().catch((e) => console.error(e));
}, [api, accountId, contract, message, value, weight, params]);

useEffect((): void => {
if (!accountId || !message || !dbParams || !dbValue) {
Expand All @@ -67,13 +97,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.refTime.toBn()
: null
);
}
})
.catch(() => {
setEstimatedWeight(null);
setEstimatedWeightV2(null);
});
}, [api, accountId, contract, message, dbParams, dbValue, weight.isWeightV2]);

const _onSubmitRpc = useCallback(
(): void => {
Expand All @@ -82,7 +125,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 Expand Up @@ -168,6 +215,13 @@ function Call ({ className = '', contract, messageIndex, onCallResult, onChangeM
)}
<InputMegaGas
estimatedWeight={message.isMutating ? estimatedWeight : MAX_CALL_WEIGHT}
estimatedWeightV2={message.isMutating
? estimatedWeightV2
: api.registry.createType('WeightV2', {
proofSize: new BN(1_000_000),
refTIme: MAX_CALL_WEIGHT
})
}
isCall={!message.isMutating}
weight={weight}
/>
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
Loading