Parachains registration (#4318)

* Parachains registration

* Registrar dialog
This commit is contained in:
Jaco Greeff 2021-01-04 14:46:14 +01:00 committed by GitHub
parent 26f592cf5e
commit c5bf0de631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 195 additions and 15 deletions

View File

@ -0,0 +1,38 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import { Button } from '@polkadot/react-components';
import { useApi, useToggle } from '@polkadot/react-hooks';
import Register from '../modals/Register';
import { useTranslation } from '../translate';
interface Props {
canRegister?: boolean;
}
function Actions ({ canRegister }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [showRegister, toggleRegister] = useToggle();
return (
<>
<Button.Group>
<Button
icon='plus'
isDisabled={!canRegister || !api.tx.registrar?.registerParathread}
label={t<string>('Register')}
onClick={toggleRegister}
/>
</Button.Group>
{showRegister && (
<Register onClose={toggleRegister} />
)}
</>
);
}
export default React.memo(Actions);

View File

@ -12,6 +12,7 @@ import { useTranslation } from '../translate';
import Parachain from './Parachain';
interface Props {
canRegister?: boolean;
ids?: ParaId[];
}

View File

@ -11,11 +11,12 @@ import { formatNumber, isNumber } from '@polkadot/util';
import { useTranslation } from '../translate';
interface Props {
canRegister?: boolean;
parachainCount?: number;
upcomingCount?: number;
}
function Summary ({ parachainCount, upcomingCount }: Props): React.ReactElement<Props> {
function Summary ({ canRegister, parachainCount, upcomingCount }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
@ -39,6 +40,11 @@ function Summary ({ parachainCount, upcomingCount }: Props): React.ReactElement<
</CardSummary>
)}
</section>
<section>
<CardSummary label={t<string>('registration')}>
{canRegister ? t<string>('open') : t<string>('closed')}
</CardSummary>
</section>
<section>
<CardSummary
className='media--800'

View File

@ -1,12 +1,14 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { bool } from '@polkadot/types';
import type { ParaId } from '@polkadot/types/interfaces';
import React from 'react';
import { useApi, useCall } from '@polkadot/react-hooks';
import Actions from './Actions';
import Parachains from './Parachains';
import Summary from './Summary';
import Upcoming from './Upcoming';
@ -15,20 +17,30 @@ interface Props {
className?: string;
}
const transformRegister = {
transform: (value: bool): boolean => value.isTrue
};
function Overview (): React.ReactElement<Props> {
const { api } = useApi();
const paraIds = useCall<ParaId[]>(api.query.paras?.parachains);
const upcomingIds = useCall<ParaId[]>(api.query.paras?.upcomingParas);
const canRegister = useCall<boolean>(api.query.registrar?.parathreadsRegistrationEnabled, [], transformRegister);
return (
<>
<Summary
canRegister={canRegister}
parachainCount={paraIds?.length}
upcomingCount={upcomingIds?.length}
/>
<Actions canRegister={canRegister} />
{api.query.paras && (
<>
<Parachains ids={paraIds} />
<Parachains
canRegister={canRegister}
ids={paraIds}
/>
<Upcoming ids={upcomingIds} />
</>
)}

View File

@ -0,0 +1,118 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React, { useCallback, useState } from 'react';
import { InputAddress, InputFile, InputNumber, InputWasm, Modal, TxButton } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
import { BN_ZERO, compactAddLength } from '@polkadot/util';
import { useTranslation } from '../translate';
interface Props {
className?: string;
onClose: () => void;
}
interface CodeState {
isWasmValid: boolean;
wasm: Uint8Array | null;
}
function Register ({ className, onClose }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [accountId, setAccountId] = useState<string | null>(null);
const [paraId, setParaId] = useState(BN_ZERO);
const [{ isWasmValid, wasm }, setWasm] = useState<CodeState>({ isWasmValid: false, wasm: null });
const [genesisState, setGenesisState] = useState<Uint8Array | null>(null);
const _setGenesisState = useCallback(
(data: Uint8Array) => setGenesisState(compactAddLength(data)),
[]
);
const _setWasm = useCallback(
(wasm: Uint8Array, isWasmValid: boolean) => setWasm({ isWasmValid, wasm }),
[]
);
console.error(genesisState);
return (
<Modal
className={className}
header={t<string>('Register parachain')}
>
<Modal.Content>
<Modal.Columns>
<Modal.Column>
<InputAddress
label={t<string>('register from')}
onChange={setAccountId}
type='account'
value={accountId}
/>
</Modal.Column>
<Modal.Column>
<p>{t<string>('This account will be associated with the parachain and pay the deposit.')}</p>
</Modal.Column>
</Modal.Columns>
<Modal.Columns>
<Modal.Column>
<InputNumber
label={t<string>('parachain id')}
onChange={setParaId}
/>
</Modal.Column>
<Modal.Column>
<p>{t<string>('The id of this parachain as known on the network')}</p>
</Modal.Column>
</Modal.Columns>
<Modal.Columns>
<Modal.Column>
<InputWasm
help={t<string>('The compiled runtime WASM for the parachain you wish to register.')}
isError={!isWasmValid}
label={t<string>('code')}
onChange={_setWasm}
placeholder={
wasm && !isWasmValid
? t<string>('The code is not recognized as being in valid WASM format')
: null
}
/>
</Modal.Column>
<Modal.Column>
<p>{t<string>('The WASM validation function for this parachain.')}</p>
</Modal.Column>
</Modal.Columns>
<Modal.Columns>
<Modal.Column>
<InputFile
help={t<string>('The genesis state for the parachain.')}
isError={!genesisState}
label={t<string>('initial state')}
onChange={_setGenesisState}
/>
</Modal.Column>
<Modal.Column>
<p>{t<string>('The genesis state for this parachain.')}</p>
</Modal.Column>
</Modal.Columns>
</Modal.Content>
<Modal.Actions onCancel={onClose}>
<TxButton
accountId={accountId}
icon='plus'
isDisabled={!isWasmValid || !genesisState}
onStart={onClose}
params={[paraId, genesisState, wasm]}
tx={api.tx.registrar.registerParathread}
/>
</Modal.Actions>
</Modal>
);
}
export default React.memo(Register);

View File

@ -12,10 +12,7 @@ import { formatNumber, hexToU8a, isHex, u8aToString } from '@polkadot/util';
import Labelled from './Labelled';
import { useTranslation } from './translate';
export interface InputFileProps {
// Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept
// i.e. MIME types: 'application/json, text/plain', or '.json, .txt'
accept?: string;
export interface InputFilePropsBase {
className?: string;
clearContent?: boolean;
help?: React.ReactNode;
@ -23,12 +20,18 @@ export interface InputFileProps {
isError?: boolean;
isFull?: boolean;
label: React.ReactNode;
onChange?: (contents: Uint8Array, name: string) => void;
placeholder?: React.ReactNode | null;
withEllipsis?: boolean;
withLabel?: boolean;
}
export interface InputFileProps extends InputFilePropsBase {
// Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept
// i.e. MIME types: 'application/json, text/plain', or '.json, .txt'
accept?: string;
onChange?: (contents: Uint8Array, name: string) => void;
}
interface FileState {
name: string;
size: number;

View File

@ -1,24 +1,26 @@
// Copyright 2017-2021 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { InputFilePropsBase } from './InputFile';
import React, { useCallback } from 'react';
import { compactAddLength, isWasm } from '@polkadot/util';
import InputFile, { InputFileProps } from './InputFile';
import InputFile from './InputFile';
interface Props extends Omit<InputFileProps, 'accept'> {
isValidRef: React.MutableRefObject<boolean>;
onChange: (contents: Uint8Array, name?: string) => void;
interface Props extends InputFilePropsBase {
onChange: (contents: Uint8Array, isValid: boolean, name?: string) => void;
}
function InputWasm ({ isValidRef, onChange, ...props }: Props): React.ReactElement<Props> {
function InputWasm ({ onChange, ...props }: Props): React.ReactElement<Props> {
const _onChange = useCallback(
(wasm: Uint8Array, name: string): void => {
isValidRef.current = isWasm(wasm);
onChange(compactAddLength(wasm), name);
const isValid = isWasm(wasm);
onChange(compactAddLength(wasm), isValid, name);
},
[isValidRef, onChange]
[onChange]
);
return (