@aztec/sequencer-client 2.0.3 → 2.1.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +7 -4
- package/dest/config.d.ts +2 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -0
- package/dest/publisher/config.d.ts +2 -4
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +7 -10
- package/dest/publisher/index.d.ts +1 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/index.js +1 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts +5 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +8 -1
- package/dest/publisher/sequencer-publisher.d.ts +14 -20
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +53 -58
- package/dest/sequencer/errors.d.ts +11 -0
- package/dest/sequencer/errors.d.ts.map +1 -0
- package/dest/sequencer/errors.js +15 -0
- package/dest/sequencer/metrics.d.ts +5 -17
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +22 -88
- package/dest/sequencer/sequencer.d.ts +4 -3
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +27 -21
- package/dest/sequencer/timetable.d.ts +0 -6
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +2 -9
- package/dest/sequencer/utils.d.ts +10 -24
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +9 -24
- package/package.json +28 -28
- package/src/client/sequencer-client.ts +6 -2
- package/src/config.ts +3 -0
- package/src/publisher/config.ts +13 -11
- package/src/publisher/index.ts +1 -1
- package/src/publisher/sequencer-publisher-factory.ts +12 -2
- package/src/publisher/sequencer-publisher.ts +77 -77
- package/src/sequencer/errors.ts +21 -0
- package/src/sequencer/metrics.ts +24 -100
- package/src/sequencer/sequencer.ts +51 -46
- package/src/sequencer/timetable.ts +2 -13
- package/src/sequencer/utils.ts +10 -24
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { L2Block } from '@aztec/aztec.js';
|
|
2
|
-
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import { BLOBS_PER_BLOCK, FIELDS_PER_BLOB, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
3
3
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
4
4
|
import { FormattedViemError, NoCommitteeError, type RollupContract } from '@aztec/ethereum';
|
|
5
5
|
import { omit, pick } from '@aztec/foundation/collection';
|
|
6
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
|
+
import { Signature } from '@aztec/foundation/eth-signature';
|
|
7
8
|
import { Fr } from '@aztec/foundation/fields';
|
|
8
9
|
import { createLogger } from '@aztec/foundation/log';
|
|
9
10
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
@@ -11,8 +12,13 @@ import { type DateProvider, Timer } from '@aztec/foundation/timer';
|
|
|
11
12
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
12
13
|
import type { P2P } from '@aztec/p2p';
|
|
13
14
|
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
14
|
-
import
|
|
15
|
-
|
|
15
|
+
import {
|
|
16
|
+
type CommitteeAttestation,
|
|
17
|
+
CommitteeAttestationsAndSigners,
|
|
18
|
+
type L2BlockSource,
|
|
19
|
+
type ValidateBlockResult,
|
|
20
|
+
} from '@aztec/stdlib/block';
|
|
21
|
+
import { type L1RollupConstants, getSlotAtTimestamp, getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
16
22
|
import { Gas } from '@aztec/stdlib/gas';
|
|
17
23
|
import {
|
|
18
24
|
type IFullNodeBlockBuilder,
|
|
@@ -21,19 +27,11 @@ import {
|
|
|
21
27
|
type WorldStateSynchronizer,
|
|
22
28
|
} from '@aztec/stdlib/interfaces/server';
|
|
23
29
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
24
|
-
import type
|
|
25
|
-
import { orderAttestations } from '@aztec/stdlib/p2p';
|
|
30
|
+
import { type BlockProposalOptions, orderAttestations } from '@aztec/stdlib/p2p';
|
|
26
31
|
import { pickFromSchema } from '@aztec/stdlib/schemas';
|
|
27
32
|
import type { L2BlockBuiltStats } from '@aztec/stdlib/stats';
|
|
28
33
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
29
|
-
import {
|
|
30
|
-
ContentCommitment,
|
|
31
|
-
type FailedTx,
|
|
32
|
-
GlobalVariables,
|
|
33
|
-
ProposedBlockHeader,
|
|
34
|
-
Tx,
|
|
35
|
-
type TxHash,
|
|
36
|
-
} from '@aztec/stdlib/tx';
|
|
34
|
+
import { ContentCommitment, type FailedTx, GlobalVariables, ProposedBlockHeader, Tx } from '@aztec/stdlib/tx';
|
|
37
35
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
38
36
|
import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
39
37
|
import type { ValidatorClient } from '@aztec/validator-client';
|
|
@@ -45,8 +43,9 @@ import type { GlobalVariableBuilder } from '../global_variable_builder/global_bu
|
|
|
45
43
|
import type { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
46
44
|
import type { Action, InvalidateBlockRequest, SequencerPublisher } from '../publisher/sequencer-publisher.js';
|
|
47
45
|
import type { SequencerConfig } from './config.js';
|
|
46
|
+
import { SequencerInterruptedError, SequencerTooSlowError } from './errors.js';
|
|
48
47
|
import { SequencerMetrics } from './metrics.js';
|
|
49
|
-
import { SequencerTimetable
|
|
48
|
+
import { SequencerTimetable } from './timetable.js';
|
|
50
49
|
import { SequencerState, type SequencerStateWithSlot } from './utils.js';
|
|
51
50
|
|
|
52
51
|
export { SequencerState };
|
|
@@ -127,15 +126,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
127
126
|
) {
|
|
128
127
|
super();
|
|
129
128
|
|
|
130
|
-
|
|
131
|
-
const validatorAddresses = this.validatorClient?.getValidatorAddresses() ?? [];
|
|
132
|
-
const coinbase =
|
|
133
|
-
validatorAddresses.length === 0
|
|
134
|
-
? EthAddress.ZERO
|
|
135
|
-
: (this.validatorClient?.getCoinbaseForAttestor(validatorAddresses[0]) ?? EthAddress.ZERO);
|
|
136
|
-
|
|
137
|
-
this.metrics = new SequencerMetrics(telemetry, () => this.state, coinbase, this.rollupContract, 'Sequencer');
|
|
138
|
-
|
|
129
|
+
this.metrics = new SequencerMetrics(telemetry, this.rollupContract, 'Sequencer');
|
|
139
130
|
// Initialize config
|
|
140
131
|
this.updateConfig(this.config);
|
|
141
132
|
}
|
|
@@ -220,7 +211,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
220
211
|
* Starts the sequencer and moves to IDLE state.
|
|
221
212
|
*/
|
|
222
213
|
public start() {
|
|
223
|
-
this.metrics.start();
|
|
224
214
|
this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.pollingIntervalMs);
|
|
225
215
|
this.setState(SequencerState.IDLE, undefined, { force: true });
|
|
226
216
|
this.runningPromise.start();
|
|
@@ -232,9 +222,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
232
222
|
*/
|
|
233
223
|
public async stop(): Promise<void> {
|
|
234
224
|
this.log.info(`Stopping sequencer`);
|
|
235
|
-
this.
|
|
225
|
+
this.setState(SequencerState.STOPPING, undefined, { force: true });
|
|
236
226
|
this.publisher?.interrupt();
|
|
237
|
-
await this.validatorClient?.stop();
|
|
238
227
|
await this.runningPromise?.stop();
|
|
239
228
|
this.setState(SequencerState.STOPPED, undefined, { force: true });
|
|
240
229
|
this.log.info('Stopped sequencer');
|
|
@@ -361,8 +350,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
361
350
|
const coinbase = this.validatorClient!.getCoinbaseForAttestor(attestorAddress);
|
|
362
351
|
const feeRecipient = this.validatorClient!.getFeeRecipientForAttestor(attestorAddress);
|
|
363
352
|
|
|
364
|
-
this.metrics.setCoinbase(coinbase);
|
|
365
|
-
|
|
366
353
|
// Prepare invalidation request if the pending chain is invalid (returns undefined if no need)
|
|
367
354
|
const invalidateBlock = await publisher.simulateInvalidateBlock(syncedTo.pendingChainValidationStatus);
|
|
368
355
|
const canProposeCheck = await publisher.canProposeAtNextEthBlock(
|
|
@@ -435,6 +422,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
435
422
|
}
|
|
436
423
|
|
|
437
424
|
this.setState(SequencerState.INITIALIZING_PROPOSAL, slot);
|
|
425
|
+
|
|
426
|
+
this.metrics.incOpenSlot(slot, proposerAddressInNextSlot.toString());
|
|
438
427
|
this.log.verbose(`Preparing proposal for block ${newBlockNumber} at slot ${slot}`, {
|
|
439
428
|
proposer: proposerInNextSlot?.toString(),
|
|
440
429
|
coinbase,
|
|
@@ -494,7 +483,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
494
483
|
if (proposedBlock) {
|
|
495
484
|
this.lastBlockPublished = block;
|
|
496
485
|
this.emit('block-published', { blockNumber: newBlockNumber, slot: Number(slot) });
|
|
497
|
-
this.metrics.incFilledSlot(publisher.getSenderAddress().toString());
|
|
486
|
+
await this.metrics.incFilledSlot(publisher.getSenderAddress().toString(), coinbase);
|
|
498
487
|
} else if (block) {
|
|
499
488
|
this.emit('block-publish-failed', l1Response ?? {});
|
|
500
489
|
}
|
|
@@ -535,6 +524,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
535
524
|
opts?: { force?: boolean },
|
|
536
525
|
): void;
|
|
537
526
|
setState(proposedState: SequencerState, slotNumber: bigint | undefined, opts: { force?: boolean } = {}): void {
|
|
527
|
+
if (this.state === SequencerState.STOPPING && proposedState !== SequencerState.STOPPED && !opts.force) {
|
|
528
|
+
this.log.warn(`Cannot set sequencer to ${proposedState} as it is stopping.`);
|
|
529
|
+
throw new SequencerInterruptedError();
|
|
530
|
+
}
|
|
538
531
|
if (this.state === SequencerState.STOPPED && !opts.force) {
|
|
539
532
|
this.log.warn(`Cannot set sequencer from ${this.state} to ${proposedState} as it is stopped.`);
|
|
540
533
|
return;
|
|
@@ -584,6 +577,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
584
577
|
maxTransactions: this.maxTxsPerBlock,
|
|
585
578
|
maxBlockSize: this.maxBlockSizeInBytes,
|
|
586
579
|
maxBlockGas: this.maxBlockGas,
|
|
580
|
+
maxBlobFields: BLOBS_PER_BLOCK * FIELDS_PER_BLOB,
|
|
587
581
|
deadline,
|
|
588
582
|
};
|
|
589
583
|
}
|
|
@@ -616,7 +610,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
616
610
|
const slot = proposalHeader.slotNumber.toBigInt();
|
|
617
611
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
|
|
618
612
|
|
|
619
|
-
// this.metrics.recordNewBlock(blockNumber, validTxs.length);
|
|
620
613
|
const workTimer = new Timer();
|
|
621
614
|
this.setState(SequencerState.CREATING_BLOCK, slot);
|
|
622
615
|
|
|
@@ -675,7 +668,18 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
675
668
|
this.log.verbose(`Collected ${attestations.length} attestations`, { blockHash, blockNumber });
|
|
676
669
|
}
|
|
677
670
|
|
|
678
|
-
|
|
671
|
+
const attestationsAndSigners = new CommitteeAttestationsAndSigners(attestations ?? []);
|
|
672
|
+
const attestationsAndSignersSignature = this.validatorClient
|
|
673
|
+
? await this.validatorClient.signAttestationsAndSigners(attestationsAndSigners, proposerAddress)
|
|
674
|
+
: Signature.empty();
|
|
675
|
+
|
|
676
|
+
await this.enqueuePublishL2Block(
|
|
677
|
+
block,
|
|
678
|
+
attestationsAndSigners,
|
|
679
|
+
attestationsAndSignersSignature,
|
|
680
|
+
invalidateBlock,
|
|
681
|
+
publisher,
|
|
682
|
+
);
|
|
679
683
|
this.metrics.recordBuiltBlock(blockBuildDuration, publicGas.l2Gas);
|
|
680
684
|
return block;
|
|
681
685
|
} catch (err) {
|
|
@@ -751,7 +755,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
751
755
|
this.metrics.recordRequiredAttestations(numberOfRequiredAttestations, attestationTimeAllowed);
|
|
752
756
|
|
|
753
757
|
const timer = new Timer();
|
|
754
|
-
let
|
|
758
|
+
let collectedAttestationsCount: number = 0;
|
|
755
759
|
try {
|
|
756
760
|
const attestationDeadline = new Date(this.dateProvider.now() + attestationTimeAllowed * 1000);
|
|
757
761
|
const attestations = await this.validatorClient.collectAttestations(
|
|
@@ -760,17 +764,17 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
760
764
|
attestationDeadline,
|
|
761
765
|
);
|
|
762
766
|
|
|
763
|
-
|
|
767
|
+
collectedAttestationsCount = attestations.length;
|
|
764
768
|
|
|
765
769
|
// note: the smart contract requires that the signatures are provided in the order of the committee
|
|
766
770
|
return orderAttestations(attestations, committee);
|
|
767
771
|
} catch (err) {
|
|
768
772
|
if (err && err instanceof AttestationTimeoutError) {
|
|
769
|
-
|
|
773
|
+
collectedAttestationsCount = err.collectedCount;
|
|
770
774
|
}
|
|
771
775
|
throw err;
|
|
772
776
|
} finally {
|
|
773
|
-
this.metrics.recordCollectedAttestations(
|
|
777
|
+
this.metrics.recordCollectedAttestations(collectedAttestationsCount, timer.ms());
|
|
774
778
|
}
|
|
775
779
|
}
|
|
776
780
|
|
|
@@ -783,8 +787,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
783
787
|
}))
|
|
784
788
|
protected async enqueuePublishL2Block(
|
|
785
789
|
block: L2Block,
|
|
786
|
-
|
|
787
|
-
|
|
790
|
+
attestationsAndSigners: CommitteeAttestationsAndSigners,
|
|
791
|
+
attestationsAndSignersSignature: Signature,
|
|
788
792
|
invalidateBlock: InvalidateBlockRequest | undefined,
|
|
789
793
|
publisher: SequencerPublisher,
|
|
790
794
|
): Promise<void> {
|
|
@@ -795,10 +799,15 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
795
799
|
const slot = block.header.globalVariables.slotNumber.toNumber();
|
|
796
800
|
const txTimeoutAt = new Date((this.getSlotStartBuildTimestamp(slot) + this.aztecSlotDuration) * 1000);
|
|
797
801
|
|
|
798
|
-
const enqueued = await publisher.enqueueProposeL2Block(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
+
const enqueued = await publisher.enqueueProposeL2Block(
|
|
803
|
+
block,
|
|
804
|
+
attestationsAndSigners,
|
|
805
|
+
attestationsAndSignersSignature,
|
|
806
|
+
{
|
|
807
|
+
txTimeoutAt,
|
|
808
|
+
forcePendingBlockNumber: invalidateBlock?.forcePendingBlockNumber,
|
|
809
|
+
},
|
|
810
|
+
);
|
|
802
811
|
|
|
803
812
|
if (!enqueued) {
|
|
804
813
|
throw new Error(`Failed to enqueue publish of block ${block.number}`);
|
|
@@ -946,11 +955,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
946
955
|
}
|
|
947
956
|
|
|
948
957
|
private getSlotStartBuildTimestamp(slotNumber: number | bigint): number {
|
|
949
|
-
return (
|
|
950
|
-
Number(this.l1Constants.l1GenesisTime) +
|
|
951
|
-
Number(slotNumber) * this.l1Constants.slotDuration -
|
|
952
|
-
this.l1Constants.ethereumSlotDuration
|
|
953
|
-
);
|
|
958
|
+
return getSlotStartBuildTimestamp(slotNumber, this.l1Constants);
|
|
954
959
|
}
|
|
955
960
|
|
|
956
961
|
private getSecondsIntoSlot(slotNumber: number | bigint): number {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/aztec.js';
|
|
2
2
|
|
|
3
3
|
import { DEFAULT_ATTESTATION_PROPAGATION_TIME } from '../config.js';
|
|
4
|
+
import { SequencerTooSlowError } from './errors.js';
|
|
4
5
|
import type { SequencerMetrics } from './metrics.js';
|
|
5
6
|
import { SequencerState } from './utils.js';
|
|
6
7
|
|
|
@@ -139,6 +140,7 @@ export class SequencerTimetable {
|
|
|
139
140
|
public getMaxAllowedTime(state: SequencerState): number | undefined {
|
|
140
141
|
switch (state) {
|
|
141
142
|
case SequencerState.STOPPED:
|
|
143
|
+
case SequencerState.STOPPING:
|
|
142
144
|
case SequencerState.IDLE:
|
|
143
145
|
case SequencerState.SYNCHRONIZING:
|
|
144
146
|
return; // We don't really care about times for this states
|
|
@@ -177,16 +179,3 @@ export class SequencerTimetable {
|
|
|
177
179
|
this.log.trace(`Enough time to transition to ${newState}`, { maxAllowedTime, secondsIntoSlot });
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
|
-
|
|
181
|
-
export class SequencerTooSlowError extends Error {
|
|
182
|
-
constructor(
|
|
183
|
-
public readonly proposedState: SequencerState,
|
|
184
|
-
public readonly maxAllowedTime: number,
|
|
185
|
-
public readonly currentTime: number,
|
|
186
|
-
) {
|
|
187
|
-
super(
|
|
188
|
-
`Too far into slot for ${proposedState} (time into slot ${currentTime}s greater than ${maxAllowedTime}s allowance)`,
|
|
189
|
-
);
|
|
190
|
-
this.name = 'SequencerTooSlowError';
|
|
191
|
-
}
|
|
192
|
-
}
|
package/src/sequencer/utils.ts
CHANGED
|
@@ -1,35 +1,21 @@
|
|
|
1
1
|
export enum SequencerState {
|
|
2
|
-
/**
|
|
3
|
-
* Sequencer is stopped and not processing any txs from the pool.
|
|
4
|
-
*/
|
|
2
|
+
/** Sequencer is stopped and not processing any txs from the pool. */
|
|
5
3
|
STOPPED = 'STOPPED',
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/** Sequencer is being stopped. Will move to STOPPED shortly. */
|
|
5
|
+
STOPPING = 'STOPPING',
|
|
6
|
+
/** Sequencer is awaiting the next call to work(). */
|
|
9
7
|
IDLE = 'IDLE',
|
|
10
|
-
/**
|
|
11
|
-
* Synchronizing with the L2 chain.
|
|
12
|
-
*/
|
|
8
|
+
/** Synchronizing with the L2 chain. */
|
|
13
9
|
SYNCHRONIZING = 'SYNCHRONIZING',
|
|
14
|
-
/**
|
|
15
|
-
* Checking if we are the proposer for the current slot.
|
|
16
|
-
*/
|
|
10
|
+
/** Checking if we are the proposer for the current slot. */
|
|
17
11
|
PROPOSER_CHECK = 'PROPOSER_CHECK',
|
|
18
|
-
/**
|
|
19
|
-
* Initializing the block proposal. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise.
|
|
20
|
-
*/
|
|
12
|
+
/** Initializing the block proposal. Will move to CREATING_BLOCK if there are valid txs to include, or back to SYNCHRONIZING otherwise. */
|
|
21
13
|
INITIALIZING_PROPOSAL = 'INITIALIZING_PROPOSAL',
|
|
22
|
-
/**
|
|
23
|
-
* Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA.
|
|
24
|
-
*/
|
|
14
|
+
/** Creating a new L2 block. Includes processing public function calls and running rollup circuits. Will move to PUBLISHING_CONTRACT_DATA. */
|
|
25
15
|
CREATING_BLOCK = 'CREATING_BLOCK',
|
|
26
|
-
/**
|
|
27
|
-
* Collecting attestations from its peers. Will move to PUBLISHING_BLOCK.
|
|
28
|
-
*/
|
|
16
|
+
/** Collecting attestations from its peers. Will move to PUBLISHING_BLOCK. */
|
|
29
17
|
COLLECTING_ATTESTATIONS = 'COLLECTING_ATTESTATIONS',
|
|
30
|
-
/**
|
|
31
|
-
* Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING.
|
|
32
|
-
*/
|
|
18
|
+
/** Sending the tx to L1 with the L2 block data and awaiting it to be mined. Will move to SYNCHRONIZING. */
|
|
33
19
|
PUBLISHING_BLOCK = 'PUBLISHING_BLOCK',
|
|
34
20
|
}
|
|
35
21
|
|