@xyo-network/chain-services 1.20.14 → 1.20.16
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/README.md +9 -7634
- package/dist/neutral/index.mjs +2 -2
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/neutral/simple/block/runner/SimpleBlockRunner.d.ts +2 -2
- package/dist/neutral/simple/block/runner/SimpleBlockRunner.d.ts.map +1 -1
- package/package.json +122 -29
- package/src/BlockReward/EvmBlockRewardViewer.ts +0 -53
- package/src/BlockReward/index.ts +0 -1
- package/src/ChainValidator/XyoValidator.ts +0 -71
- package/src/ChainValidator/index.ts +0 -2
- package/src/ChainValidator/model/Validator.ts +0 -7
- package/src/ChainValidator/model/index.ts +0 -1
- package/src/Election/BaseElectionService.ts +0 -55
- package/src/Election/index.ts +0 -1
- package/src/NetworkStakeStepReward/BaseNetworkStakeStepRewardService.ts +0 -99
- package/src/NetworkStakeStepReward/index.ts +0 -1
- package/src/StepStake/BaseStepStakeService.ts +0 -24
- package/src/StepStake/index.ts +0 -1
- package/src/implementation/head/createBootstrapHead.ts +0 -36
- package/src/implementation/head/index.ts +0 -1
- package/src/implementation/index.ts +0 -1
- package/src/index.ts +0 -8
- package/src/model/Params.ts +0 -10
- package/src/model/index.ts +0 -1
- package/src/simple/block/index.ts +0 -1
- package/src/simple/block/runner/SimpleBlockRunner.ts +0 -363
- package/src/simple/block/runner/generateTransactionFeeTransfers.ts +0 -56
- package/src/simple/block/runner/index.ts +0 -1
- package/src/simple/index.ts +0 -1
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Promisable } from '@xylabs/sdk-js'
|
|
2
|
-
import type { BlockBoundWitness, SignedHydratedTransactionWithStorageMeta } from '@xyo-network/xl1-sdk'
|
|
3
|
-
|
|
4
|
-
export interface Validator {
|
|
5
|
-
validatePendingBlock(block: BlockBoundWitness): Promisable<Error[]>
|
|
6
|
-
validatePendingTransaction(tx: SignedHydratedTransactionWithStorageMeta): Promise<boolean>
|
|
7
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './Validator.ts'
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Address, assertEx, Hash,
|
|
3
|
-
} from '@xylabs/sdk-js'
|
|
4
|
-
import { hexToLast4BytesInt, shuffleWithSeed } from '@xyo-network/chain-utils'
|
|
5
|
-
import { WithHashMeta } from '@xyo-network/sdk-js'
|
|
6
|
-
import {
|
|
7
|
-
AbstractCreatableProvider,
|
|
8
|
-
type BlockViewer,
|
|
9
|
-
type ChainStakeViewer, creatableProvider,
|
|
10
|
-
type ElectionService, type StakeIntentService,
|
|
11
|
-
} from '@xyo-network/xl1-sdk'
|
|
12
|
-
import { BlockBoundWitness } from '@xyo-network/xl1-sdk'
|
|
13
|
-
|
|
14
|
-
import { BaseServiceParams } from '../model/index.ts'
|
|
15
|
-
|
|
16
|
-
export interface BaseElectionServicesParams extends BaseServiceParams {
|
|
17
|
-
blockViewer?: BlockViewer
|
|
18
|
-
chainStakeViewer?: ChainStakeViewer
|
|
19
|
-
stakeIntentService?: StakeIntentService
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
@creatableProvider()
|
|
23
|
-
export class BaseElectionService extends AbstractCreatableProvider<BaseElectionServicesParams> implements ElectionService {
|
|
24
|
-
static readonly defaultMoniker = 'Election'
|
|
25
|
-
static readonly dependencies = []
|
|
26
|
-
static readonly monikers = ['Election']
|
|
27
|
-
moniker = BaseElectionService.defaultMoniker
|
|
28
|
-
get blockViewer() {
|
|
29
|
-
return assertEx(this.params.blockViewer, () => 'No block viewer')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get chainStakeViewer() {
|
|
33
|
-
return assertEx(this.params.chainStakeViewer, () => 'No chain stake viewer')
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get stakeIntentService() {
|
|
37
|
-
return assertEx(this.params.stakeIntentService, () => 'No staked intent service')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async getCreatorCommitteeForNextBlock(current: WithHashMeta<BlockBoundWitness>): Promise<Address[]> {
|
|
41
|
-
return await this.spanAsync('getCreatorCommitteeForNextBlock', async () => {
|
|
42
|
-
const nextBlock = current.block + 1
|
|
43
|
-
const candidates = await this.stakeIntentService.getDeclaredCandidatesForBlock(nextBlock, 'producer')
|
|
44
|
-
const previousBlockHash = current._hash
|
|
45
|
-
return this.generateCreatorCommittee(candidates, previousBlockHash)
|
|
46
|
-
}, this.context)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
protected generateCreatorCommittee(candidates: Address[], previousBlockHash: Hash, maxSize = 3): Address[] {
|
|
50
|
-
const creators = new Set<Address>(candidates)
|
|
51
|
-
const seed = hexToLast4BytesInt(previousBlockHash)
|
|
52
|
-
const creatorArray = shuffleWithSeed(creators, seed)
|
|
53
|
-
return creatorArray.slice(0, maxSize)
|
|
54
|
-
}
|
|
55
|
-
}
|
package/src/Election/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './BaseElectionService.ts'
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { Address, Promisable } from '@xylabs/sdk-js'
|
|
2
|
-
import { ReadArchivist } from '@xyo-network/sdk-js'
|
|
3
|
-
import {
|
|
4
|
-
AbstractCreatableProvider,
|
|
5
|
-
AttoXL1,
|
|
6
|
-
creatableProvider,
|
|
7
|
-
NetworkStakeStepRewardService, NetworkStakeStepRewardViewerMoniker,
|
|
8
|
-
StepIdentity,
|
|
9
|
-
StepIdentityString,
|
|
10
|
-
} from '@xyo-network/xl1-sdk'
|
|
11
|
-
import { Provider } from 'ethers'
|
|
12
|
-
|
|
13
|
-
import { BaseServiceParams } from '../model/index.ts'
|
|
14
|
-
|
|
15
|
-
export interface BaseNetworkStakeStepRewardServiceParams extends BaseServiceParams {
|
|
16
|
-
chainArchivist: ReadArchivist
|
|
17
|
-
ethProvider?: Provider
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@creatableProvider()
|
|
21
|
-
export class BaseNetworkStakeStepRewardService extends
|
|
22
|
-
AbstractCreatableProvider<BaseNetworkStakeStepRewardServiceParams> implements NetworkStakeStepRewardService {
|
|
23
|
-
static readonly defaultMoniker = NetworkStakeStepRewardViewerMoniker
|
|
24
|
-
static readonly dependencies = []
|
|
25
|
-
static readonly monikers = [NetworkStakeStepRewardViewerMoniker]
|
|
26
|
-
override moniker = BaseNetworkStakeStepRewardService.defaultMoniker
|
|
27
|
-
|
|
28
|
-
networkStakeStepRewardAddressHistory(_address: Address): Promisable<Record<Address, AttoXL1>> {
|
|
29
|
-
throw new Error('Method [networkStakeStepRewardAddressHistory] not implemented.')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
networkStakeStepRewardAddressReward(_context: StepIdentity, _address: Address): Promisable<Record<Address, AttoXL1>> {
|
|
33
|
-
throw new Error('Method [networkStakeStepRewardAddressReward] not implemented.')
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
networkStakeStepRewardAddressShare(_context: StepIdentity, _address: Address): Promisable<[bigint, bigint]> {
|
|
37
|
-
throw new Error('Method [networkStakeStepRewardAddressShare] not implemented.')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
networkStakeStepRewardClaimedByAddress(_address: Address): Promisable<AttoXL1> {
|
|
41
|
-
throw new Error('Method [networkStakeStepRewardClaimedByAddress] not implemented.')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
networkStakeStepRewardForPosition(_position: number, _range: [number, number]): Promisable<[AttoXL1, AttoXL1]> {
|
|
45
|
-
throw new Error('Method [networkStakeStepRewardForPosition] not implemented.')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
networkStakeStepRewardForStep(_context: StepIdentity): Promisable<AttoXL1> {
|
|
49
|
-
throw new Error('Method [networkStakeStepRewardForStep] not implemented.')
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
networkStakeStepRewardForStepForPosition(_context: StepIdentity, _position: number): Promisable<[AttoXL1, AttoXL1]> {
|
|
53
|
-
throw new Error('Method [networkStakeStepRewardForStepForPosition] not implemented.')
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
networkStakeStepRewardPoolRewards(_context: StepIdentity): Promisable<Record<Address, AttoXL1>> {
|
|
57
|
-
throw new Error('Method [networkStakeStepRewardPoolRewards] not implemented.')
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
networkStakeStepRewardPoolShares(_context: StepIdentity): Promisable<Record<Address, bigint>> {
|
|
61
|
-
throw new Error('Method [networkStakeStepRewardPoolShares] not implemented.')
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
networkStakeStepRewardPositionWeight(_context: StepIdentity, _position: number): Promisable<bigint> {
|
|
65
|
-
throw new Error('Method [networkStakeStepRewardPositionWeight] not implemented.')
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
networkStakeStepRewardPotentialPositionLoss(_context: StepIdentity, _position: number): Promisable<AttoXL1> {
|
|
69
|
-
throw new Error('Method [networkStakeStepRewardPotentialPositionLoss] not implemented.')
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
networkStakeStepRewardRandomizer(_context: StepIdentity): Promisable<AttoXL1> {
|
|
73
|
-
throw new Error('Method [networkStakeStepRewardRandomizer] not implemented.')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
networkStakeStepRewardStakerCount(_context: StepIdentity): Promisable<number> {
|
|
77
|
-
throw new Error('Method [networkStakeStepRewardStakerCount] not implemented.')
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
networkStakeStepRewardUnclaimedByAddress(_address: Address): Promisable<AttoXL1> {
|
|
81
|
-
throw new Error('Method [networkStakeStepRewardUnclaimedByAddress] not implemented.')
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
networkStakeStepRewardWeightForAddress(_context: StepIdentity, _address: Address): Promisable<bigint> {
|
|
85
|
-
throw new Error('Method [networkStakeStepRewardWeightForAddress] not implemented.')
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
networkStakeStepRewardsForPosition(_position: number, _range: [number, number]): Promisable<Record<StepIdentityString, [AttoXL1, AttoXL1]>> {
|
|
89
|
-
throw new Error('Method [networkStakeStepRewardsForPosition] not implemented.')
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
networkStakeStepRewardsForRange(_range: [number, number]): Promisable<AttoXL1> {
|
|
93
|
-
throw new Error('Method [networkStakeStepRewardsForRange] not implemented.')
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
networkStakeStepRewardsForStepLevel(_stepLevel: number, _range: [number, number]): Promisable<AttoXL1> {
|
|
97
|
-
throw new Error('Method [networkStakeStepRewardsForStepLevel] not implemented.')
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './BaseNetworkStakeStepRewardService.ts'
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Address, Promisable } from '@xylabs/sdk-js'
|
|
2
|
-
import type { ReadArchivist } from '@xyo-network/sdk-js'
|
|
3
|
-
import type { StepIdentity, StepStakeViewer } from '@xyo-network/xl1-sdk'
|
|
4
|
-
import { AbstractCreatableProvider, StepStakeViewerMoniker } from '@xyo-network/xl1-sdk'
|
|
5
|
-
|
|
6
|
-
import type { BaseServiceParams } from '../model/index.ts'
|
|
7
|
-
|
|
8
|
-
export interface BaseStepStakeServiceParams extends BaseServiceParams {
|
|
9
|
-
chainArchivist: ReadArchivist
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export abstract class AbstractStepStakeService extends AbstractCreatableProvider<BaseStepStakeServiceParams> implements StepStakeViewer {
|
|
13
|
-
static readonly defaultMoniker = StepStakeViewerMoniker
|
|
14
|
-
static readonly monikers = [StepStakeViewerMoniker]
|
|
15
|
-
override moniker = AbstractStepStakeService.defaultMoniker
|
|
16
|
-
|
|
17
|
-
stepStake(_step: StepIdentity): Promisable<Record<Address, bigint>> {
|
|
18
|
-
throw new Error('Method [stepStake] not implemented.')
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
stepStakeForAddress(_address: Address, _step: StepIdentity): Promisable<bigint> {
|
|
22
|
-
throw new Error('Method [stepStakeForAddress] not implemented.')
|
|
23
|
-
}
|
|
24
|
-
}
|
package/src/StepStake/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './BaseStepStakeService.ts'
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { Address } from '@xylabs/sdk-js'
|
|
2
|
-
import { buildNextBlock, createGenesisBlock } from '@xyo-network/chain-protocol'
|
|
3
|
-
import type { AccountInstance } from '@xyo-network/sdk-js'
|
|
4
|
-
import type {
|
|
5
|
-
AttoXL1, ChainId, SignedHydratedBlockWithHashMeta,
|
|
6
|
-
} from '@xyo-network/xl1-sdk'
|
|
7
|
-
import { createDeclarationIntent } from '@xyo-network/xl1-sdk'
|
|
8
|
-
|
|
9
|
-
export const createBootstrapHead = async (
|
|
10
|
-
account: AccountInstance,
|
|
11
|
-
chainId: ChainId,
|
|
12
|
-
genesisBlockRewardAmount: AttoXL1,
|
|
13
|
-
genesisBlockRewardAddress: Address,
|
|
14
|
-
): Promise<SignedHydratedBlockWithHashMeta[]> => {
|
|
15
|
-
const chain: SignedHydratedBlockWithHashMeta[] = []
|
|
16
|
-
|
|
17
|
-
// Create genesis block
|
|
18
|
-
const genesisBlock = await createGenesisBlock(account, chainId, genesisBlockRewardAmount, genesisBlockRewardAddress)
|
|
19
|
-
chain.push(genesisBlock)
|
|
20
|
-
|
|
21
|
-
// Create producer declaration block
|
|
22
|
-
const producerDeclarationPayload = createDeclarationIntent(
|
|
23
|
-
account.address,
|
|
24
|
-
'producer',
|
|
25
|
-
genesisBlock[0].block,
|
|
26
|
-
genesisBlock[0].block + 10_000,
|
|
27
|
-
)
|
|
28
|
-
const producerDeclarationBlock = await buildNextBlock(
|
|
29
|
-
genesisBlock[0],
|
|
30
|
-
[],
|
|
31
|
-
[producerDeclarationPayload],
|
|
32
|
-
[account],
|
|
33
|
-
)
|
|
34
|
-
chain.push(producerDeclarationBlock)
|
|
35
|
-
return chain
|
|
36
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './createBootstrapHead.ts'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './head/index.ts'
|
package/src/index.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export * from './BlockReward/index.ts'
|
|
2
|
-
export * from './ChainValidator/index.ts'
|
|
3
|
-
export * from './Election/index.ts'
|
|
4
|
-
export * from './implementation/index.ts'
|
|
5
|
-
export * from './model/index.ts'
|
|
6
|
-
export * from './NetworkStakeStepReward/index.ts'
|
|
7
|
-
export * from './simple/index.ts'
|
|
8
|
-
export * from './StepStake/index.ts'
|
package/src/model/Params.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { AccountInstance } from '@xyo-network/sdk-js'
|
|
2
|
-
import type { CreatableProviderParams, OpenTelemetryProviders } from '@xyo-network/xl1-sdk'
|
|
3
|
-
|
|
4
|
-
export interface BaseServiceParams extends CreatableProviderParams, OpenTelemetryProviders {
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface BaseAccountableServiceParams extends BaseServiceParams {
|
|
9
|
-
account: AccountInstance
|
|
10
|
-
}
|
package/src/model/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './Params.ts'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './runner/index.ts'
|
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Address, assertEx, exists, Hex, hexToBigInt, isDefined, Promisable,
|
|
3
|
-
} from '@xylabs/sdk-js'
|
|
4
|
-
import {
|
|
5
|
-
BlockRewardDiviner, FixedPercentageBlockRewardDiviner, FixedPercentageBlockRewardDivinerConfigSchema,
|
|
6
|
-
} from '@xyo-network/chain-modules'
|
|
7
|
-
import { buildNextBlock } from '@xyo-network/chain-protocol'
|
|
8
|
-
import {
|
|
9
|
-
AccountInstance,
|
|
10
|
-
ArchivistInstance, MemoryArchivist,
|
|
11
|
-
PayloadBuilder, WithHashMeta,
|
|
12
|
-
} from '@xyo-network/sdk-js'
|
|
13
|
-
import {
|
|
14
|
-
AbstractCreatableProvider, AccountBalanceViewer, AccountBalanceViewerMoniker, AllowedBlockPayload, asBlockBoundWitness, AttoXL1, BlockBoundWitness,
|
|
15
|
-
BlockNumberPayload, BlockNumberSchema, BlockRewardViewer, BlockRewardViewerMoniker, BlockRunner, BlockRunnerMoniker, BlockValidationViewer,
|
|
16
|
-
BlockValidationViewerMoniker, ChainStakeIntent, creatableProvider, CreatableProviderParams, createDeclarationIntent, defaultRewardRatio,
|
|
17
|
-
FinalizationViewer,
|
|
18
|
-
FinalizationViewerMoniker,
|
|
19
|
-
HydratedBlockStateValidationFunction, isSignedHydratedBlockWithHashMeta, MempoolRunner, MempoolRunnerMoniker, MempoolViewer, MempoolViewerMoniker,
|
|
20
|
-
SignedBlockBoundWitnessWithHashMeta,
|
|
21
|
-
SignedHydratedBlockWithHashMeta, SignedHydratedTransaction, TimeSyncViewer, TimeSyncViewerMoniker, Transfer, XYO_STEP_REWARD_ADDRESS,
|
|
22
|
-
} from '@xyo-network/xl1-sdk'
|
|
23
|
-
|
|
24
|
-
import { generateTransactionFeeTransfers } from './generateTransactionFeeTransfers.ts'
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* The default block size for a block
|
|
28
|
-
*/
|
|
29
|
-
export const DEFAULT_BLOCK_SIZE = 10
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The amount of time for which a producer will restake their intent
|
|
33
|
-
*/
|
|
34
|
-
export const XYO_PRODUCER_REDECLARATION_DURATION = 10_000
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The number of blocks within which a producer will redeclare
|
|
38
|
-
* their intent to produce blocks
|
|
39
|
-
*/
|
|
40
|
-
export const XYO_PRODUCER_REDECLARATION_WINDOW = 500
|
|
41
|
-
|
|
42
|
-
export interface SimpleBlockRunnerParams extends CreatableProviderParams {
|
|
43
|
-
account: AccountInstance
|
|
44
|
-
disableIntentRedeclaration?: boolean
|
|
45
|
-
heartbeatInterval?: number
|
|
46
|
-
rejectedTransactionsArchivist?: ArchivistInstance
|
|
47
|
-
rewardAddress: Address
|
|
48
|
-
validateHydratedBlockState?: HydratedBlockStateValidationFunction
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@creatableProvider()
|
|
52
|
-
export class SimpleBlockRunner extends AbstractCreatableProvider<SimpleBlockRunnerParams> implements BlockRunner {
|
|
53
|
-
static readonly defaultMoniker = BlockRunnerMoniker
|
|
54
|
-
static readonly dependencies = [
|
|
55
|
-
AccountBalanceViewerMoniker,
|
|
56
|
-
BlockRewardViewerMoniker,
|
|
57
|
-
BlockValidationViewerMoniker,
|
|
58
|
-
FinalizationViewerMoniker,
|
|
59
|
-
MempoolRunnerMoniker,
|
|
60
|
-
MempoolViewerMoniker,
|
|
61
|
-
TimeSyncViewerMoniker,
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
static readonly monikers = [BlockRunnerMoniker]
|
|
65
|
-
moniker = SimpleBlockRunner.defaultMoniker
|
|
66
|
-
|
|
67
|
-
protected _blockRewardDiviner?: BlockRewardDiviner
|
|
68
|
-
protected _lastRedeclarationBlock?: number
|
|
69
|
-
protected _rejectedTransactionsArchivist?: ArchivistInstance
|
|
70
|
-
|
|
71
|
-
private _account?: AccountInstance
|
|
72
|
-
private _accountBalanceViewer?: AccountBalanceViewer
|
|
73
|
-
private _address?: Address
|
|
74
|
-
private _blockRewardViewer?: BlockRewardViewer
|
|
75
|
-
private _blockValidationViewer?: BlockValidationViewer
|
|
76
|
-
private _finalizationViewer?: FinalizationViewer
|
|
77
|
-
private _mempoolRunner?: MempoolRunner
|
|
78
|
-
private _mempoolViewer?: MempoolViewer
|
|
79
|
-
private _rewardAddress?: Address
|
|
80
|
-
private _timeSyncViewer?: TimeSyncViewer
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* The default block size for a block
|
|
84
|
-
*/
|
|
85
|
-
static get DefaultBlockSize(): number {
|
|
86
|
-
return DEFAULT_BLOCK_SIZE
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* The amount of time for which the producer will redeclare
|
|
91
|
-
* their intent to continue producing blocks
|
|
92
|
-
*/
|
|
93
|
-
static get RedeclarationDuration(): number {
|
|
94
|
-
return XYO_PRODUCER_REDECLARATION_DURATION
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The number of blocks within which the producer will redeclare
|
|
99
|
-
* their intent to continue producing blocks
|
|
100
|
-
*/
|
|
101
|
-
static get RedeclarationWindow(): number {
|
|
102
|
-
return XYO_PRODUCER_REDECLARATION_WINDOW
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
protected get account() {
|
|
106
|
-
return this._account!
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
protected get accountBalanceViewer() {
|
|
110
|
-
return this._accountBalanceViewer!
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
protected get address() {
|
|
114
|
-
return this._address!
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
protected get blockRewardViewer() {
|
|
118
|
-
return this._blockRewardViewer!
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
protected get blockValidationViewer() {
|
|
122
|
-
return this._blockValidationViewer!
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
protected get finalizationViewer() {
|
|
126
|
-
return this._finalizationViewer!
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
protected get heartbeatInterval() {
|
|
130
|
-
return this.params.heartbeatInterval ?? 3_600_000
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
protected get mempoolRunner() {
|
|
134
|
-
return this._mempoolRunner!
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
protected get mempoolViewer() {
|
|
138
|
-
return this._mempoolViewer!
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// protected get pendingTransactionsService() {
|
|
142
|
-
// return assertEx(this.params.pendingTransactionsService, () => 'Missing pendingTransactionsService')
|
|
143
|
-
// }
|
|
144
|
-
|
|
145
|
-
protected get rejectedTransactionsArchivist() {
|
|
146
|
-
return this._rejectedTransactionsArchivist!
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
protected get rewardAddress(): Address {
|
|
150
|
-
return this._rewardAddress!
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// protected get stakeIntentService(): StakeIntentService {
|
|
154
|
-
// return assertEx(this.params.stakeIntentService, () => 'No StakeIntentService provided')
|
|
155
|
-
// }
|
|
156
|
-
|
|
157
|
-
protected get timeSyncViewer(): TimeSyncViewer {
|
|
158
|
-
return this._timeSyncViewer!
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// protected get validateHydratedBlockState() {
|
|
162
|
-
// return assertEx(this.params.validateHydratedBlockState, () => 'validateHydratedBlockState is required')
|
|
163
|
-
// }
|
|
164
|
-
|
|
165
|
-
override async createHandler() {
|
|
166
|
-
this._rejectedTransactionsArchivist = this.params.rejectedTransactionsArchivist ?? await MemoryArchivist.create()
|
|
167
|
-
this._account = assertEx(this.params.account, () => 'Account is required')
|
|
168
|
-
this._address = this.account.address
|
|
169
|
-
this._accountBalanceViewer = await this.locateAndCreate<AccountBalanceViewer>(AccountBalanceViewerMoniker)
|
|
170
|
-
this._blockRewardViewer = await this.locateAndCreate<BlockRewardViewer>(BlockRewardViewerMoniker)
|
|
171
|
-
this._blockValidationViewer = await this.locator.getInstance<BlockValidationViewer>(BlockValidationViewerMoniker)
|
|
172
|
-
this._finalizationViewer = await this.locateAndCreate<FinalizationViewer>(FinalizationViewerMoniker)
|
|
173
|
-
this._mempoolRunner = await this.locateAndCreate<MempoolRunner>(MempoolRunnerMoniker)
|
|
174
|
-
this._mempoolViewer = await this.locateAndCreate<MempoolViewer>(MempoolViewerMoniker)
|
|
175
|
-
this._rewardAddress = this.params.rewardAddress
|
|
176
|
-
this._timeSyncViewer = await this.locateAndCreate<TimeSyncViewer>(TimeSyncViewerMoniker)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async next(head: WithHashMeta<BlockBoundWitness>): Promise<SignedHydratedBlockWithHashMeta | undefined> {
|
|
180
|
-
// If the block is for another chain, ignore
|
|
181
|
-
// if (head.chain !== this.chainId) return
|
|
182
|
-
// const leadersStart = Date.now()
|
|
183
|
-
// const leaders = await this.electionService.getCreatorCommitteeForNextBlock(head)
|
|
184
|
-
// const leadersDuration = Date.now() - leadersStart
|
|
185
|
-
// if (leadersDuration > 100) {
|
|
186
|
-
// this.logger?.warn(`[Slow] Fetched leaders in ${leadersDuration}ms: ${leaders.map(l => l.slice(0, 6)).join(', ')}`)
|
|
187
|
-
// }
|
|
188
|
-
// TODO: Should we propose block if creator committee is empty?
|
|
189
|
-
// TODO: Handle the case where we're not the 1st leader but they're not responding
|
|
190
|
-
// at a higher level than here as that's a network issue
|
|
191
|
-
// if (!leaders.includes(this.address)) return
|
|
192
|
-
return await this.proposeNextValidBlock(head)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async produceNextBlock(head: SignedBlockBoundWitnessWithHashMeta, force: true): Promise<SignedHydratedBlockWithHashMeta>
|
|
196
|
-
async produceNextBlock(head: SignedBlockBoundWitnessWithHashMeta, force?: false): Promise<SignedHydratedBlockWithHashMeta | undefined>
|
|
197
|
-
async produceNextBlock(head: SignedBlockBoundWitnessWithHashMeta, force?: boolean): Promise<SignedHydratedBlockWithHashMeta | undefined> {
|
|
198
|
-
// assertEx(head.chain === this.chainId, () => 'Block chain ID does not match')
|
|
199
|
-
const result = await this.proposeNextValidBlock(head)
|
|
200
|
-
return force ? assertEx(result, () => 'Failed to produce next block') : result
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
protected async getBlockRewardTransfers(block: number): Promise<Transfer[]> {
|
|
204
|
-
if (!this._blockRewardDiviner) {
|
|
205
|
-
// TODO: Adjust to allow for genesis block reward vs. normal block reward
|
|
206
|
-
this._blockRewardDiviner = await FixedPercentageBlockRewardDiviner.create({
|
|
207
|
-
account: 'random',
|
|
208
|
-
blockRewardViewer: this.blockRewardViewer,
|
|
209
|
-
config: {
|
|
210
|
-
rewardAddress: this.rewardAddress,
|
|
211
|
-
rewardPercentageRatio: defaultRewardRatio,
|
|
212
|
-
schema: FixedPercentageBlockRewardDivinerConfigSchema,
|
|
213
|
-
},
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const blockId = new PayloadBuilder<BlockNumberPayload>({ schema: BlockNumberSchema }).fields({ block }).build()
|
|
218
|
-
const rewards = await this._blockRewardDiviner.divine([blockId])
|
|
219
|
-
return rewards as Transfer[]
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Handles the producer redeclaration logic
|
|
224
|
-
* @param head The current head block
|
|
225
|
-
* @returns chain stake intent for the producer redeclaration, or undefined if no redeclaration is needed
|
|
226
|
-
*/
|
|
227
|
-
protected getProducerRedeclaration(head: WithHashMeta<BlockBoundWitness>): Promisable<ChainStakeIntent | undefined> {
|
|
228
|
-
// TODO: Do not redeclare on every block
|
|
229
|
-
// Decide if we should redeclare intent
|
|
230
|
-
if (this.params.disableIntentRedeclaration) return
|
|
231
|
-
// Decide if we need to redeclare intent
|
|
232
|
-
// const ranges = await this.stakeIntentService.getDeclaredCandidateRanges(this.address, 'producer')
|
|
233
|
-
// TODO: This doesn't handle the case where the producer had declared a range for the future
|
|
234
|
-
// but we're in a range that's not the future
|
|
235
|
-
// Sort in ascending order based on ending range to get range with highest ending block
|
|
236
|
-
// const lastRange = ranges.toSorted((a, b) => a[1] > b[1] ? 1 : -1).at(-1)
|
|
237
|
-
// if (!lastRange) return
|
|
238
|
-
// const [, currentDeclarationEnd] = lastRange
|
|
239
|
-
const currentBlock = head.block
|
|
240
|
-
// const timeToProducerExpiration = currentDeclarationEnd - currentBlock
|
|
241
|
-
// if (timeToProducerExpiration > BaseBlockProducerService.RedeclarationWindow) return
|
|
242
|
-
return createDeclarationIntent(this.address, 'producer', currentBlock, currentBlock + SimpleBlockRunner.RedeclarationDuration)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
protected async proposeNextValidBlock(head: WithHashMeta<BlockBoundWitness>, validateBalances = false, force = false) {
|
|
246
|
-
// eslint-disable-next-line max-statements
|
|
247
|
-
return await this.spanAsync('proposeNextValidBlock', async () => {
|
|
248
|
-
try {
|
|
249
|
-
// Calculate the next block components
|
|
250
|
-
const { block: previousBlock } = assertEx(asBlockBoundWitness(head), () => 'Invalid head block')
|
|
251
|
-
const nextBlock = previousBlock + 1
|
|
252
|
-
const nextBlockTransactions = await this.mempoolViewer.pendingTransactions({ limit: SimpleBlockRunner.DefaultBlockSize })
|
|
253
|
-
|
|
254
|
-
this.logger?.info(`Pending Tx Count ${nextBlockTransactions.length}`)
|
|
255
|
-
|
|
256
|
-
const blockPayloads: AllowedBlockPayload[] = []
|
|
257
|
-
|
|
258
|
-
// Calculate the optional producer redeclaration and add it if necessary
|
|
259
|
-
const producerRedeclarationPayload = await this.getProducerRedeclaration(head)
|
|
260
|
-
if (producerRedeclarationPayload) blockPayloads.push(producerRedeclarationPayload)
|
|
261
|
-
|
|
262
|
-
// If there are no transactions, no payloads and no heartbeat required, we don't need to create a block
|
|
263
|
-
if (nextBlockTransactions.length === 0 && !this.heartbeatRequired(head) && !force) return
|
|
264
|
-
|
|
265
|
-
// Calculate the optional block reward transfer and add if necessary
|
|
266
|
-
const rewardTransferPayloads = await this.getBlockRewardTransfers(nextBlock)
|
|
267
|
-
blockPayloads.push(...rewardTransferPayloads)
|
|
268
|
-
|
|
269
|
-
const transactionTransfers = await generateTransactionFeeTransfers(this.address, nextBlockTransactions)
|
|
270
|
-
const timeStart = Date.now()
|
|
271
|
-
const timePayload = await this.generateTimePayload()
|
|
272
|
-
const timeDuration = Date.now() - timeStart
|
|
273
|
-
if (timeDuration > 100) {
|
|
274
|
-
this.logger?.warn(`[Slow] Generated time payload in ${timeDuration}ms`)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const [fundedNextBlockTransactions, fundedTransfers] = await this.filterByFunded(head, nextBlockTransactions, transactionTransfers, validateBalances)
|
|
278
|
-
|
|
279
|
-
blockPayloads.push(...fundedTransfers, timePayload)
|
|
280
|
-
|
|
281
|
-
// Build the block
|
|
282
|
-
this.logger?.info(`Building block ${head.block + 1}`)
|
|
283
|
-
const startBuild = Date.now()
|
|
284
|
-
const stepRewardPoolBalance = (await this.accountBalanceViewer.accountBalances([XYO_STEP_REWARD_ADDRESS]))[XYO_STEP_REWARD_ADDRESS]
|
|
285
|
-
const block = await buildNextBlock(
|
|
286
|
-
head,
|
|
287
|
-
fundedNextBlockTransactions,
|
|
288
|
-
blockPayloads,
|
|
289
|
-
[this.account],
|
|
290
|
-
XYO_STEP_REWARD_ADDRESS,
|
|
291
|
-
stepRewardPoolBalance,
|
|
292
|
-
undefined,
|
|
293
|
-
await this.finalizationViewer.chainId(),
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
this.logger?.info(
|
|
297
|
-
`Built block ${block[0].block} in ${Date.now() - startBuild}ms with ${block[1].length} payloads`,
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
this.logger?.info(`Validating block ${block[0].block} with ${block[1].length} payloads`)
|
|
301
|
-
const startValidate = Date.now()
|
|
302
|
-
const validatedBlock = await this.blockValidationViewer.validateBlock(block, { head: head._hash })
|
|
303
|
-
this.logger?.info(`Validated block ${block[0].block} in ${Date.now() - startValidate}ms with ${block[1].length} payloads`)
|
|
304
|
-
|
|
305
|
-
if (isSignedHydratedBlockWithHashMeta(validatedBlock)) {
|
|
306
|
-
await this.mempoolRunner.submitBlocks([validatedBlock])
|
|
307
|
-
return validatedBlock
|
|
308
|
-
} else {
|
|
309
|
-
const errors = validatedBlock
|
|
310
|
-
this.logger?.warn(`Validation of produced block failed: ${errors.at(0)?.message}`)
|
|
311
|
-
const rejectedTransactions = block[1]
|
|
312
|
-
await this.rejectedTransactionsArchivist.insert(rejectedTransactions)
|
|
313
|
-
}
|
|
314
|
-
} catch (error) {
|
|
315
|
-
this.logger?.error(`Error proposing next valid block: ${(error as Error).message}`)
|
|
316
|
-
throw error
|
|
317
|
-
}
|
|
318
|
-
}, this.context)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// remove unfunded transactions and block transfers
|
|
322
|
-
private async filterByFunded(
|
|
323
|
-
head: WithHashMeta<BlockBoundWitness>,
|
|
324
|
-
txs: SignedHydratedTransaction[],
|
|
325
|
-
transfers: Transfer[],
|
|
326
|
-
validateBalances = false,
|
|
327
|
-
): Promise<[SignedHydratedTransaction[], Transfer[]]> {
|
|
328
|
-
const fundedTransfers: Transfer[] = []
|
|
329
|
-
const fundedTransactions = (await Promise.all(txs.map(async (tx) => {
|
|
330
|
-
const transfer: Transfer | undefined = transfers.find(transfer => transfer.from === tx[0].from)
|
|
331
|
-
if (!transfer) return
|
|
332
|
-
const totalTransferCost = Object.values(transfer?.transfers).reduce((acc, t) => acc + hexToBigInt(t ?? '00' as Hex), 0n)
|
|
333
|
-
if (validateBalances) {
|
|
334
|
-
const balance = (await this.accountBalanceViewer.accountBalances([transfer.from]))[transfer.from] ?? AttoXL1(0n)
|
|
335
|
-
if (balance >= totalTransferCost) {
|
|
336
|
-
fundedTransfers.push(transfer)
|
|
337
|
-
return tx
|
|
338
|
-
}
|
|
339
|
-
} else {
|
|
340
|
-
fundedTransfers.push(transfer)
|
|
341
|
-
return tx
|
|
342
|
-
}
|
|
343
|
-
}))).filter(exists)
|
|
344
|
-
return [fundedTransactions, fundedTransfers]
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
private async generateTimePayload() {
|
|
348
|
-
return await this.timeSyncViewer.currentTimePayload()
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Check if a heartbeat block is required based on network activity.
|
|
353
|
-
* @param head The current head block
|
|
354
|
-
* @returns True if a heartbeat is required, false otherwise
|
|
355
|
-
*/
|
|
356
|
-
private heartbeatRequired(head: WithHashMeta<BlockBoundWitness>): boolean {
|
|
357
|
-
const epoch = head.$epoch
|
|
358
|
-
if (isDefined(epoch) && Date.now() - epoch > this.heartbeatInterval) {
|
|
359
|
-
return true
|
|
360
|
-
}
|
|
361
|
-
return false
|
|
362
|
-
}
|
|
363
|
-
}
|