Skip to content

Commit

Permalink
Drop Metadata V0-V8 (polkadot-js#2634)
Browse files Browse the repository at this point in the history
* Drop MetadatV0

* Apply suggestions from code review

* Restore asV1

* Remove V0 comment

* Handle DoNotConstruct in enum

* No imports from DoNotConstruct

* Merge & re-generate

* Attempt empty construction

* Drop Metadata from 0-4

* CHANGELOG

* assert(5)

* BE vs LE

* Metadataall to no-construction

* Empty U8a create

* Remove old comment

* Santize handling

* Update CHANGELOG.md

* Drop support for Metadata < 9

* Remove old pre-9 definitions

* Update CHANGELOG.md

* CHANGELOG

* Remove v8-era tests

* v8 tests
  • Loading branch information
jacogr authored Sep 25, 2020
1 parent dff7243 commit 5ce3524
Show file tree
Hide file tree
Showing 56 changed files with 170 additions and 35,158 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

## 1.35.0-beta.x

- **Important** Metadata versions before v9 is not supported anymore. v4 was the first version to go with the Substrate 1.0 while Kusama itself starts at v9 as the earliest version. This means that Substrate 1.x chains that have not had any upgrades are not supported in this version of the API anymore.
- **Breaking change** The `RefCount` type (used by `query.system.accounts`) has been changed to a `u32`. On older chains supply the `RefCount: 'RefCountTo259'` override
- **Breaking change** Support for the old-style linked-map retrievals have been dropped, only `.keys()/.entries()` are available now for map iteration. Al known live chains have been upgraded to versions that don't have linked lists.
- **Breaking change** Support for the old-style linked-map retrievals via `query.<module>.map()` have been dropped, only the existing `.keys()/.entries()` are available for map iteration.

Changes:

- Drop support for Substrate 1.0 metadata versions 0-4
- Adjust `RefCount` type as per substrate 2.0
- Add bounty type definitions from treasury
- Add support for `grandpa_proveFinality` RPC
Expand Down
5 changes: 1 addition & 4 deletions packages/api/src/base/Init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Observable, Subscription, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Metadata, Text, TypeRegistry } from '@polkadot/types';
import { LATEST_EXTRINSIC_VERSION } from '@polkadot/types/extrinsic/Extrinsic';
import { getMetadataTypes, getSpecAlias, getSpecTypes, getUpgradeVersion } from '@polkadot/types-known';
import { getSpecAlias, getSpecTypes, getUpgradeVersion } from '@polkadot/types-known';
import { BN_ZERO, assert, logger, u8aEq, u8aToU8a } from '@polkadot/util';
import { cryptoWaitReady } from '@polkadot/util-crypto';

Expand Down Expand Up @@ -264,9 +264,6 @@ export default abstract class Init<ApiType extends ApiTypes> extends Decorate<Ap
}

