@xyo-network/xl1-protocol-sdk 1.5.34 → 1.5.36
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/dist/neutral/index.mjs +304 -124
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/types/ChainServiceCollection.d.ts +60 -0
- package/dist/types/ChainServiceCollection.d.ts.map +1 -0
- package/dist/types/ChainServiceCollectionV2.d.ts +60 -0
- package/dist/types/ChainServiceCollectionV2.d.ts.map +1 -0
- package/dist/types/SignedBigInt.d.ts +14 -0
- package/dist/types/SignedBigInt.d.ts.map +1 -0
- package/dist/types/block/hydrateBlock.d.ts +1 -1
- package/dist/types/block/hydrateBlock.d.ts.map +1 -1
- package/dist/types/block/primitives/balanceStepSummaryFromRange.d.ts +6 -0
- package/dist/types/block/primitives/balanceStepSummaryFromRange.d.ts.map +1 -0
- package/dist/types/block/primitives/balanceSummary.d.ts +4 -0
- package/dist/types/block/primitives/balanceSummary.d.ts.map +1 -0
- package/dist/types/block/primitives/frames/deepCalculateFramesFromRange.d.ts.map +1 -1
- package/dist/types/block/primitives/frames/index.d.ts +2 -1
- package/dist/types/block/primitives/frames/index.d.ts.map +1 -1
- package/dist/types/block/primitives/hashFromBlockNumber.d.ts +4 -0
- package/dist/types/block/primitives/hashFromBlockNumber.d.ts.map +1 -0
- package/dist/types/block/primitives/index.d.ts +5 -0
- package/dist/types/block/primitives/index.d.ts.map +1 -1
- package/dist/types/block/primitives/model.d.ts +16 -0
- package/dist/types/block/primitives/model.d.ts.map +1 -0
- package/dist/types/block/primitives/payloads.d.ts +21 -0
- package/dist/types/block/primitives/payloads.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/payload/index.d.ts +2 -0
- package/dist/types/payload/index.d.ts.map +1 -0
- package/dist/types/payload/netBalancesForPayloads.d.ts +3 -0
- package/dist/types/payload/netBalancesForPayloads.d.ts.map +1 -0
- package/dist/types/transaction/buildTransaction.d.ts +1 -1
- package/dist/types/transaction/buildTransaction.d.ts.map +1 -1
- package/package.json +19 -19
- package/src/ChainServiceCollection.ts +65 -0
- package/src/ChainServiceCollectionV2.ts +65 -0
- package/src/SignedBigInt.ts +51 -0
- package/src/block/hydrateBlock.ts +14 -13
- package/src/block/primitives/balanceStepSummaryFromRange.ts +78 -0
- package/src/block/primitives/balanceSummary.ts +27 -0
- package/src/block/primitives/frames/calculateFramesFromRange.ts +2 -2
- package/src/block/primitives/frames/deepCalculateFramesFromRange.ts +2 -2
- package/src/block/primitives/frames/index.ts +2 -1
- package/src/block/primitives/hashFromBlockNumber.ts +31 -0
- package/src/block/primitives/index.ts +5 -0
- package/src/block/primitives/model.ts +18 -0
- package/src/block/primitives/payloads.ts +29 -0
- package/src/index.ts +4 -0
- package/src/payload/index.ts +1 -0
- package/src/payload/netBalancesForPayloads.ts +19 -0
- package/src/transaction/buildTransaction.ts +16 -9
- package/dist/types/block/primitives/frames/loadFrameSummaries.d.ts +0 -5
- package/dist/types/block/primitives/frames/loadFrameSummaries.d.ts.map +0 -1
- package/dist/types/block/primitives/frames/stepHashFramesFromBlock.d.ts +0 -5
- package/dist/types/block/primitives/frames/stepHashFramesFromBlock.d.ts.map +0 -1
- package/src/block/primitives/frames/loadFrameSummaries.ts +0 -12
- package/src/block/primitives/frames/stepHashFramesFromBlock.ts +0 -72
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ArchivistInstance, WriteArchivist } from '@xyo-network/archivist-model'
|
|
2
|
+
import type { WalletInstance } from '@xyo-network/wallet-model'
|
|
3
|
+
import type {
|
|
4
|
+
AccountBalanceService, BlockProducerService,
|
|
5
|
+
BlockRewardService, ChainContractViewer, ChainStaker, ChainStakeViewer, ElectionService, EventingChainBlockNumberIterator,
|
|
6
|
+
StakeIntentService,
|
|
7
|
+
} from '@xyo-network/xl1-protocol'
|
|
8
|
+
|
|
9
|
+
export interface ChainServiceCollection {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The account which is used to sign transactions
|
|
13
|
+
*/
|
|
14
|
+
account: WalletInstance
|
|
15
|
+
/**
|
|
16
|
+
* Services for working with account balances
|
|
17
|
+
*/
|
|
18
|
+
balanceService: AccountBalanceService
|
|
19
|
+
/**
|
|
20
|
+
* The archivist which the chain data is stored in
|
|
21
|
+
*/
|
|
22
|
+
chainArchivist: ArchivistInstance
|
|
23
|
+
/**
|
|
24
|
+
* Service for viewing codified chain information
|
|
25
|
+
* from a contract
|
|
26
|
+
*/
|
|
27
|
+
chainContractViewer: ChainContractViewer
|
|
28
|
+
/**
|
|
29
|
+
* The chain iterator
|
|
30
|
+
*/
|
|
31
|
+
chainIterator?: EventingChainBlockNumberIterator
|
|
32
|
+
/**
|
|
33
|
+
* Service for viewing stake information
|
|
34
|
+
*/
|
|
35
|
+
chainStakeViewer: ChainStakeViewer
|
|
36
|
+
/**
|
|
37
|
+
* Service for staking
|
|
38
|
+
*/
|
|
39
|
+
chainStaker: ChainStaker
|
|
40
|
+
/**
|
|
41
|
+
* The archivist which the chain submissions are stored in
|
|
42
|
+
*/
|
|
43
|
+
chainSubmissionsArchivistWrite: WriteArchivist
|
|
44
|
+
/**
|
|
45
|
+
* Service for determining leader election
|
|
46
|
+
*/
|
|
47
|
+
electionService: ElectionService
|
|
48
|
+
/**
|
|
49
|
+
* The archivist which the pending transactions are stored
|
|
50
|
+
* as bundled transactions
|
|
51
|
+
*/
|
|
52
|
+
pendingBundledTransactionsArchivistWrite: ArchivistInstance
|
|
53
|
+
/**
|
|
54
|
+
* The block producer service
|
|
55
|
+
*/
|
|
56
|
+
producer: BlockProducerService
|
|
57
|
+
/**
|
|
58
|
+
* Service response for calculating block rewards
|
|
59
|
+
*/
|
|
60
|
+
rewardService: BlockRewardService
|
|
61
|
+
/**
|
|
62
|
+
* Services for working with staked intents
|
|
63
|
+
*/
|
|
64
|
+
stakeIntentService: StakeIntentService
|
|
65
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ArchivistInstance, WriteArchivist } from '@xyo-network/archivist-model'
|
|
2
|
+
import type { WalletInstance } from '@xyo-network/wallet-model'
|
|
3
|
+
import type {
|
|
4
|
+
AccountBalanceServiceV2, BlockProducerService,
|
|
5
|
+
BlockRewardService, ChainContractViewer, ChainStaker, ChainStakeViewer, ElectionService, EventingChainBlockNumberIterator,
|
|
6
|
+
StakeIntentService,
|
|
7
|
+
} from '@xyo-network/xl1-protocol'
|
|
8
|
+
|
|
9
|
+
export interface ChainServiceCollectionV2 {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The account which is used to sign transactions
|
|
13
|
+
*/
|
|
14
|
+
account: WalletInstance
|
|
15
|
+
/**
|
|
16
|
+
* Services for working with account balances
|
|
17
|
+
*/
|
|
18
|
+
balanceService: AccountBalanceServiceV2
|
|
19
|
+
/**
|
|
20
|
+
* The archivist which the chain data is stored in
|
|
21
|
+
*/
|
|
22
|
+
chainArchivist: ArchivistInstance
|
|
23
|
+
/**
|
|
24
|
+
* Service for viewing codified chain information
|
|
25
|
+
* from a contract
|
|
26
|
+
*/
|
|
27
|
+
chainContractViewer: ChainContractViewer
|
|
28
|
+
/**
|
|
29
|
+
* The chain iterator
|
|
30
|
+
*/
|
|
31
|
+
chainIterator?: EventingChainBlockNumberIterator
|
|
32
|
+
/**
|
|
33
|
+
* Service for viewing stake information
|
|
34
|
+
*/
|
|
35
|
+
chainStakeViewer: ChainStakeViewer
|
|
36
|
+
/**
|
|
37
|
+
* Service for staking
|
|
38
|
+
*/
|
|
39
|
+
chainStaker: ChainStaker
|
|
40
|
+
/**
|
|
41
|
+
* The archivist which the chain submissions are stored in
|
|
42
|
+
*/
|
|
43
|
+
chainSubmissionsArchivistWrite: WriteArchivist
|
|
44
|
+
/**
|
|
45
|
+
* Service for determining leader election
|
|
46
|
+
*/
|
|
47
|
+
electionService: ElectionService
|
|
48
|
+
/**
|
|
49
|
+
* The archivist which the pending transactions are stored
|
|
50
|
+
* as bundled transactions
|
|
51
|
+
*/
|
|
52
|
+
pendingBundledTransactionsArchivistWrite: ArchivistInstance
|
|
53
|
+
/**
|
|
54
|
+
* The block producer service
|
|
55
|
+
*/
|
|
56
|
+
producer: BlockProducerService
|
|
57
|
+
/**
|
|
58
|
+
* Service response for calculating block rewards
|
|
59
|
+
*/
|
|
60
|
+
rewardService: BlockRewardService
|
|
61
|
+
/**
|
|
62
|
+
* Services for working with staked intents
|
|
63
|
+
*/
|
|
64
|
+
stakeIntentService: StakeIntentService
|
|
65
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Hex,
|
|
3
|
+
hexToBigInt,
|
|
4
|
+
toHex,
|
|
5
|
+
} from '@xylabs/hex'
|
|
6
|
+
import { isObject } from '@xylabs/object'
|
|
7
|
+
|
|
8
|
+
export interface NegativeBigInt {
|
|
9
|
+
negative: Hex
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PositiveBigInt {
|
|
13
|
+
positive: Hex
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type SignedBigInt = NegativeBigInt | PositiveBigInt
|
|
17
|
+
|
|
18
|
+
export const isNegativeBigInt = (value: unknown): value is NegativeBigInt => {
|
|
19
|
+
return isObject(value) && 'negative' in value && typeof value.negative === 'string'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const isPositiveBigInt = (value: unknown): value is PositiveBigInt => {
|
|
23
|
+
return isObject(value) && 'positive' in value && typeof value.positive === 'string'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const parseSignedBigInt = (value: SignedBigInt): bigint => {
|
|
27
|
+
if (isNegativeBigInt(value)) {
|
|
28
|
+
return -hexToBigInt(value.negative)
|
|
29
|
+
} else if (isPositiveBigInt(value)) {
|
|
30
|
+
return hexToBigInt(value.positive)
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error('Invalid balance type')
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const toSignedBigInt = (value: bigint): SignedBigInt => {
|
|
37
|
+
return value < 0n ? { negative: toHex(-value) } : { positive: toHex(value) }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const toPositiveBigInt = (value: unknown): PositiveBigInt => {
|
|
41
|
+
if (isNegativeBigInt(value)) {
|
|
42
|
+
return { positive: toHex(0n) }
|
|
43
|
+
}
|
|
44
|
+
if (isPositiveBigInt(value)) {
|
|
45
|
+
return { positive: value.positive }
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === 'bigint') {
|
|
48
|
+
return { positive: toHex(value) }
|
|
49
|
+
}
|
|
50
|
+
throw new Error('Invalid value for positive big int')
|
|
51
|
+
}
|
|
@@ -17,27 +17,28 @@ export const tryHydrateBlock = async (
|
|
|
17
17
|
archivist: ReadArchivist,
|
|
18
18
|
hash: Hash,
|
|
19
19
|
maxDepth: number = 1,
|
|
20
|
-
minDepth?: number,
|
|
21
20
|
): Promise<HydratedBlock | undefined> => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
assertEx(maxDepth >= 0, () => 'maxDepth must be greater than or equal to 0')
|
|
22
|
+
const bw = filterAs(await archivist.get([hash]), asBlockBoundWitnessWithStorageMeta).at(0)
|
|
23
|
+
if (!bw) return undefined
|
|
24
|
+
if (maxDepth === 0) return [bw, []]
|
|
25
|
+
const blkPayloads = await archivist.get(bw.payload_hashes)
|
|
26
|
+
if (maxDepth === 1) return [bw, blkPayloads]
|
|
27
|
+
const transactions = filterAs(blkPayloads, asTransactionBoundWitnessWithStorageMeta)
|
|
28
|
+
const transactionsPayloadHashes = transactions.flatMap(tx => tx.payload_hashes)
|
|
29
|
+
const transactionsPayloads = await archivist.get(transactionsPayloadHashes)
|
|
30
|
+
const allPayloadsHashes = new Set([...blkPayloads, ...transactionsPayloads].flatMap(p => p._hash))
|
|
31
|
+
const allPayloads = await archivist.get([...allPayloadsHashes])
|
|
32
|
+
const allPayloadsFiltered = allPayloads.filter(p => allPayloadsHashes.has(p._hash))
|
|
33
|
+
return [bw, allPayloadsFiltered]
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export const hydrateBlock = async (
|
|
35
37
|
archivist: ReadArchivist,
|
|
36
38
|
hash: Hash,
|
|
37
39
|
maxDepth: number = 1,
|
|
38
|
-
minDepth
|
|
40
|
+
minDepth = maxDepth,
|
|
39
41
|
): Promise<HydratedBlock> => {
|
|
40
|
-
if (minDepth === undefined) minDepth = maxDepth
|
|
41
42
|
assertEx(maxDepth >= 0, () => 'maxDepth must be greater than or equal to 0')
|
|
42
43
|
assertEx(minDepth >= 0, () => 'minDepth must be greater than or equal to 0')
|
|
43
44
|
assertEx(maxDepth >= minDepth, () => 'maxDepth must be greater than or equal to minDepth')
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { type Address } from '@xylabs/hex'
|
|
3
|
+
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
4
|
+
import type { WithStorageMeta } from '@xyo-network/payload-model'
|
|
5
|
+
import { isAnyPayload } from '@xyo-network/payload-model'
|
|
6
|
+
import { StepSizes } from '@xyo-network/xl1-protocol'
|
|
7
|
+
|
|
8
|
+
import { netBalancesForPayloads } from '../../payload/netBalancesForPayloads.ts'
|
|
9
|
+
import {
|
|
10
|
+
parseSignedBigInt, type SignedBigInt, toSignedBigInt,
|
|
11
|
+
} from '../../SignedBigInt.ts'
|
|
12
|
+
import { hydrateBlock } from '../hydrateBlock.ts'
|
|
13
|
+
import type { BlockNumberRange } from './frames/BlockNumberRange.ts'
|
|
14
|
+
import { deepCalculateFramesFromRange } from './frames/deepCalculateFramesFromRange.ts'
|
|
15
|
+
import { hashFromBlockNumber } from './hashFromBlockNumber.ts'
|
|
16
|
+
import type { BalanceStepSummaryContext } from './model.ts'
|
|
17
|
+
import { type BalancesStepSummary, BalancesStepSummarySchema } from './payloads.ts'
|
|
18
|
+
|
|
19
|
+
export async function balanceStepSummaryFromRange(
|
|
20
|
+
context: BalanceStepSummaryContext,
|
|
21
|
+
range: BlockNumberRange,
|
|
22
|
+
): Promise<WithStorageMeta<BalancesStepSummary>> {
|
|
23
|
+
// console.log(`balanceStepSummaryFromRange: head=${head}, range=${range[0]}-${range[1]}`)
|
|
24
|
+
const frameHeadHash = await hashFromBlockNumber(context, range[1])
|
|
25
|
+
const frameSize = range[1] - range[0] + 1
|
|
26
|
+
|
|
27
|
+
let result: BalancesStepSummary | undefined = undefined
|
|
28
|
+
|
|
29
|
+
if (frameSize === 1) {
|
|
30
|
+
const [, payloads] = await hydrateBlock(context.chainArchivist, context.head)
|
|
31
|
+
const balances: Record<Address, SignedBigInt> = {}
|
|
32
|
+
for (const [address, balance] of Object.entries(netBalancesForPayloads(payloads))) {
|
|
33
|
+
balances[address as Address] = toSignedBigInt(balance)
|
|
34
|
+
}
|
|
35
|
+
result = {
|
|
36
|
+
schema: BalancesStepSummarySchema, hash: context.head, stepSize: -1, balances,
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
const step = (StepSizes as any).indexOf(frameSize)
|
|
41
|
+
assertEx(step !== -1, () => `Invalid step size: ${frameSize}. Must be one of ${StepSizes.join(', ')}`)
|
|
42
|
+
|
|
43
|
+
const [summaryResult] = await context.summaryRepository.get([frameHeadHash])
|
|
44
|
+
if (isAnyPayload(summaryResult)) {
|
|
45
|
+
result = summaryResult as WithStorageMeta<BalancesStepSummary>
|
|
46
|
+
} else {
|
|
47
|
+
// We do not have it, so lets build it
|
|
48
|
+
const subRanges = deepCalculateFramesFromRange(range, step - 1)
|
|
49
|
+
const promises = subRanges.map(subRange => balanceStepSummaryFromRange(
|
|
50
|
+
context,
|
|
51
|
+
subRange,
|
|
52
|
+
))
|
|
53
|
+
const subResults = await Promise.all(promises)
|
|
54
|
+
|
|
55
|
+
// add them all up
|
|
56
|
+
const bigIntBalances: Record<Address, bigint> = {}
|
|
57
|
+
for (const subResult of subResults) {
|
|
58
|
+
for (const [address, balance] of Object.entries(subResult.balances)) {
|
|
59
|
+
bigIntBalances[address as Address] = (bigIntBalances[address as Address] ?? 0n) + parseSignedBigInt(balance)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const balances: Record<Address, SignedBigInt> = {}
|
|
64
|
+
for (const [address, balance] of Object.entries(bigIntBalances)) {
|
|
65
|
+
balances[address as Address] = toSignedBigInt(balance)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
result = {
|
|
69
|
+
schema: BalancesStepSummarySchema, hash: frameHeadHash, stepSize: frameSize, balances,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await context.summaryRepository.insert([result])
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// console.log(`balanceStepSummaryFromRange-result: head=${head}, range=${range[0]}-${range[1]}: ${toJsonString(result, 10)}`)
|
|
76
|
+
const finalResult = await PayloadBuilder.addStorageMeta(result)
|
|
77
|
+
return finalResult
|
|
78
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Address } from '@xylabs/hex'
|
|
2
|
+
import { asAddress } from '@xylabs/hex'
|
|
3
|
+
import { isDefined } from '@xylabs/typeof'
|
|
4
|
+
import { asBlockBoundWitnessWithStorageMeta } from '@xyo-network/xl1-protocol'
|
|
5
|
+
|
|
6
|
+
import { parseSignedBigInt } from '../../SignedBigInt.ts'
|
|
7
|
+
import { balanceStepSummaryFromRange } from './balanceStepSummaryFromRange.ts'
|
|
8
|
+
import { deepCalculateFramesFromRange } from './frames/deepCalculateFramesFromRange.ts'
|
|
9
|
+
import type { BalanceStepSummaryContext } from './model.ts'
|
|
10
|
+
|
|
11
|
+
export async function balanceSummary(
|
|
12
|
+
context: BalanceStepSummaryContext,
|
|
13
|
+
): Promise<Partial<Record<Address, bigint>>> {
|
|
14
|
+
const headResult = await context.chainArchivist.get([context.head])
|
|
15
|
+
const headBoundWitness = asBlockBoundWitnessWithStorageMeta(headResult.at(0), () => `Head block not found for hash: ${context.head}`, { required: true })
|
|
16
|
+
const rangeStart = isDefined(context.windowSize) ? Math.max(headBoundWitness.block - context.windowSize + 1, 0) : 0
|
|
17
|
+
const ranges = deepCalculateFramesFromRange([rangeStart, headBoundWitness.block])
|
|
18
|
+
const summaries = await Promise.all(ranges.map(range => balanceStepSummaryFromRange(context, range)))
|
|
19
|
+
const balances: Partial<Record<Address, bigint>> = {}
|
|
20
|
+
for (let summary of summaries) {
|
|
21
|
+
for (const [address, balance] of Object.entries(summary.balances)) {
|
|
22
|
+
const validAddress = asAddress(address, () => `Invalid address: ${address}`)
|
|
23
|
+
balances[validAddress] = (balances[validAddress] ?? 0n) + parseSignedBigInt(balance)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return balances
|
|
27
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { stepSize } from '@xyo-network/xl1-protocol'
|
|
2
2
|
|
|
3
3
|
import type { BlockNumberRange } from './BlockNumberRange.ts'
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ export function calculateFramesFromRange(range: BlockNumberRange, step: number):
|
|
|
7
7
|
BlockNumberRange[],
|
|
8
8
|
// ranges of remaining blocks
|
|
9
9
|
BlockNumberRange[]] {
|
|
10
|
-
const size =
|
|
10
|
+
const size = stepSize(step)
|
|
11
11
|
let start = (Math.trunc(range[0] / size)) * size
|
|
12
12
|
const fitted: BlockNumberRange[] = []
|
|
13
13
|
const remaining: BlockNumberRange[] = []
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StepSizes } from '@xyo-network/xl1-protocol'
|
|
2
2
|
|
|
3
3
|
import type { BlockNumberRange } from './BlockNumberRange.ts'
|
|
4
4
|
import { calculateFramesFromRange } from './calculateFramesFromRange.ts'
|
|
5
5
|
|
|
6
|
-
export function deepCalculateFramesFromRange(range: BlockNumberRange, startingStep =
|
|
6
|
+
export function deepCalculateFramesFromRange(range: BlockNumberRange, startingStep = StepSizes.length - 1): BlockNumberRange[] {
|
|
7
7
|
const fitted: BlockNumberRange[] = []
|
|
8
8
|
let remaining: BlockNumberRange[] = [range]
|
|
9
9
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { asHash, type Hash } from '@xylabs/hex'
|
|
2
|
+
import { toJsonString } from '@xylabs/object'
|
|
3
|
+
import { asBlockBoundWitnessWithStorageMeta, StepSizes } from '@xyo-network/xl1-protocol'
|
|
4
|
+
|
|
5
|
+
import type { ChainContext } from './model.ts'
|
|
6
|
+
|
|
7
|
+
export async function hashFromBlockNumber(context: ChainContext, blockNumber: number): Promise<Hash> {
|
|
8
|
+
const result = await context.chainArchivist.get([context.head])
|
|
9
|
+
let currentBlock = asBlockBoundWitnessWithStorageMeta(result.at(0), () => `Head block not found for hash: ${context.head}`, { required: true })
|
|
10
|
+
while (currentBlock.block > blockNumber) {
|
|
11
|
+
let jumpHash: Hash | null = currentBlock.previous
|
|
12
|
+
let jumpBlockNumber = currentBlock.block - 1
|
|
13
|
+
for (const [step, stepSize] of StepSizes.entries()) {
|
|
14
|
+
const possibleJumpBlockNumber = currentBlock.block - stepSize
|
|
15
|
+
if (possibleJumpBlockNumber >= blockNumber && possibleJumpBlockNumber <= jumpBlockNumber) {
|
|
16
|
+
jumpBlockNumber = possibleJumpBlockNumber
|
|
17
|
+
jumpHash = asHash(currentBlock.step_hashes.at(step), () => `Step hash not found for step ${step} in block ${currentBlock.block}`)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const [newBlock] = await context.chainArchivist.get([
|
|
21
|
+
asHash(jumpHash, () => `Jump hash not found for block number [${blockNumber}]: ${jumpBlockNumber} ${toJsonString(currentBlock, 10)}`)])
|
|
22
|
+
currentBlock = asBlockBoundWitnessWithStorageMeta(newBlock, () => `Block not found for hash: ${jumpHash}`, { required: true })
|
|
23
|
+
if (currentBlock.block === blockNumber) {
|
|
24
|
+
break
|
|
25
|
+
}
|
|
26
|
+
if (currentBlock.block < blockNumber) {
|
|
27
|
+
throw new Error(`Block number ${blockNumber} is not a valid step block number for block ${context.head}.`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return currentBlock._hash
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Hash } from '@xylabs/hex'
|
|
2
|
+
import type { ReadArchivist } from '@xyo-network/archivist-model'
|
|
3
|
+
import type { Payload } from '@xyo-network/payload-model'
|
|
4
|
+
import type { PayloadRepository } from '@xyo-network/xl1-protocol'
|
|
5
|
+
|
|
6
|
+
import type { BalancesStepSummary } from './payloads.ts'
|
|
7
|
+
|
|
8
|
+
export interface ChainContext {
|
|
9
|
+
chainArchivist: ReadArchivist
|
|
10
|
+
head: Hash
|
|
11
|
+
windowSize?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ChainSummaryContext<T extends Payload> extends ChainContext {
|
|
15
|
+
summaryRepository: PayloadRepository<Hash, T>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BalanceStepSummaryContext extends ChainSummaryContext<BalancesStepSummary> {}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Address, Hash } from '@xylabs/hex'
|
|
2
|
+
import type { EmptyObject } from '@xylabs/object'
|
|
3
|
+
import type { Payload, Schema } from '@xyo-network/payload-model'
|
|
4
|
+
|
|
5
|
+
import type { SignedBigInt } from '../../SignedBigInt.ts'
|
|
6
|
+
|
|
7
|
+
export const StepSummarySchema: Schema = 'network.xyo.step.summary'
|
|
8
|
+
export type StepSummarySchema = typeof StepSummarySchema
|
|
9
|
+
|
|
10
|
+
export interface StepSummaryFields {
|
|
11
|
+
hash: Hash // the stepHash - the hash of the last block in the step frame
|
|
12
|
+
stepSize: number // the stepSize in blocks
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ChainWindow {
|
|
16
|
+
depth: number // number of blocks the window covers, including the head
|
|
17
|
+
head: Hash // the head of the chain
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type StepSummary<TAdditionalFields extends EmptyObject | void = void,
|
|
21
|
+
TSchema extends Schema | void = void> = Payload<TAdditionalFields extends void ? StepSummaryFields : TAdditionalFields & StepSummaryFields,
|
|
22
|
+
TSchema extends void ? StepSummarySchema : TSchema>
|
|
23
|
+
|
|
24
|
+
export const BalancesStepSummarySchema: Schema = 'network.xyo.step.summary.balances'
|
|
25
|
+
export type BalancesStepSummarySchema = typeof BalancesStepSummarySchema
|
|
26
|
+
|
|
27
|
+
export type BalancesStepSummary = StepSummary<{
|
|
28
|
+
balances: Record<Address, SignedBigInt>
|
|
29
|
+
}, BalancesStepSummarySchema>
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export * from './block/index.ts'
|
|
2
|
+
export * from './ChainServiceCollection.ts'
|
|
3
|
+
export * from './ChainServiceCollectionV2.ts'
|
|
2
4
|
export * from './instances/index.ts'
|
|
5
|
+
export * from './payload/index.ts'
|
|
6
|
+
export * from './SignedBigInt.ts'
|
|
3
7
|
export * from './transaction/index.ts'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './netBalancesForPayloads.ts'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address, type Hex, hexToBigInt, toAddress,
|
|
3
|
+
} from '@xylabs/hex'
|
|
4
|
+
import type { Payload } from '@xyo-network/payload-model'
|
|
5
|
+
import { isTransfer } from '@xyo-network/xl1-protocol'
|
|
6
|
+
|
|
7
|
+
export const netBalancesForPayloads = (payloads: Payload[]) => {
|
|
8
|
+
const balances: Record<Address, bigint> = {}
|
|
9
|
+
for (const payload of payloads) {
|
|
10
|
+
if (isTransfer(payload)) {
|
|
11
|
+
const { from } = payload
|
|
12
|
+
for (let [address, amount] of Object.entries(payload.transfers) as [Address, Hex][]) {
|
|
13
|
+
balances[toAddress(address)] = (balances[toAddress(address)] ?? 0n) + hexToBigInt(amount)
|
|
14
|
+
balances[toAddress(from)] = (balances[toAddress(from)] ?? 0n) - hexToBigInt(amount)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return balances
|
|
19
|
+
}
|
|
@@ -5,11 +5,13 @@ import type { AccountInstance } from '@xyo-network/account-model'
|
|
|
5
5
|
import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
|
|
6
6
|
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
7
7
|
import type { Payload } from '@xyo-network/payload-model'
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import type {
|
|
9
|
+
AllowedBlockPayload,
|
|
10
|
+
ExecutableFields,
|
|
11
|
+
FromFields,
|
|
12
|
+
HydratedTransaction, TransactionBoundWitness, TransactionBoundWitnessFields, TransactionFeesBigInt,
|
|
12
13
|
} from '@xyo-network/xl1-protocol'
|
|
14
|
+
import { defaultTransactionFees } from '@xyo-network/xl1-protocol'
|
|
13
15
|
|
|
14
16
|
export async function buildTransaction(
|
|
15
17
|
chain: Address,
|
|
@@ -43,12 +45,17 @@ export async function buildTransaction(
|
|
|
43
45
|
script.push(`elevate|${elevatedHash}`)
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
const fields: TransactionBoundWitnessFields & FromFields & Partial<ExecutableFields> = {
|
|
49
|
+
...txBoundWitnessFields,
|
|
50
|
+
from: from ?? (Array.isArray(signer) ? assertEx(signer.at(0)?.address) : signer.address),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (script.length > 0) {
|
|
54
|
+
fields.script = script
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
const [tx, txPayloads] = await new BoundWitnessBuilder<TransactionBoundWitness>()
|
|
47
|
-
.fields(
|
|
48
|
-
...txBoundWitnessFields,
|
|
49
|
-
script,
|
|
50
|
-
from: from ?? (Array.isArray(signer) ? assertEx(signer.at(0)?.address) : signer.address),
|
|
51
|
-
})
|
|
58
|
+
.fields(fields)
|
|
52
59
|
.meta({ $signatures: [] })
|
|
53
60
|
.payloads([...elevatedPayloads, ...additionalPayloads])
|
|
54
61
|
.signers(Array.isArray(signer) ? signer : [signer])
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model';
|
|
2
|
-
import type { Payload } from '@xyo-network/payload-model';
|
|
3
|
-
import type { BlockNumberRange } from './BlockNumberRange.ts';
|
|
4
|
-
export declare function loadFrameSummaries(ranges: BlockNumberRange[], finalizedArchivist: ArchivistInstance, summaryArchivist: ArchivistInstance): Promise<Payload[]>;
|
|
5
|
-
//# sourceMappingURL=loadFrameSummaries.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loadFrameSummaries.d.ts","sourceRoot":"","sources":["../../../../../src/block/primitives/frames/loadFrameSummaries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAEzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,gBAAgB,EAAE,EAC1B,kBAAkB,EAAE,iBAAiB,EACrC,gBAAgB,EAAE,iBAAiB,GAClC,OAAO,CAAC,OAAO,EAAE,CAAC,CAEpB"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type Hash } from '@xylabs/hex';
|
|
2
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model';
|
|
3
|
-
export declare function stepHashFramesFromBlockAtSize(archivist: ArchivistInstance, head: Hash, sizeIndex: number): Promise<[Lowercase<string>, number, number][]>;
|
|
4
|
-
export declare function stepHashFramesFromBlock(archivist: ArchivistInstance, head: Hash): Promise<[Lowercase<string>, number, number][]>;
|
|
5
|
-
//# sourceMappingURL=stepHashFramesFromBlock.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stepHashFramesFromBlock.d.ts","sourceRoot":"","sources":["../../../../../src/block/primitives/frames/stepHashFramesFromBlock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,EAAU,MAAM,aAAa,CAAA;AAE/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAIrE,wBAAsB,6BAA6B,CAAC,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kDA0B9G;AAGD,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,kDAmCrF"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
2
|
-
import type { Payload } from '@xyo-network/payload-model'
|
|
3
|
-
|
|
4
|
-
import type { BlockNumberRange } from './BlockNumberRange.ts'
|
|
5
|
-
|
|
6
|
-
export async function loadFrameSummaries(
|
|
7
|
-
ranges: BlockNumberRange[],
|
|
8
|
-
finalizedArchivist: ArchivistInstance,
|
|
9
|
-
summaryArchivist: ArchivistInstance,
|
|
10
|
-
): Promise<Payload[]> {
|
|
11
|
-
return await Promise.resolve([])
|
|
12
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { assertEx } from '@xylabs/assert'
|
|
2
|
-
import { type Hash, isHash } from '@xylabs/hex'
|
|
3
|
-
import { isDefined } from '@xylabs/typeof'
|
|
4
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
5
|
-
import { isBlockBoundWitness, StepSizes } from '@xyo-network/xl1-protocol'
|
|
6
|
-
|
|
7
|
-
// get the list of step frames for a block at a specific step size index
|
|
8
|
-
export async function stepHashFramesFromBlockAtSize(archivist: ArchivistInstance, head: Hash, sizeIndex: number) {
|
|
9
|
-
if (!Number.isInteger(sizeIndex) || sizeIndex < 0 || sizeIndex >= StepSizes.length) {
|
|
10
|
-
throw new Error(`Invalid sizeIndex: ${sizeIndex}`)
|
|
11
|
-
}
|
|
12
|
-
let currentHead = head
|
|
13
|
-
const steps: [Hash, number, number][] = []
|
|
14
|
-
while (isHash(currentHead)) {
|
|
15
|
-
const [block] = await archivist.get([currentHead])
|
|
16
|
-
if (!isBlockBoundWitness(block)) {
|
|
17
|
-
throw new Error(`Block with hash ${currentHead} not found`)
|
|
18
|
-
}
|
|
19
|
-
let stepHash = block.step_hashes.at(sizeIndex)
|
|
20
|
-
while (isDefined(stepHash)) {
|
|
21
|
-
const [stepHashBlock] = await archivist.get([stepHash])
|
|
22
|
-
if (!isBlockBoundWitness(stepHashBlock)) {
|
|
23
|
-
throw new Error(`StepHashBlock with hash ${currentHead} not found`)
|
|
24
|
-
}
|
|
25
|
-
const [lastBlockInStep] = await archivist.get([assertEx(stepHashBlock.previous, () => 'StepHashBlock must have a previous block')])
|
|
26
|
-
if (!isBlockBoundWitness(lastBlockInStep)) {
|
|
27
|
-
throw new Error(`StepHashBlock with hash ${currentHead} not found`)
|
|
28
|
-
}
|
|
29
|
-
steps.push([stepHash, stepHashBlock.block - StepSizes[sizeIndex], stepHashBlock.block - 1])
|
|
30
|
-
stepHash = lastBlockInStep.step_hashes.at(sizeIndex)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return steps
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// TODO: Figure out how to get ranges of smaller blocks for each available range
|
|
37
|
-
export async function stepHashFramesFromBlock(archivist: ArchivistInstance, head: Hash) {
|
|
38
|
-
const [block] = await archivist.get([head])
|
|
39
|
-
if (!isBlockBoundWitness(block)) {
|
|
40
|
-
throw new Error(`Block with hash ${head} not found`)
|
|
41
|
-
}
|
|
42
|
-
let availableRanges: [number, number][] = [[0, block.block]]
|
|
43
|
-
const foundRanges: [Hash, number, number][] = []
|
|
44
|
-
// fit biggest to smallest
|
|
45
|
-
for (let i = StepSizes.length - 1; i >= 0; i--) {
|
|
46
|
-
const steps = await stepHashFramesFromBlockAtSize(archivist, head, i)
|
|
47
|
-
for (let step of steps) {
|
|
48
|
-
const [, start, end] = step
|
|
49
|
-
if (availableRanges.some(range => range[0] <= start && range[1] >= end)) {
|
|
50
|
-
foundRanges.push(step)
|
|
51
|
-
availableRanges = availableRanges.flatMap((range) => {
|
|
52
|
-
if (range[0] >= start && range[1] <= end) {
|
|
53
|
-
// remove the range
|
|
54
|
-
return [[range[0], start - 1]]
|
|
55
|
-
} else if (range[0] < start && range[1] >= end) {
|
|
56
|
-
// split the range
|
|
57
|
-
return [[range[0], start - 1], [end + 1, range[1]]]
|
|
58
|
-
} else if (range[0] < start && range[1] < end) {
|
|
59
|
-
// adjust the end of the range
|
|
60
|
-
return [[range[0], start - 1]]
|
|
61
|
-
} else if (range[0] > start && range[1] > end) {
|
|
62
|
-
// adjust the start of the range
|
|
63
|
-
return [[end + 1, range[1]]]
|
|
64
|
-
}
|
|
65
|
-
// otherwise, return the range as is
|
|
66
|
-
return [range]
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return foundRanges
|
|
72
|
-
}
|