Adjust contracts to pass either V1 or V2 weights (#5254)
* Adjust contracts to pass either V1 or V2 weights * Adjust * Formatting * Adjust * Fix build
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ApiTypes, DecorateMethod } from '@polkadot/api/types';
|
||||
import type { Registry } from '@polkadot/types/types';
|
||||
import type { INumber, Registry } from '@polkadot/types/types';
|
||||
|
||||
import { ApiBase } from '@polkadot/api/base';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
@@ -16,14 +16,9 @@ export abstract class Base<ApiType extends ApiTypes> {
|
||||
|
||||
protected readonly _decorateMethod: DecorateMethod<ApiType>;
|
||||
|
||||
protected readonly _isOldWeight: boolean;
|
||||
|
||||
constructor (api: ApiBase<ApiType>, abi: string | Record<string, unknown> | Abi, decorateMethod: DecorateMethod<ApiType>) {
|
||||
this.abi = abi instanceof Abi
|
||||
? abi
|
||||
: new Abi(abi, api.registry.getChainProperties());
|
||||
this.api = api;
|
||||
|
||||
this._decorateMethod = decorateMethod;
|
||||
|
||||
if (!api || !api.isConnected || !api.tx) {
|
||||
throw new Error('Your API has not been initialized correctly and is not connected to a chain');
|
||||
} else if (!api.tx.contracts || !isFunction(api.tx.contracts.instantiateWithCode) || api.tx.contracts.instantiateWithCode.meta.args.length !== 6) {
|
||||
@@ -31,6 +26,13 @@ export abstract class Base<ApiType extends ApiTypes> {
|
||||
} else if (!api.call.contractsApi || !isFunction(api.call.contractsApi.call)) {
|
||||
throw new Error('Your runtime does not expose the api.call.contractsApi.call runtime interfaces');
|
||||
}
|
||||
|
||||
this.abi = abi instanceof Abi
|
||||
? abi
|
||||
: new Abi(abi, api.registry.getChainProperties());
|
||||
this.api = api;
|
||||
this._decorateMethod = decorateMethod;
|
||||
this._isOldWeight = isFunction(api.registry.createType<INumber>('Weight').toBn);
|
||||
}
|
||||
|
||||
public get registry (): Registry {
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
|
||||
import type { ApiTypes, DecorateMethod } from '@polkadot/api/types';
|
||||
import type { AccountId, EventRecord, Hash } from '@polkadot/types/interfaces';
|
||||
import type { ISubmittableResult } from '@polkadot/types/types';
|
||||
import type { AbiConstructor, BlueprintOptions } from '../types';
|
||||
import type { AbiConstructor, BlueprintOptions, WeightAll } from '../types';
|
||||
import type { MapConstructorExec } from './types';
|
||||
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
@@ -16,7 +16,7 @@ import { Abi } from '../Abi';
|
||||
import { applyOnEvent } from '../util';
|
||||
import { Base } from './Base';
|
||||
import { Contract } from './Contract';
|
||||
import { createBluePrintTx, encodeSalt } from './util';
|
||||
import { convertWeight, createBluePrintTx, encodeSalt } from './util';
|
||||
|
||||
export interface BlueprintConstructor<ApiType extends ApiTypes> {
|
||||
new(api: ApiBase<ApiType>, abi: string | Record<string, unknown> | Abi, codeHash: string | Hash | Uint8Array): Blueprint<ApiType>;
|
||||
@@ -57,13 +57,12 @@ export class Blueprint<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
}
|
||||
|
||||
#deploy = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, salt, storageDepositLimit = null, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic<ApiType, BlueprintSubmittableResult<ApiType>> => {
|
||||
// TODO Cater for new call structure (with old fallback)
|
||||
return (
|
||||
this.api.tx.contracts.instantiateOldWeight ||
|
||||
this.api.tx.contracts.instantiate
|
||||
)(
|
||||
return this.api.tx.contracts.instantiate(
|
||||
value,
|
||||
gasLimit,
|
||||
this._isOldWeight
|
||||
// jiggle v1 weights, metadata points to latest
|
||||
? convertWeight(gasLimit).v1Weight as unknown as WeightAll['v2Weight']
|
||||
: convertWeight(gasLimit).v2Weight,
|
||||
storageDepositLimit,
|
||||
this.codeHash,
|
||||
this.abi.findConstructor(constructorOrId).toU8a(params),
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { ApiTypes, DecorateMethod } from '@polkadot/api/types';
|
||||
import type { AccountId, EventRecord } from '@polkadot/types/interfaces';
|
||||
import type { ISubmittableResult } from '@polkadot/types/types';
|
||||
import type { Codec } from '@polkadot/types-codec/types';
|
||||
import type { AbiConstructor, BlueprintOptions } from '../types';
|
||||
import type { AbiConstructor, BlueprintOptions, WeightAll } from '../types';
|
||||
import type { MapConstructorExec } from './types';
|
||||
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
@@ -18,7 +18,7 @@ import { applyOnEvent } from '../util';
|
||||
import { Base } from './Base';
|
||||
import { Blueprint } from './Blueprint';
|
||||
import { Contract } from './Contract';
|
||||
import { createBluePrintTx, encodeSalt } from './util';
|
||||
import { convertWeight, createBluePrintTx, encodeSalt } from './util';
|
||||
|
||||
export interface CodeConstructor<ApiType extends ApiTypes> {
|
||||
new(api: ApiBase<ApiType>, abi: string | Record<string, unknown> | Abi, wasm: Uint8Array | string | Buffer | null | undefined): Code<ApiType>;
|
||||
@@ -64,13 +64,12 @@ export class Code<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
}
|
||||
|
||||
#instantiate = (constructorOrId: AbiConstructor | string | number, { gasLimit = BN_ZERO, salt, storageDepositLimit = null, value = BN_ZERO }: BlueprintOptions, params: unknown[]): SubmittableExtrinsic<ApiType, CodeSubmittableResult<ApiType>> => {
|
||||
// TODO Cater for new call structure (with old fallback)
|
||||
return (
|
||||
this.api.tx.contracts.instantiateWithCodeOldWeight ||
|
||||
this.api.tx.contracts.instantiateWithCode
|
||||
)(
|
||||
return this.api.tx.contracts.instantiateWithCode(
|
||||
value,
|
||||
gasLimit,
|
||||
this._isOldWeight
|
||||
// jiggle v1 weights, metadata points to latest
|
||||
? convertWeight(gasLimit).v1Weight as unknown as WeightAll['v2Weight']
|
||||
: convertWeight(gasLimit).v2Weight,
|
||||
storageDepositLimit,
|
||||
compactAddLength(this.code),
|
||||
this.abi.findConstructor(constructorOrId).toU8a(params),
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
|
||||
import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
|
||||
import type { ApiTypes, DecorateMethod } from '@polkadot/api/types';
|
||||
import type { Bytes, Compact } from '@polkadot/types';
|
||||
import type { Bytes } from '@polkadot/types';
|
||||
import type { AccountId, ContractExecResult, EventRecord, Weight } from '@polkadot/types/interfaces';
|
||||
import type { ISubmittableResult } from '@polkadot/types/types';
|
||||
import type { AbiMessage, ContractCallOutcome, ContractOptions, DecodedEvent } from '../types';
|
||||
import type { AbiMessage, ContractCallOutcome, ContractOptions, DecodedEvent, WeightAll, WeightV2 } from '../types';
|
||||
import type { ContractCallResult, ContractCallSend, ContractQuery, ContractTx, MapMessageQuery, MapMessageTx } from './types';
|
||||
|
||||
import { map } from 'rxjs';
|
||||
|
||||
import { SubmittableResult } from '@polkadot/api';
|
||||
import { ApiBase } from '@polkadot/api/base';
|
||||
import { BN, BN_HUNDRED, BN_ONE, BN_ZERO, bnToBn, isUndefined, logger } from '@polkadot/util';
|
||||
import { BN, BN_HUNDRED, BN_ONE, BN_ZERO, isUndefined, logger } from '@polkadot/util';
|
||||
|
||||
import { Abi } from '../Abi';
|
||||
import { applyOnEvent } from '../util';
|
||||
import { Base } from './Base';
|
||||
import { withMeta } from './util';
|
||||
import { convertWeight, withMeta } from './util';
|
||||
|
||||
export interface ContractConstructor<ApiType extends ApiTypes> {
|
||||
new(api: ApiBase<ApiType>, abi: string | Record<string, unknown> | Abi, address: string | AccountId): Contract<ApiType>;
|
||||
@@ -85,37 +85,32 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
return this.#tx;
|
||||
}
|
||||
|
||||
#getMaxGas = (): BN => {
|
||||
if (this.api.consts.system.blockWeights) {
|
||||
const maxBlock = (this.api.consts.system.blockWeights as unknown as { maxBlock: { proofSize: Compact<Weight>, refTime: Compact<Weight> } }).maxBlock;
|
||||
#getGas = (_gasLimit: bigint | BN | string | number | WeightV2, isCall = false): WeightAll => {
|
||||
const weight = convertWeight(_gasLimit);
|
||||
|
||||
return maxBlock.proofSize
|
||||
? maxBlock.refTime.unwrap()
|
||||
: maxBlock as unknown as Weight;
|
||||
if (weight.v1Weight.gt(BN_ZERO)) {
|
||||
return weight;
|
||||
}
|
||||
|
||||
return this.api.consts.system.maximumBlockWeight as Weight;
|
||||
};
|
||||
|
||||
#getGas = (_gasLimit: bigint | BN | string | number, isCall = false): BN => {
|
||||
const gasLimit = bnToBn(_gasLimit);
|
||||
|
||||
return gasLimit.lte(BN_ZERO)
|
||||
? isCall
|
||||
return convertWeight(
|
||||
isCall
|
||||
? MAX_CALL_GAS
|
||||
: this.#getMaxGas().muln(64).div(BN_HUNDRED)
|
||||
: gasLimit;
|
||||
: convertWeight(
|
||||
this.api.consts.system.blockWeights
|
||||
? (this.api.consts.system.blockWeights as unknown as { maxBlock: WeightV2 }).maxBlock
|
||||
: this.api.consts.system.maximumBlockWeight as Weight
|
||||
).v1Weight.muln(64).div(BN_HUNDRED)
|
||||
);
|
||||
};
|
||||
|
||||
#exec = (messageOrId: AbiMessage | string | number, { gasLimit = BN_ZERO, storageDepositLimit = null, value = BN_ZERO }: ContractOptions, params: unknown[]): SubmittableExtrinsic<ApiType> => {
|
||||
// TODO Cater for new call structure (with old fallback)
|
||||
return (
|
||||
this.api.tx.contracts.callOldWeight ||
|
||||
this.api.tx.contracts.call
|
||||
)(
|
||||
return this.api.tx.contracts.call(
|
||||
this.address,
|
||||
value,
|
||||
this.#getGas(gasLimit),
|
||||
this._isOldWeight
|
||||
// jiggle v1 weights, metadata points to latest
|
||||
? convertWeight(gasLimit).v1Weight as unknown as WeightAll['v2Weight']
|
||||
: convertWeight(gasLimit).v2Weight,
|
||||
storageDepositLimit,
|
||||
this.abi.findMessage(messageOrId).toU8a(params)
|
||||
).withResultTransform((result: ISubmittableResult) =>
|
||||
@@ -142,22 +137,28 @@ export class Contract<ApiType extends ApiTypes> extends Base<ApiType> {
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
send: this._decorateMethod((origin: string | AccountId | Uint8Array) =>
|
||||
this.api.rx.call.contractsApi
|
||||
.call<ContractExecResult>(origin, this.address, value, this.#getGas(gasLimit, true), storageDepositLimit, message.toU8a(params))
|
||||
.pipe(
|
||||
map(({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }): ContractCallOutcome => ({
|
||||
debugMessage,
|
||||
gasConsumed,
|
||||
gasRequired: gasRequired && !gasRequired.isZero()
|
||||
? gasRequired
|
||||
: gasConsumed,
|
||||
output: result.isOk && message.returnType
|
||||
? this.abi.registry.createTypeUnsafe(message.returnType.lookupName || message.returnType.type, [result.asOk.data.toU8a(true)], { isPedantic: true })
|
||||
: null,
|
||||
result,
|
||||
storageDeposit
|
||||
}))
|
||||
)
|
||||
this.api.rx.call.contractsApi.call<ContractExecResult>(
|
||||
origin,
|
||||
this.address,
|
||||
value,
|
||||
// the runtime interface still used u64 inputs
|
||||
this.#getGas(gasLimit, true).v1Weight,
|
||||
storageDepositLimit,
|
||||
message.toU8a(params)
|
||||
).pipe(
|
||||
map(({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }): ContractCallOutcome => ({
|
||||
debugMessage,
|
||||
gasConsumed,
|
||||
gasRequired: gasRequired && !gasRequired.isZero()
|
||||
? gasRequired
|
||||
: gasConsumed,
|
||||
output: result.isOk && message.returnType
|
||||
? this.abi.registry.createTypeUnsafe(message.returnType.lookupName || message.returnType.type, [result.asOk.data.toU8a(true)], { isPedantic: true })
|
||||
: null,
|
||||
result,
|
||||
storageDeposit
|
||||
}))
|
||||
)
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
import type { SubmittableResult } from '@polkadot/api';
|
||||
import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
|
||||
import type { ApiTypes } from '@polkadot/api/types';
|
||||
import type { AbiConstructor, AbiMessage, BlueprintOptions } from '../types';
|
||||
import type { BN } from '@polkadot/util';
|
||||
import type { AbiConstructor, AbiMessage, BlueprintOptions, WeightAll, WeightV2 } from '../types';
|
||||
import type { BlueprintDeploy, ContractGeneric } from './types';
|
||||
|
||||
import { Bytes } from '@polkadot/types';
|
||||
import { compactAddLength, u8aToU8a } from '@polkadot/util';
|
||||
import { bnToBn, compactAddLength, u8aToU8a } from '@polkadot/util';
|
||||
import { randomAsU8a } from '@polkadot/util-crypto';
|
||||
|
||||
export const EMPTY_SALT = new Uint8Array();
|
||||
@@ -37,3 +38,14 @@ export function encodeSalt (salt: Uint8Array | string | null = randomAsU8a()): U
|
||||
? compactAddLength(u8aToU8a(salt))
|
||||
: EMPTY_SALT;
|
||||
}
|
||||
|
||||
export function convertWeight (orig: WeightV2 | bigint | string | number | BN): WeightAll {
|
||||
const refTime = (orig as WeightV2).proofSize
|
||||
? (orig as WeightV2).refTime.toBn()
|
||||
: bnToBn(orig as BN);
|
||||
|
||||
return {
|
||||
v1Weight: refTime,
|
||||
v2Weight: { refTime }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { ApiBase } from '@polkadot/api/base';
|
||||
import type { ApiTypes } from '@polkadot/api/types';
|
||||
import type { Text, u64 } from '@polkadot/types';
|
||||
import type { ContractExecResultResult, ContractSelector, StorageDeposit } from '@polkadot/types/interfaces';
|
||||
import type { Codec, TypeDef } from '@polkadot/types/types';
|
||||
import type { Codec, ICompact, INumber, TypeDef } from '@polkadot/types/types';
|
||||
import type { BN } from '@polkadot/util';
|
||||
import type { Abi } from '.';
|
||||
|
||||
@@ -73,7 +73,7 @@ export interface DecodedMessage {
|
||||
}
|
||||
|
||||
export interface ContractOptions {
|
||||
gasLimit?: bigint | string | number | BN;
|
||||
gasLimit?: bigint | string | number | BN | WeightV2;
|
||||
storageDepositLimit?: bigint | string | number | BN | null;
|
||||
value?: bigint | BN | string | number;
|
||||
}
|
||||
@@ -81,3 +81,15 @@ export interface ContractOptions {
|
||||
export interface BlueprintOptions extends ContractOptions {
|
||||
salt?: Uint8Array | string | null;
|
||||
}
|
||||
|
||||
export interface WeightV2 {
|
||||
refTime: ICompact<INumber>;
|
||||
proofSize: ICompact<INumber>;
|
||||
}
|
||||
|
||||
export interface WeightAll {
|
||||
v1Weight: BN;
|
||||
v2Weight: {
|
||||
refTime: BN;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user