support manta author lookup (#5561)
* support manta author lookup * handle scenarios where queuedKeys is not of the expected type * add catchError to imports * should it be square? * resolve combineLatest deprecation issue * type safe nimbus author mappings * precise var names * remove reference to deprecated combineLatest * stay simple, that's what works * implicit type for session.validators we don't want to change this aspect of the implementation * clearer comments on the code paths * explicit variable names
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
import type { Observable } from 'rxjs';
|
||||
import type { QueryableStorage } from '@polkadot/api-base/types';
|
||||
import type { Compact, Vec } from '@polkadot/types';
|
||||
import type { AccountId, BlockNumber, Header } from '@polkadot/types/interfaces';
|
||||
import type { AccountId, Address, BlockNumber, Header } from '@polkadot/types/interfaces';
|
||||
import type { Codec, IOption } from '@polkadot/types/types';
|
||||
import type { DeriveApi } from '../types.js';
|
||||
|
||||
@@ -24,23 +24,36 @@ export function createBlockNumberDerive <T extends { number: Compact<BlockNumber
|
||||
}
|
||||
|
||||
export function getAuthorDetails (header: Header, queryAt: QueryableStorage<'rxjs'>): Observable<[Header, Vec<AccountId> | null, AccountId | null]> {
|
||||
// this is Moonbeam specific
|
||||
if (queryAt.authorMapping && queryAt.authorMapping.mappingWithDeposit) {
|
||||
const mapId = header.digest.logs[0] && (
|
||||
(header.digest.logs[0].isConsensus && header.digest.logs[0].asConsensus[1]) ||
|
||||
(header.digest.logs[0].isPreRuntime && header.digest.logs[0].asPreRuntime[1])
|
||||
);
|
||||
const validators = queryAt.session
|
||||
? queryAt.session.validators()
|
||||
: of(null);
|
||||
|
||||
if (mapId) {
|
||||
// nimbus consensus stores the session key of the block author in header logs
|
||||
const { logs: [log] } = header.digest;
|
||||
const loggedAuthor = (log && (
|
||||
(log.isConsensus && log.asConsensus[0].isNimbus && log.asConsensus[1]) ||
|
||||
(log.isPreRuntime && log.asPreRuntime[0].isNimbus && log.asPreRuntime[1])
|
||||
));
|
||||
|
||||
if (loggedAuthor) {
|
||||
// use the author mapping pallet, if available (ie: moonbeam, moonriver), to map session (nimbus) key to author (collator/validator) key
|
||||
if (queryAt.authorMapping && queryAt.authorMapping.mappingWithDeposit) {
|
||||
return combineLatest([
|
||||
of(header),
|
||||
queryAt.session
|
||||
? queryAt.session.validators()
|
||||
: of(null),
|
||||
queryAt.authorMapping.mappingWithDeposit<IOption<{ account: AccountId } & Codec>>(mapId).pipe(
|
||||
map((opt) =>
|
||||
opt.unwrapOr({ account: null }).account
|
||||
)
|
||||
validators,
|
||||
queryAt.authorMapping.mappingWithDeposit<IOption<{ account: AccountId } & Codec>>(loggedAuthor)
|
||||
.pipe(map((opt) => opt.unwrapOr({ account: null }).account))
|
||||
]);
|
||||
}
|
||||
|
||||
// fall back to session pallet, if available (ie: manta, calamari), to map session (nimbus) key to author (collator/validator) key
|
||||
if (queryAt.session && queryAt.session.queuedKeys) {
|
||||
return combineLatest([
|
||||
of(header),
|
||||
validators,
|
||||
queryAt.session.queuedKeys<[AccountId, { nimbus: Address }][]>().pipe(
|
||||
map((queuedKeys) => queuedKeys.find((sessionKey) => sessionKey[1].nimbus.toHex() === loggedAuthor.toHex())),
|
||||
map((sessionKey) => (sessionKey) ? sessionKey[0] : null)
|
||||
)
|
||||
]);
|
||||
}
|
||||
@@ -49,9 +62,7 @@ export function getAuthorDetails (header: Header, queryAt: QueryableStorage<'rxj
|
||||
// normal operation, non-mapping
|
||||
return combineLatest([
|
||||
of(header),
|
||||
queryAt.session
|
||||
? queryAt.session.validators()
|
||||
: of(null),
|
||||
validators,
|
||||
of(null)
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/// <reference types="@polkadot/dev-test/globals.d.ts" />
|
||||
|
||||
import { TypeRegistry } from '../create/index.js';
|
||||
import { CID_AURA, GenericConsensusEngineId as ConsensusEngineId } from './ConsensusEngineId.js';
|
||||
import { CID_AURA, CID_NMBS, GenericConsensusEngineId as ConsensusEngineId } from './ConsensusEngineId.js';
|
||||
|
||||
describe('ConsensusEngineId', (): void => {
|
||||
const registry = new TypeRegistry();
|
||||
@@ -16,4 +16,8 @@ describe('ConsensusEngineId', (): void => {
|
||||
it('reverses an id to string for babe', (): void => {
|
||||
expect(new ConsensusEngineId(registry, 'BABE').toString()).toEqual('BABE');
|
||||
});
|
||||
|
||||
it('creates a valid id for nimbus', (): void => {
|
||||
expect(new ConsensusEngineId(registry, 'nmbs').toU8a()).toEqual(CID_NMBS);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ export const CID_AURA = stringToU8a('aura');
|
||||
export const CID_BABE = stringToU8a('BABE');
|
||||
export const CID_GRPA = stringToU8a('FRNK');
|
||||
export const CID_POW = stringToU8a('pow_');
|
||||
export const CID_NMBS = stringToU8a('nmbs');
|
||||
|
||||
function getAuraAuthor (registry: Registry, bytes: Bytes, sessionValidators: AccountId[]): AccountId {
|
||||
return sessionValidators[
|
||||
@@ -77,6 +78,13 @@ export class GenericConsensusEngineId extends U8aFixed {
|
||||
return this.eq(CID_POW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description `true` is the engine matches nimbus
|
||||
*/
|
||||
public get isNimbus (): boolean {
|
||||
return this.eq(CID_NMBS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description From the input bytes, decode into an author
|
||||
*/
|
||||
@@ -89,8 +97,8 @@ export class GenericConsensusEngineId extends U8aFixed {
|
||||
}
|
||||
}
|
||||
|
||||
// For pow & Moonbeam, the bytes are the actual author
|
||||
if (this.isPow || bytes.length === 20) {
|
||||
// For pow & Nimbus, the bytes are the actual author
|
||||
if (this.isPow || this.isNimbus) {
|
||||
return getBytesAsAuthor(this.registry, bytes);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user