signAndSend with finalized hash (depending on lag) (#2104)
* signAndSend with finalized hash (depending on drift) * Extract lag calc * mock update * getSigningHeader * api.derive.tx (with submittable cleanups) * Adjust mortal calculations * Cleanup new tx derives * Optimize calcs * Comment cleanups, next-up testing * Adjust mocks * Adjust sig (period is now based on metadata) * Remove extra fn, tested and it works
This commit is contained in:
@@ -21,10 +21,11 @@ import * as society from './society';
|
||||
import * as staking from './staking';
|
||||
import * as technicalCommittee from './technicalCommittee';
|
||||
import * as treasury from './treasury';
|
||||
import * as tx from './tx';
|
||||
|
||||
export * from './type';
|
||||
|
||||
export const derive = { accounts, balances, chain, contracts, council, democracy, elections, imOnline, parachains, session, society, staking, technicalCommittee, treasury };
|
||||
export const derive = { accounts, balances, chain, contracts, council, democracy, elections, imOnline, parachains, session, society, staking, technicalCommittee, treasury, tx };
|
||||
|
||||
type DeriveSection<Section> = {
|
||||
[Method in keyof Section]: Section[Method] extends AnyFunction
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/api-derive authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
export const MAX_FINALITY_LAG = new BN(5);
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2017-2020 @polkadot/api-derive authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { EventRecord, Hash, SignedBlock } from '@polkadot/types/interfaces';
|
||||
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
interface Result {
|
||||
block: SignedBlock;
|
||||
events: EventRecord[];
|
||||
}
|
||||
|
||||
export function events (api: ApiInterfaceRx): (at: Hash) => Observable<Result> {
|
||||
return memo((at: Hash): Observable<Result> =>
|
||||
combineLatest([
|
||||
api.query.system.events.at(at),
|
||||
api.rpc.chain.getBlock(at)
|
||||
]).pipe(
|
||||
map(([events, block]) => ({
|
||||
block,
|
||||
events
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright 2017-2020 @polkadot/api-derive authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
export * from './events';
|
||||
export * from './signingInfo';
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2017-2020 @polkadot/api-derive authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Header, Index } from '@polkadot/types/interfaces';
|
||||
import { AnyNumber, Codec, IExtrinsicEra } from '@polkadot/types/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, combineLatest, of } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { isNumber, isUndefined } from '@polkadot/util';
|
||||
|
||||
interface Result {
|
||||
header: Header | null;
|
||||
mortalLength: number;
|
||||
nonce: Index;
|
||||
}
|
||||
|
||||
// default here to 5 min eras, adjusted based on the actual blocktime
|
||||
const FALLBACK_PERIOD = new BN(6 * 1000);
|
||||
const MAX_FINALITY_LAG = new BN(5);
|
||||
const MORTAL_PERIOD = new BN(5 * 60 * 1000);
|
||||
|
||||
function latestNonce (api: ApiInterfaceRx, address: string): Observable<Index> {
|
||||
return api.derive.balances.account(address).pipe(
|
||||
map(({ accountNonce }): Index => accountNonce)
|
||||
);
|
||||
}
|
||||
|
||||
function signingHeader (api: ApiInterfaceRx): Observable<Header> {
|
||||
return combineLatest([
|
||||
api.rpc.chain.getHeader(),
|
||||
api.rpc.chain.getFinalizedHead().pipe(
|
||||
switchMap((hash) => api.rpc.chain.getHeader(hash))
|
||||
)
|
||||
]).pipe(
|
||||
map(([current, finalized]): Header =>
|
||||
// determine the hash to use, current when lag > max, else finalized
|
||||
current.number.unwrap().sub(finalized.number.unwrap()).gt(MAX_FINALITY_LAG)
|
||||
? current
|
||||
: finalized
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function signingInfo (api: ApiInterfaceRx): (address: string, nonce?: AnyNumber | Codec, era?: IExtrinsicEra | number) => Observable<Result> {
|
||||
// no memo, we want to do this fresh on each run
|
||||
return (address: string, nonce?: AnyNumber | Codec, era?: IExtrinsicEra | number): Observable<Result> =>
|
||||
combineLatest([
|
||||
// retrieve nonce if none was specified
|
||||
isUndefined(nonce)
|
||||
? latestNonce(api, address)
|
||||
: of(api.registry.createType('Index', nonce)),
|
||||
// if no era (create) or era > 0 (mortal), do block retrieval
|
||||
(isUndefined(era) || (isNumber(era) && era > 0))
|
||||
? signingHeader(api)
|
||||
: of(null)
|
||||
]).pipe(
|
||||
map(([nonce, header]) => ({
|
||||
header,
|
||||
nonce,
|
||||
mortalLength: MORTAL_PERIOD
|
||||
.div(api.consts.babe?.expectedBlockTime || api.consts.timestamp?.minimumPeriod.muln(2) || FALLBACK_PERIOD)
|
||||
.add(MAX_FINALITY_LAG)
|
||||
.toNumber()
|
||||
}))
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user