private async _initFromMeta (metadata: Metadata): Promise<boolean> {
// inject types based on metadata, if applicable
this.registerTypes(getMetadataTypes(this.registry, metadata.version));

const metaExtrinsic = metadata.asLatest.extrinsic;

// only inject if we are not a clone (global init)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,150 +2,13 @@
// SPDX-License-Identifier: Apache-2.0

import { Text, TypeRegistry } from '@polkadot/types';
import { StorageEntry } from '@polkadot/types/primitive/StorageKey';
import { assert, stringToU8a, u8aConcat, u8aToHex } from '@polkadot/util';
import { u8aToHex } from '@polkadot/util';

import createFunction from './createFunction';

describe('createFunction', (): void => {
const registry = new TypeRegistry();

it('should create timestamp.now correctly', (): void => {
expect(
createFunction(registry, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
meta: { type: {} } as any,
method: 'Now',
prefix: 'Timestamp',
section: 'timestamp'
}, { metaVersion: 8 })()
).toEqual(
Uint8Array.from([64, 14, 73, 68, 207, 217, 141, 111, 76, 195, 116, 209, 111, 90, 78, 63, 156]) // Length-prefixed
);
});

it('allows overrides on key (keeping name)', (): void => {
expect(
createFunction(
registry,
{
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
meta: { type: {} } as any,
method: 'authorityCount',
prefix: 'Substrate',
section: 'substrate'
},
{
key: ':auth:len',
metaVersion: 8,
skipHashing: true
}
).method
).toEqual('authorityCount');
});

it('allows overrides on key (unhashed)', (): void => {
const key = ':auth:len';

expect(
createFunction(
registry,
{
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
meta: { type: {} } as any,
method: 'authorityCount',
prefix: 'Substrate',
section: 'substrate'
},
{
key,
metaVersion: 8,
skipHashing: true
}
)()
).toEqual(
u8aConcat(
Uint8Array.from([key.length << 2]),
stringToU8a(':auth:len')
)
);
});

describe('the created double map function', (): void => {
let storageFn: StorageEntry;

beforeAll((): void => {
storageFn = createFunction(registry, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
meta: {
name: 'metaName',
type: {
asDoubleMap: {
hasher: registry.createType('StorageHasher', 'Blake2_256'),
key1: new Text(registry, 'AccountId'),
key2: new Text(registry, 'AccountId'),
key2Hasher: registry.createType('StorageHasher', 'Twox128'),
value: new Text(registry, 'Balance')
},
isDoubleMap: true
}
} as any,
method: 'FreeBalance',
prefix: 'GenericAsset',
section: 'genericAsset'
}, { metaVersion: 8 });
});

it('should return correct key', (): void => {
const result = storageFn(['5DXUeE5N5LtkW97F2PzqYPyqNkxqSWESdGSPTX6AvkUAhwKP', '5DXUeE5N5LtkW97F2PzqYPyqNkxqSWESdGSPTX6AvkUAhwKP']);

expect(u8aToHex(result)).toEqual('0xc000fa40e72d7173e69ee54b980345ea01cb81e64258502e0247af4303dee91ec0aec2ecd3a60ab080cff7b52a8f6d543b');
});

it('needs two arguments', (): void => {
expect(
(): Uint8Array => storageFn(['5DXUeE5N5LtkW97F2PzqYPyqNkxqSWESdGSPTX6AvkUAhwKP'])
).toThrow(/requires two arguments/);
});

it('accepts an optional parameter for key construction', (): void => {
const iterKey = storageFn.iterKey;

assert(iterKey, 'storageFn.iterKey is undefined');

const result = iterKey('5DXUeE5N5LtkW97F2PzqYPyqNkxqSWESdGSPTX6AvkUAhwKP');

expect(u8aToHex(result)).toEqual('0x223416315e3dddca3b5a47fd0ac8e4916482b9ade7bc6657aaca787ba1add3b4c4303117deb55aad9858c8a873273280f78d172b398d5e77e43a2db5e42163e9');
expect(u8aToHex(iterKey())).toEqual('0x223416315e3dddca3b5a47fd0ac8e4916482b9ade7bc6657aaca787ba1add3b4');
});
});

it('allows creates double map function with a Null type key', (): void => {
const storageFn = createFunction(registry, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
meta: {
type: {
asDoubleMap: {
hasher: registry.createType('StorageHasher', 'Blake2_256'),
key1: new Text(registry, 'Null'),
key2: new Text(registry, 'Hash'),
key2Hasher: registry.createType('StorageHasher', 'Blake2_256'),
value: new Text(registry, 'Vec<(BlockNumber,EventIndex)>')
},
isDoubleMap: true
}
} as any,
method: 'EventTopics',
prefix: 'System',
section: 'system'
}, { metaVersion: 8 });

// the value of the Null type key does not effect the result
expect(u8aToHex(storageFn(['any', [1, 2, 3]]))).toEqual(u8aToHex(storageFn([[1, 2, 3], [1, 2, 3]])));
// the value of the not Null type key does effect the result
expect(u8aToHex(storageFn(['any', [1, 2, 3]]))).not.toEqual(u8aToHex(storageFn(['any', [1, 2, 3, 4]])));
});

it('allows creating of known DoubleMap keys (with Bytes)', (): void => {
const storageFn = createFunction(registry, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import BN from 'bn.js';
import { Compact, Raw } from '@polkadot/types/codec';
import { createTypeUnsafe } from '@polkadot/types/create';
import StorageKey, { StorageEntry } from '@polkadot/types/primitive/StorageKey';
import { assert, compactStripLength, isNull, isUndefined, stringLowerFirst, stringToU8a, u8aConcat } from '@polkadot/util';
import { assert, compactStripLength, isNull, isUndefined, stringLowerFirst, u8aConcat } from '@polkadot/util';
import { xxhashAsU8a } from '@polkadot/util-crypto';

import getHasher, { HasherFunction } from './getHasher';
Expand Down Expand Up @@ -68,7 +68,7 @@ function createPrefixedKey ({ method, prefix }: CreateItemFn): Uint8Array {

// create a key for a DoubleMap type
/** @internal */
function createKeyDoubleMap (registry: Registry, itemFn: CreateItemFn, stringKey: string, args: [CreateArgType, CreateArgType], [hasher1, hasher2]: [HasherFunction, HasherFunction?], metaVersion: number): Uint8Array {
function createKeyDoubleMap (registry: Registry, itemFn: CreateItemFn, stringKey: string, args: [CreateArgType, CreateArgType], [hasher1, hasher2]: [HasherFunction, HasherFunction?]): Uint8Array {
const { meta: { name, type } } = itemFn;

// since we are passing an almost-unknown through, trust, but verify
Expand All @@ -83,23 +83,16 @@ function createKeyDoubleMap (registry: Registry, itemFn: CreateItemFn, stringKey
const val2 = createTypeUnsafe(registry, map.key2.toString(), [key2]).toU8a();

// as per createKey, always add the length prefix (underlying it is Bytes)
return Compact.addLengthPrefix(
metaVersion <= 8
? u8aConcat(
hasher1(u8aConcat(stringToU8a(stringKey), val1)),
hasher2(val2)
)
: u8aConcat(
createPrefixedKey(itemFn),
hasher1(val1),
hasher2(val2)
)
);
return Compact.addLengthPrefix(u8aConcat(
createPrefixedKey(itemFn),
hasher1(val1),
hasher2(val2)
));
}

// create a key for either a map or a plain value
/** @internal */
function createKey (registry: Registry, itemFn: CreateItemFn, stringKey: string, arg: CreateArgType, hasher: (value: Uint8Array) => Uint8Array, metaVersion: number): Uint8Array {
function createKey (registry: Registry, itemFn: CreateItemFn, stringKey: string, arg: CreateArgType, hasher: (value: Uint8Array) => Uint8Array): Uint8Array {
const { meta: { name, type } } = itemFn;
let param: Uint8Array = EMPTY_U8A;

Expand All @@ -112,11 +105,12 @@ function createKey (registry: Registry, itemFn: CreateItemFn, stringKey: string,
}

// StorageKey is a Bytes, so is length-prefixed
return Compact.addLengthPrefix(
metaVersion <= 8
? hasher(u8aConcat(stringToU8a(stringKey), param))
: u8aConcat(createPrefixedKey(itemFn), param.length ? hasher(param) : EMPTY_U8A)
);
return Compact.addLengthPrefix(u8aConcat(
createPrefixedKey(itemFn),
param.length
? hasher(param)
: EMPTY_U8A
));
}

// attach the metadata to expand to a StorageFunction
Expand Down Expand Up @@ -150,7 +144,7 @@ function extendHeadMeta (registry: Registry, { meta: { documentation, name, type
fallback: registry.createType('Bytes', createTypeUnsafe(registry, outputType).toHex()),
modifier: registry.createType('StorageEntryModifierLatest', 1), // required
name,
type: registry.createType('StorageEntryTypeLatest', registry.createType('PlainTypeLatest', type.isMap ? type.asMap.key : type.asDoubleMap.key1), 0)
type: registry.createType('StorageEntryTypeLatest', registry.createType('Type', type.isMap ? type.asMap.key : type.asDoubleMap.key1), 0)
});

const prefixKey = registry.createType('StorageKey', iterFn, { method, section });
Expand Down Expand Up @@ -195,8 +189,8 @@ export default function createFunction (registry: Registry, itemFn: CreateItemFn
// For doublemap queries the params is passed in as an tuple, [key1, key2]
const _storageFn = (arg?: CreateArgType | [CreateArgType?, CreateArgType?]): Uint8Array =>
type.isDoubleMap
? createKeyDoubleMap(registry, itemFn, stringKey, arg as [CreateArgType, CreateArgType], [hasher, key2Hasher], options.metaVersion)
: createKey(registry, itemFn, stringKey, arg as CreateArgType, options.skipHashing ? NULL_HASHER : hasher, options.metaVersion);
? createKeyDoubleMap(registry, itemFn, stringKey, arg as [CreateArgType, CreateArgType], [hasher, key2Hasher])
: createKey(registry, itemFn, stringKey, arg as CreateArgType, options.skipHashing ? NULL_HASHER : hasher);

const storageFn = expandWithMeta(itemFn, _storageFn as StorageEntry);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { u8aToHex } from '@polkadot/util';

import Metadata from '../../../Metadata';
import rpcMetadata from '../../../Metadata/static';
import rpcMetadataV8 from '../../../Metadata/v8/static';
import Decorated from '../../Decorated';

const keyring = testingPairs({ type: 'ed25519' });
Expand Down Expand Up @@ -39,24 +38,4 @@ describe('fromMetadata', (): void => {
);
});
});

describe('V8', (): void => {
const registry = new TypeRegistry();
const metadata = new Metadata(registry, rpcMetadataV8);

registry.setMetadata(metadata);

const decorated = new Decorated(registry, metadata);

it('should return the correct length-prefixed storage key', (): void => {
expect(
u8aToHex(
decorated.query.balances.freeBalance(keyring.alice.address)
)
).toEqual(
// old storage key format
'0x807f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587bb'
);
});
});
});

This file was deleted.

26 changes: 18 additions & 8 deletions packages/metadata/src/Metadata/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@

import { Registry } from '@polkadot/types/types';

import { isHex, hexToU8a } from '@polkadot/util';
import { isString, u8aConcat, u8aToU8a } from '@polkadot/util';

import MetadataVersioned from './MetadataVersioned';

const VERSION_IDX = 4; // magic u32 preceding
// magic u32 preceding the version id
const VERSION_IDX = 4;

// first we try and parse using the versioned structure, if this does fail,
// we adjust with the magic number and a manual version and re-try. As soon as
// we remove support for V0, we will just do a new here
function decodeMetadata (registry: Registry, _value: Uint8Array | string = new Uint8Array()): MetadataVersioned {
const value = isHex(_value)
? hexToU8a(_value)
// magic + lowest supported version
const EMPTY_METADATA = u8aConcat(new Uint8Array([0x6d, 0x65, 0x74, 0x61, 9]));
const EMPTY_U8A = new Uint8Array();

function sanitizeInput (_value: Uint8Array | string = EMPTY_U8A): Uint8Array {
if (isString(_value)) {
return sanitizeInput(u8aToU8a(_value));
}

return _value.length === 0
? EMPTY_METADATA
: _value;
}

function decodeMetadata (registry: Registry, _value?: Uint8Array | string): MetadataVersioned {
const value = sanitizeInput(_value);
const version = value[VERSION_IDX];

try {
Expand Down
Loading

0 comments on commit 5ce3524

Please sign in to comment.