@o1-labs/mina-archive-node-graphql 0.0.6

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.
Files changed (138) hide show
  1. package/README.md +321 -0
  2. package/build/benchmark/setup.js +32 -0
  3. package/build/benchmark/setup.js.map +1 -0
  4. package/build/src/blockchain/constants.js +2 -0
  5. package/build/src/blockchain/constants.js.map +1 -0
  6. package/build/src/blockchain/types.js +7 -0
  7. package/build/src/blockchain/types.js.map +1 -0
  8. package/build/src/blockchain/utils.js +39 -0
  9. package/build/src/blockchain/utils.js.map +1 -0
  10. package/build/src/consensus/mina-consensus.js +59 -0
  11. package/build/src/consensus/mina-consensus.js.map +1 -0
  12. package/build/src/context.js +10 -0
  13. package/build/src/context.js.map +1 -0
  14. package/build/src/db/archive-node-adapter/archive-node-adapter.interface.js +2 -0
  15. package/build/src/db/archive-node-adapter/archive-node-adapter.interface.js.map +1 -0
  16. package/build/src/db/archive-node-adapter/archive-node-adapter.js +47 -0
  17. package/build/src/db/archive-node-adapter/archive-node-adapter.js.map +1 -0
  18. package/build/src/db/sql/events-actions/queries.js +438 -0
  19. package/build/src/db/sql/events-actions/queries.js.map +1 -0
  20. package/build/src/db/sql/events-actions/types.js +2 -0
  21. package/build/src/db/sql/events-actions/types.js.map +1 -0
  22. package/build/src/errors/error.js +17 -0
  23. package/build/src/errors/error.js.map +1 -0
  24. package/build/src/index.js +27 -0
  25. package/build/src/index.js.map +1 -0
  26. package/build/src/resolvers-types.js +8 -0
  27. package/build/src/resolvers-types.js.map +1 -0
  28. package/build/src/resolvers.js +67 -0
  29. package/build/src/resolvers.js.map +1 -0
  30. package/build/src/server/plugins.js +39 -0
  31. package/build/src/server/plugins.js.map +1 -0
  32. package/build/src/server/server.js +25 -0
  33. package/build/src/server/server.js.map +1 -0
  34. package/build/src/services/actions-service/actions-service.interface.js +2 -0
  35. package/build/src/services/actions-service/actions-service.interface.js.map +1 -0
  36. package/build/src/services/actions-service/actions-service.js +94 -0
  37. package/build/src/services/actions-service/actions-service.js.map +1 -0
  38. package/build/src/services/blocks-service/blocks-service.interface.js +2 -0
  39. package/build/src/services/blocks-service/blocks-service.interface.js.map +1 -0
  40. package/build/src/services/blocks-service/blocks-service.js +263 -0
  41. package/build/src/services/blocks-service/blocks-service.js.map +1 -0
  42. package/build/src/services/data-adapters/database-row-adapters.js +116 -0
  43. package/build/src/services/data-adapters/database-row-adapters.js.map +1 -0
  44. package/build/src/services/events-service/events-service.interface.js +2 -0
  45. package/build/src/services/events-service/events-service.interface.js.map +1 -0
  46. package/build/src/services/events-service/events-service.js +64 -0
  47. package/build/src/services/events-service/events-service.js.map +1 -0
  48. package/build/src/services/network-service/network-service.interface.js +2 -0
  49. package/build/src/services/network-service/network-service.interface.js.map +1 -0
  50. package/build/src/services/network-service/network-service.js +31 -0
  51. package/build/src/services/network-service/network-service.js.map +1 -0
  52. package/build/src/tracing/jaeger-setup.js +39 -0
  53. package/build/src/tracing/jaeger-setup.js.map +1 -0
  54. package/build/src/tracing/jaeger-tracing.js +29 -0
  55. package/build/src/tracing/jaeger-tracing.js.map +1 -0
  56. package/build/src/tracing/tracer.js +31 -0
  57. package/build/src/tracing/tracer.js.map +1 -0
  58. package/build/tests/__mocks__/generate_mock_data.js +13 -0
  59. package/build/tests/__mocks__/generate_mock_data.js.map +1 -0
  60. package/build/tests/consensus/run-compare.js +40 -0
  61. package/build/tests/consensus/run-compare.js.map +1 -0
  62. package/build/tests/consensus/select-consensus-precomputed.js +80 -0
  63. package/build/tests/consensus/select-consensus-precomputed.js.map +1 -0
  64. package/build/tests/consensus/types.js +15 -0
  65. package/build/tests/consensus/types.js.map +1 -0
  66. package/build/tests/devnet-dump/devnet-dump.test.js +311 -0
  67. package/build/tests/devnet-dump/devnet-dump.test.js.map +1 -0
  68. package/build/tests/devnet-dump/setup.js +58 -0
  69. package/build/tests/devnet-dump/setup.js.map +1 -0
  70. package/build/tests/integration/integration.test.js +226 -0
  71. package/build/tests/integration/integration.test.js.map +1 -0
  72. package/build/tests/integration/setup.js +82 -0
  73. package/build/tests/integration/setup.js.map +1 -0
  74. package/build/tests/live-api/actions.test.js +4 -0
  75. package/build/tests/live-api/actions.test.js.map +1 -0
  76. package/build/tests/live-api/blocks.test.js +116 -0
  77. package/build/tests/live-api/blocks.test.js.map +1 -0
  78. package/build/tests/live-api/events.test.js +97 -0
  79. package/build/tests/live-api/events.test.js.map +1 -0
  80. package/build/tests/live-api/networkState.test.js +27 -0
  81. package/build/tests/live-api/networkState.test.js.map +1 -0
  82. package/build/tests/live-network/live-network.test.js +144 -0
  83. package/build/tests/live-network/live-network.test.js.map +1 -0
  84. package/build/tests/live-network/setup.js +206 -0
  85. package/build/tests/live-network/setup.js.map +1 -0
  86. package/build/tests/resolvers.test.js +475 -0
  87. package/build/tests/resolvers.test.js.map +1 -0
  88. package/build/tests/services/actions-service/actions-service.test.js +124 -0
  89. package/build/tests/services/actions-service/actions-service.test.js.map +1 -0
  90. package/build/tests/services/blocks-service/blocks-service.test.js +348 -0
  91. package/build/tests/services/blocks-service/blocks-service.test.js.map +1 -0
  92. package/build/tests/services/events-service/events-service.test.js +185 -0
  93. package/build/tests/services/events-service/events-service.test.js.map +1 -0
  94. package/build/tests/test-helpers.js +11 -0
  95. package/build/tests/test-helpers.js.map +1 -0
  96. package/build/tests/unit/blockchain-utils.test.js +106 -0
  97. package/build/tests/unit/blockchain-utils.test.js.map +1 -0
  98. package/build/tests/unit/consensus.test.js +154 -0
  99. package/build/tests/unit/consensus.test.js.map +1 -0
  100. package/build/tests/unit/error-handling.test.js +52 -0
  101. package/build/tests/unit/error-handling.test.js.map +1 -0
  102. package/build/tests/utils.test.js +313 -0
  103. package/build/tests/utils.test.js.map +1 -0
  104. package/build/zkapp/contract.js +144 -0
  105. package/build/zkapp/contract.js.map +1 -0
  106. package/build/zkapp/utils.js +174 -0
  107. package/build/zkapp/utils.js.map +1 -0
  108. package/package.json +85 -0
  109. package/schema.graphql +221 -0
  110. package/src/blockchain/constants.ts +2 -0
  111. package/src/blockchain/types.ts +121 -0
  112. package/src/blockchain/utils.ts +54 -0
  113. package/src/consensus/mina-consensus.ts +137 -0
  114. package/src/context.ts +18 -0
  115. package/src/db/archive-node-adapter/archive-node-adapter.interface.ts +23 -0
  116. package/src/db/archive-node-adapter/archive-node-adapter.ts +101 -0
  117. package/src/db/sql/events-actions/queries.ts +490 -0
  118. package/src/db/sql/events-actions/types.ts +208 -0
  119. package/src/envionment.d.ts +18 -0
  120. package/src/errors/error.ts +20 -0
  121. package/src/index.ts +31 -0
  122. package/src/resolvers-types.ts +754 -0
  123. package/src/resolvers.ts +102 -0
  124. package/src/server/plugins.ts +56 -0
  125. package/src/server/server.ts +30 -0
  126. package/src/services/actions-service/actions-service.interface.ts +9 -0
  127. package/src/services/actions-service/actions-service.ts +195 -0
  128. package/src/services/blocks-service/blocks-service.interface.ts +11 -0
  129. package/src/services/blocks-service/blocks-service.ts +407 -0
  130. package/src/services/data-adapters/database-row-adapters.ts +261 -0
  131. package/src/services/events-service/events-service.interface.ts +6 -0
  132. package/src/services/events-service/events-service.ts +118 -0
  133. package/src/services/network-service/network-service.interface.ts +5 -0
  134. package/src/services/network-service/network-service.ts +53 -0
  135. package/src/tracing/jaeger-setup.ts +65 -0
  136. package/src/tracing/jaeger-tracing.ts +44 -0
  137. package/src/tracing/tracer.ts +52 -0
  138. package/tsconfig.json +104 -0
@@ -0,0 +1,106 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { createBlockInfo, createTransactionInfo, createEvent, createAction, } from '../../src/blockchain/utils.js';
4
+ const baseRow = {
5
+ state_hash: 'state_hash_abc',
6
+ parent_hash: 'parent_hash_xyz',
7
+ height: '42',
8
+ global_slot_since_genesis: '100',
9
+ global_slot_since_hard_fork: '50',
10
+ authorization_kind: 'Proof',
11
+ timestamp: '1700000000000',
12
+ chain_status: 'canonical',
13
+ sequence_number: 3,
14
+ ledger_hash: 'ledger_hash_def',
15
+ distance_from_max_block_height: '10',
16
+ zkapp_account_updates_ids: [7, 8, 9],
17
+ status: 'applied',
18
+ memo: 'E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH',
19
+ hash: 'CkpZZMFyrBAnKidFoHxLiGbfeKKTFVFNJRhS3y3UUc5rVaoEMi8sZ',
20
+ last_vrf_output: 'AABBCCDD',
21
+ };
22
+ describe('Blockchain Utils', () => {
23
+ describe('createBlockInfo', () => {
24
+ test('maps all database row fields to BlockInfo', () => {
25
+ const result = createBlockInfo(baseRow);
26
+ assert.strictEqual(result.height, 42);
27
+ assert.strictEqual(result.stateHash, 'state_hash_abc');
28
+ assert.strictEqual(result.parentHash, 'parent_hash_xyz');
29
+ assert.strictEqual(result.ledgerHash, 'ledger_hash_def');
30
+ assert.strictEqual(result.chainStatus, 'canonical');
31
+ assert.strictEqual(result.timestamp, '1700000000000');
32
+ assert.strictEqual(result.globalSlotSinceHardfork, 50);
33
+ assert.strictEqual(result.globalSlotSinceGenesis, 100);
34
+ assert.strictEqual(result.distanceFromMaxBlockHeight, 10);
35
+ assert.strictEqual(result.lastVrfOutput, 'AABBCCDD');
36
+ });
37
+ test('converts string height to number', () => {
38
+ const row = { ...baseRow, height: '99999' };
39
+ assert.strictEqual(createBlockInfo(row).height, 99999);
40
+ });
41
+ test('handles zero height', () => {
42
+ const row = { ...baseRow, height: '0' };
43
+ assert.strictEqual(createBlockInfo(row).height, 0);
44
+ });
45
+ });
46
+ describe('createTransactionInfo', () => {
47
+ test('maps all database row fields to TransactionInfo', () => {
48
+ const result = createTransactionInfo(baseRow);
49
+ assert.strictEqual(result.status, 'applied');
50
+ assert.strictEqual(result.hash, 'CkpZZMFyrBAnKidFoHxLiGbfeKKTFVFNJRhS3y3UUc5rVaoEMi8sZ');
51
+ assert.strictEqual(result.memo, 'E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH');
52
+ assert.strictEqual(result.authorizationKind, 'Proof');
53
+ assert.strictEqual(result.sequenceNumber, 3);
54
+ assert.deepStrictEqual(result.zkappAccountUpdateIds, [7, 8, 9]);
55
+ });
56
+ test('preserves sequence_number as number', () => {
57
+ const row = { ...baseRow, sequence_number: 0 };
58
+ assert.strictEqual(createTransactionInfo(row).sequenceNumber, 0);
59
+ });
60
+ });
61
+ describe('createEvent', () => {
62
+ test('creates event with all properties', () => {
63
+ const txInfo = {
64
+ status: 'applied',
65
+ hash: 'tx_hash',
66
+ memo: 'memo',
67
+ authorizationKind: 'Proof',
68
+ sequenceNumber: 1,
69
+ zkappAccountUpdateIds: [1],
70
+ };
71
+ const event = createEvent('42', ['field1', 'field2'], txInfo);
72
+ assert.strictEqual(event.accountUpdateId, '42');
73
+ assert.deepStrictEqual(event.data, ['field1', 'field2']);
74
+ assert.strictEqual(event.transactionInfo, txInfo);
75
+ });
76
+ test('creates event with empty data', () => {
77
+ const txInfo = {
78
+ status: 'applied',
79
+ hash: 'h',
80
+ memo: '',
81
+ authorizationKind: 'None_given',
82
+ sequenceNumber: 0,
83
+ zkappAccountUpdateIds: [],
84
+ };
85
+ const event = createEvent('1', [], txInfo);
86
+ assert.deepStrictEqual(event.data, []);
87
+ });
88
+ });
89
+ describe('createAction', () => {
90
+ test('creates action with all properties', () => {
91
+ const txInfo = {
92
+ status: 'applied',
93
+ hash: 'tx_hash',
94
+ memo: 'memo',
95
+ authorizationKind: 'Signature',
96
+ sequenceNumber: 2,
97
+ zkappAccountUpdateIds: [10, 11],
98
+ };
99
+ const action = createAction('99', ['val1'], txInfo);
100
+ assert.strictEqual(action.accountUpdateId, '99');
101
+ assert.deepStrictEqual(action.data, ['val1']);
102
+ assert.strictEqual(action.transactionInfo, txInfo);
103
+ });
104
+ });
105
+ });
106
+ //# sourceMappingURL=blockchain-utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockchain-utils.test.js","sourceRoot":"","sources":["../../../tests/unit/blockchain-utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { select, getAllPredicate, filterBestTip, } from '../../src/consensus/mina-consensus.js';
4
+ function makeBlockInfo(overrides = {}) {
5
+ return {
6
+ height: 100,
7
+ stateHash: 'default_state_hash',
8
+ parentHash: 'default_parent_hash',
9
+ ledgerHash: 'default_ledger_hash',
10
+ chainStatus: 'canonical',
11
+ timestamp: '1700000000000',
12
+ globalSlotSinceHardfork: 100,
13
+ globalSlotSinceGenesis: 100,
14
+ distanceFromMaxBlockHeight: 0,
15
+ lastVrfOutput: 'AABBCCDD',
16
+ ...overrides,
17
+ };
18
+ }
19
+ function makeEntry(blockInfo) {
20
+ return { blockInfo, data: [] };
21
+ }
22
+ describe('Mina Consensus', () => {
23
+ describe('getAllPredicate', () => {
24
+ test('returns all elements matching predicate', () => {
25
+ const arr = [1, 2, 3, 4, 5];
26
+ const result = getAllPredicate(arr, (x) => x > 3);
27
+ assert.deepStrictEqual(result, [4, 5]);
28
+ });
29
+ test('returns empty array when nothing matches', () => {
30
+ const arr = [1, 2, 3];
31
+ const result = getAllPredicate(arr, (x) => x > 10);
32
+ assert.deepStrictEqual(result, []);
33
+ });
34
+ test('returns all elements when everything matches', () => {
35
+ const arr = [1, 2, 3];
36
+ const result = getAllPredicate(arr, () => true);
37
+ assert.deepStrictEqual(result, [1, 2, 3]);
38
+ });
39
+ test('handles empty array', () => {
40
+ const result = getAllPredicate([], () => true);
41
+ assert.deepStrictEqual(result, []);
42
+ });
43
+ });
44
+ describe('select', () => {
45
+ test('selects candidate when existing state hash is smaller', () => {
46
+ const existing = makeEntry(makeBlockInfo({ stateHash: 'aaa', lastVrfOutput: 'AA', height: 100 }));
47
+ const candidate = makeEntry(makeBlockInfo({ stateHash: 'zzz', lastVrfOutput: 'AA', height: 100 }));
48
+ const result = select(existing, candidate);
49
+ assert.strictEqual(result, candidate);
50
+ });
51
+ test('deterministically selects one of two blocks', () => {
52
+ const a = makeEntry(makeBlockInfo({
53
+ stateHash: '3NKabc',
54
+ lastVrfOutput: '1122334455',
55
+ height: 100,
56
+ }));
57
+ const b = makeEntry(makeBlockInfo({
58
+ stateHash: '3NKxyz',
59
+ lastVrfOutput: '5566778899',
60
+ height: 100,
61
+ }));
62
+ const result1 = select(a, b);
63
+ const result2 = select(a, b);
64
+ assert.strictEqual(result1, result2);
65
+ });
66
+ test('prefers longer chain when VRF and hash are equal', () => {
67
+ const shorter = makeEntry(makeBlockInfo({
68
+ stateHash: 'same_hash',
69
+ lastVrfOutput: 'AABB',
70
+ height: 100,
71
+ }));
72
+ const longer = makeEntry(makeBlockInfo({
73
+ stateHash: 'same_hash',
74
+ lastVrfOutput: 'AABB',
75
+ height: 200,
76
+ }));
77
+ const result = select(shorter, longer);
78
+ assert.strictEqual(result.blockInfo.height, 200);
79
+ });
80
+ });
81
+ describe('filterBestTip', () => {
82
+ test('does nothing when no blocks at distance 0', () => {
83
+ const data = [
84
+ makeEntry(makeBlockInfo({ distanceFromMaxBlockHeight: 1 })),
85
+ makeEntry(makeBlockInfo({ distanceFromMaxBlockHeight: 2 })),
86
+ ];
87
+ filterBestTip(data);
88
+ assert.strictEqual(data.length, 2);
89
+ });
90
+ test('does nothing when exactly one block at distance 0', () => {
91
+ const data = [
92
+ makeEntry(makeBlockInfo({ distanceFromMaxBlockHeight: 1 })),
93
+ makeEntry(makeBlockInfo({ distanceFromMaxBlockHeight: 0 })),
94
+ ];
95
+ filterBestTip(data);
96
+ assert.strictEqual(data.length, 2);
97
+ });
98
+ test('reduces multiple blocks at distance 0 to one', () => {
99
+ const data = [
100
+ makeEntry(makeBlockInfo({
101
+ distanceFromMaxBlockHeight: 5,
102
+ height: 95,
103
+ stateHash: 'older',
104
+ })),
105
+ makeEntry(makeBlockInfo({
106
+ distanceFromMaxBlockHeight: 0,
107
+ height: 100,
108
+ stateHash: 'tip_a',
109
+ lastVrfOutput: 'AA11',
110
+ })),
111
+ makeEntry(makeBlockInfo({
112
+ distanceFromMaxBlockHeight: 0,
113
+ height: 100,
114
+ stateHash: 'tip_b',
115
+ lastVrfOutput: 'BB22',
116
+ })),
117
+ ];
118
+ filterBestTip(data);
119
+ assert.strictEqual(data.length, 2);
120
+ assert.strictEqual(data[0].blockInfo.height, 95);
121
+ assert.strictEqual(data[1].blockInfo.distanceFromMaxBlockHeight, 0);
122
+ });
123
+ test('reduces three blocks at distance 0 to one', () => {
124
+ const data = [
125
+ makeEntry(makeBlockInfo({
126
+ distanceFromMaxBlockHeight: 0,
127
+ stateHash: 'a',
128
+ lastVrfOutput: 'AA',
129
+ height: 100,
130
+ })),
131
+ makeEntry(makeBlockInfo({
132
+ distanceFromMaxBlockHeight: 0,
133
+ stateHash: 'b',
134
+ lastVrfOutput: 'BB',
135
+ height: 100,
136
+ })),
137
+ makeEntry(makeBlockInfo({
138
+ distanceFromMaxBlockHeight: 0,
139
+ stateHash: 'c',
140
+ lastVrfOutput: 'CC',
141
+ height: 100,
142
+ })),
143
+ ];
144
+ filterBestTip(data);
145
+ assert.strictEqual(data.length, 1);
146
+ });
147
+ test('handles empty array', () => {
148
+ const data = [];
149
+ filterBestTip(data);
150
+ assert.strictEqual(data.length, 0);
151
+ });
152
+ });
153
+ });
154
+ //# sourceMappingURL=consensus.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consensus.test.js","sourceRoot":"","sources":["../../../tests/unit/consensus.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { GraphQLError } from 'graphql';
4
+ import { throwGraphQLError, throwActionStateError, throwBlockRangeError, } from '../../src/errors/error.js';
5
+ describe('Error Handling', () => {
6
+ describe('throwGraphQLError', () => {
7
+ test('throws GraphQLError with message', () => {
8
+ assert.throws(() => throwGraphQLError('test message'), (err) => {
9
+ assert.ok(err instanceof GraphQLError);
10
+ assert.strictEqual(err.message, 'test message');
11
+ return true;
12
+ });
13
+ });
14
+ test('throws GraphQLError with code and status', () => {
15
+ assert.throws(() => throwGraphQLError('msg', 'MY_CODE', 422), (err) => {
16
+ assert.strictEqual(err.extensions.code, 'MY_CODE');
17
+ assert.strictEqual(err.extensions.status, 422);
18
+ return true;
19
+ });
20
+ });
21
+ test('throws with undefined code and status when not provided', () => {
22
+ assert.throws(() => throwGraphQLError('msg'), (err) => {
23
+ assert.strictEqual(err.extensions.code, undefined);
24
+ assert.strictEqual(err.extensions.status, undefined);
25
+ return true;
26
+ });
27
+ });
28
+ });
29
+ describe('throwActionStateError', () => {
30
+ test('throws with ACTION_STATE_NOT_FOUND code and 400 status', () => {
31
+ assert.throws(() => throwActionStateError('state xyz does not exist'), (err) => {
32
+ assert.ok(err instanceof GraphQLError);
33
+ assert.strictEqual(err.message, 'state xyz does not exist');
34
+ assert.strictEqual(err.extensions.code, 'ACTION_STATE_NOT_FOUND');
35
+ assert.strictEqual(err.extensions.status, 400);
36
+ return true;
37
+ });
38
+ });
39
+ });
40
+ describe('throwBlockRangeError', () => {
41
+ test('throws with BLOCK_RANGE_ERROR code and 400 status', () => {
42
+ assert.throws(() => throwBlockRangeError('range too large'), (err) => {
43
+ assert.ok(err instanceof GraphQLError);
44
+ assert.strictEqual(err.message, 'range too large');
45
+ assert.strictEqual(err.extensions.code, 'BLOCK_RANGE_ERROR');
46
+ assert.strictEqual(err.extensions.status, 400);
47
+ return true;
48
+ });
49
+ });
50
+ });
51
+ });
52
+ //# sourceMappingURL=error-handling.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handling.test.js","sourceRoot":"","sources":["../../../tests/unit/error-handling.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,313 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { partitionBlocks, getElementIdFieldValues, removeRedundantEmittedFields, mapActionOrEvent, sortAndFilterBlocks, } from '../src/services/data-adapters/database-row-adapters.js';
4
+ describe('utils', () => {
5
+ describe('partitionBlocks', () => {
6
+ test('should partition rows by block hash and transaction hash', () => {
7
+ const rows = [
8
+ { state_hash: 'state_hash_1', hash: 'hash_1' },
9
+ { state_hash: 'state_hash_1', hash: 'hash_2' },
10
+ { state_hash: 'state_hash_2', hash: 'hash_3' },
11
+ { state_hash: 'state_hash_2', hash: 'hash_4' },
12
+ ];
13
+ const result = partitionBlocks(rows);
14
+ const stateHash1 = result.get('state_hash_1');
15
+ const stateHash2 = result.get('state_hash_2');
16
+ assert(stateHash1);
17
+ assert(stateHash2);
18
+ assert.strictEqual(stateHash1.size, 2);
19
+ assert.strictEqual(stateHash2.size, 2);
20
+ });
21
+ test('should return empty array if no rows', () => {
22
+ const rows = [];
23
+ const result = partitionBlocks(rows);
24
+ assert.strictEqual(result.size, 0);
25
+ });
26
+ test('should accumulate multiple rows for the same transaction', () => {
27
+ const rows = [
28
+ { state_hash: 'b1', hash: 'tx1', field_id: 1 },
29
+ { state_hash: 'b1', hash: 'tx1', field_id: 2 },
30
+ ];
31
+ const result = partitionBlocks(rows);
32
+ assert.strictEqual(result.size, 1);
33
+ assert.strictEqual(result.get('b1').get('tx1').length, 2);
34
+ });
35
+ });
36
+ describe('getElementIdFieldValues', () => {
37
+ test('should map id to field for each row', () => {
38
+ const rows = [
39
+ { field_id: 1, field_value: 'field_1' },
40
+ { field_id: 2, field_value: 'field_2' },
41
+ { field_id: 3, field_value: 'field_3' },
42
+ ];
43
+ const result = getElementIdFieldValues(rows);
44
+ assert.equal(result.get('1'), 'field_1');
45
+ assert.equal(result.get('2'), 'field_2');
46
+ assert.equal(result.get('3'), 'field_3');
47
+ });
48
+ test('should handle empty rows', () => {
49
+ const rows = [];
50
+ const result = getElementIdFieldValues(rows);
51
+ assert(result.size === 0);
52
+ });
53
+ test('later row should overwrite earlier for same field_id', () => {
54
+ const rows = [
55
+ { field_id: 1, field_value: 'first' },
56
+ { field_id: 1, field_value: 'second' },
57
+ ];
58
+ const result = getElementIdFieldValues(rows);
59
+ assert.strictEqual(result.size, 1);
60
+ assert.strictEqual(result.get('1'), 'second');
61
+ });
62
+ });
63
+ describe('removeRedundantEmittedFields', () => {
64
+ test('should remove duplicate rows based on unique event ID', () => {
65
+ const rows = [
66
+ {
67
+ event_field_elements_id: 1,
68
+ event_element_ids: [1, 2],
69
+ zkapp_account_update_id: 10,
70
+ zkapp_account_updates_ids: [10, 12],
71
+ },
72
+ {
73
+ event_field_elements_id: 1,
74
+ event_element_ids: [1, 2],
75
+ zkapp_account_update_id: 10,
76
+ zkapp_account_updates_ids: [10, 12],
77
+ },
78
+ {
79
+ event_field_elements_id: 2,
80
+ event_element_ids: [1, 2],
81
+ zkapp_account_update_id: 12,
82
+ zkapp_account_updates_ids: [10, 12],
83
+ },
84
+ ];
85
+ const result = removeRedundantEmittedFields(rows);
86
+ assert.strictEqual(result.length, 2);
87
+ });
88
+ test('should throw an error for a missing matching account update', () => {
89
+ const rows = [
90
+ {
91
+ event_field_elements_id: 1,
92
+ event_field_element_ids: [1, 2],
93
+ zkapp_account_update_id: 99,
94
+ zkapp_account_updates_ids: [10, 11],
95
+ },
96
+ ];
97
+ assert.throws(() => removeRedundantEmittedFields(rows)),
98
+ /No matching account update found/;
99
+ });
100
+ test('should keep rows for different events in same account update', () => {
101
+ const rows = [
102
+ {
103
+ event_field_elements_id: 100,
104
+ event_element_ids: [100, 101],
105
+ zkapp_account_update_id: 10,
106
+ zkapp_account_updates_ids: [10],
107
+ },
108
+ {
109
+ event_field_elements_id: 101,
110
+ event_element_ids: [100, 101],
111
+ zkapp_account_update_id: 10,
112
+ zkapp_account_updates_ids: [10],
113
+ },
114
+ ];
115
+ const result = removeRedundantEmittedFields(rows);
116
+ assert.strictEqual(result.length, 2);
117
+ });
118
+ test('should preserve ordering by account update index', () => {
119
+ const rows = [
120
+ {
121
+ event_field_elements_id: 200,
122
+ event_element_ids: [200],
123
+ zkapp_account_update_id: 10,
124
+ zkapp_account_updates_ids: [20, 10],
125
+ },
126
+ {
127
+ event_field_elements_id: 100,
128
+ event_element_ids: [100],
129
+ zkapp_account_update_id: 20,
130
+ zkapp_account_updates_ids: [20, 10],
131
+ },
132
+ ];
133
+ const result = removeRedundantEmittedFields(rows);
134
+ assert.strictEqual(result.length, 2);
135
+ assert.strictEqual(result[0].zkapp_account_update_id, 20);
136
+ assert.strictEqual(result[1].zkapp_account_update_id, 10);
137
+ });
138
+ test('should handle multiple events per account update with correct ordering', () => {
139
+ const rows = [
140
+ {
141
+ event_field_elements_id: 102,
142
+ event_element_ids: [100, 101, 102],
143
+ zkapp_account_update_id: 10,
144
+ zkapp_account_updates_ids: [10],
145
+ },
146
+ {
147
+ event_field_elements_id: 100,
148
+ event_element_ids: [100, 101, 102],
149
+ zkapp_account_update_id: 10,
150
+ zkapp_account_updates_ids: [10],
151
+ },
152
+ {
153
+ event_field_elements_id: 101,
154
+ event_element_ids: [100, 101, 102],
155
+ zkapp_account_update_id: 10,
156
+ zkapp_account_updates_ids: [10],
157
+ },
158
+ ];
159
+ const result = removeRedundantEmittedFields(rows);
160
+ assert.strictEqual(result.length, 3);
161
+ assert.strictEqual(result[0].event_field_elements_id, 100);
162
+ assert.strictEqual(result[1].event_field_elements_id, 101);
163
+ assert.strictEqual(result[2].event_field_elements_id, 102);
164
+ });
165
+ describe('mapActionOrEvent', () => {
166
+ const mockElementIdFieldValues = new Map();
167
+ mockElementIdFieldValues.set('1', 'value1');
168
+ mockElementIdFieldValues.set('2', 'value2');
169
+ describe('when kind is "event"', () => {
170
+ test('map rows to an array of events', () => {
171
+ const rows = [
172
+ {
173
+ zkapp_account_update_id: 1,
174
+ event_field_element_ids: [1, 2],
175
+ },
176
+ ];
177
+ const result = mapActionOrEvent('event', rows, mockElementIdFieldValues);
178
+ assert(result[0].data);
179
+ assert(result[0].transactionInfo);
180
+ });
181
+ test('should map rows with correct data values', () => {
182
+ const rows = [
183
+ {
184
+ zkapp_account_update_id: 5,
185
+ event_field_element_ids: [1, 2],
186
+ status: 'applied',
187
+ hash: 'tx_abc',
188
+ memo: 'test memo',
189
+ authorization_kind: 'Proof',
190
+ sequence_number: 3,
191
+ zkapp_account_updates_ids: [5, 6],
192
+ },
193
+ ];
194
+ const result = mapActionOrEvent('event', rows, mockElementIdFieldValues);
195
+ assert.deepStrictEqual(result[0].data, ['value1', 'value2']);
196
+ assert.strictEqual(result[0].transactionInfo.hash, 'tx_abc');
197
+ assert.strictEqual(result[0].transactionInfo.status, 'applied');
198
+ assert.strictEqual(result[0].transactionInfo.authorizationKind, 'Proof');
199
+ assert.strictEqual(result[0].transactionInfo.sequenceNumber, 3);
200
+ });
201
+ });
202
+ describe('when kind is "action"', () => {
203
+ test('should map rows to an array of actions', () => {
204
+ const rows = [
205
+ {
206
+ event_field_element_ids: [1, 2],
207
+ zkapp_account_update_id: 123,
208
+ account_update_event_id: 456,
209
+ },
210
+ ];
211
+ const result = mapActionOrEvent('action', rows, mockElementIdFieldValues);
212
+ assert(result[0].data);
213
+ assert(result[0].transactionInfo);
214
+ assert(result[0].accountUpdateId);
215
+ });
216
+ });
217
+ test('should skip field ids not found in the map', () => {
218
+ const fieldValues = new Map([
219
+ ['1', 'value1'],
220
+ ['2', 'value2'],
221
+ ]);
222
+ const rows = [
223
+ { zkapp_account_update_id: 1, event_field_element_ids: [1, 999, 2] },
224
+ ];
225
+ const result = mapActionOrEvent('event', rows, fieldValues);
226
+ assert.deepStrictEqual(result[0].data, ['value1', 'value2']);
227
+ });
228
+ test('should handle empty element ids', () => {
229
+ const rows = [
230
+ { zkapp_account_update_id: 1, event_field_element_ids: [] },
231
+ ];
232
+ const result = mapActionOrEvent('event', rows, mockElementIdFieldValues);
233
+ assert.deepStrictEqual(result[0].data, []);
234
+ });
235
+ test('should map multiple rows', () => {
236
+ const rows = [
237
+ { zkapp_account_update_id: 1, event_field_element_ids: [1], hash: 'tx1' },
238
+ { zkapp_account_update_id: 2, event_field_element_ids: [1, 2], hash: 'tx2' },
239
+ ];
240
+ const result = mapActionOrEvent('event', rows, mockElementIdFieldValues);
241
+ assert.strictEqual(result.length, 2);
242
+ assert.deepStrictEqual(result[0].data, ['value1']);
243
+ assert.deepStrictEqual(result[1].data, ['value1', 'value2']);
244
+ });
245
+ });
246
+ });
247
+ describe('sortAndFilterBlocks', () => {
248
+ function makeBlockEntry(height, timestamp, distanceFromMax, stateHash = 'sh' + height, lastVrfOutput = 'AA') {
249
+ return {
250
+ blockInfo: {
251
+ height,
252
+ stateHash,
253
+ parentHash: 'ph',
254
+ ledgerHash: 'lh',
255
+ chainStatus: 'canonical',
256
+ timestamp,
257
+ globalSlotSinceHardfork: height,
258
+ globalSlotSinceGenesis: height,
259
+ distanceFromMaxBlockHeight: distanceFromMax,
260
+ lastVrfOutput,
261
+ },
262
+ eventData: [],
263
+ };
264
+ }
265
+ test('should sort blocks by height ascending', () => {
266
+ const data = [
267
+ makeBlockEntry(300, '1000', 1),
268
+ makeBlockEntry(100, '1000', 3),
269
+ makeBlockEntry(200, '1000', 2),
270
+ ];
271
+ sortAndFilterBlocks(data);
272
+ assert.strictEqual(data[0].blockInfo.height, 100);
273
+ assert.strictEqual(data[1].blockInfo.height, 200);
274
+ assert.strictEqual(data[2].blockInfo.height, 300);
275
+ });
276
+ test('should use timestamp as tiebreaker for equal heights', () => {
277
+ const data = [
278
+ makeBlockEntry(100, '3000', 1),
279
+ makeBlockEntry(100, '1000', 1),
280
+ makeBlockEntry(100, '2000', 1),
281
+ ];
282
+ sortAndFilterBlocks(data);
283
+ assert.strictEqual(data[0].blockInfo.timestamp, '1000');
284
+ assert.strictEqual(data[1].blockInfo.timestamp, '2000');
285
+ assert.strictEqual(data[2].blockInfo.timestamp, '3000');
286
+ });
287
+ test('should filter best tip when multiple blocks at distance 0', () => {
288
+ const data = [
289
+ makeBlockEntry(100, '1000', 5),
290
+ makeBlockEntry(200, '2000', 0, 'hash_a', 'AA'),
291
+ makeBlockEntry(200, '2000', 0, 'hash_b', 'BB'),
292
+ ];
293
+ sortAndFilterBlocks(data);
294
+ assert.strictEqual(data.length, 2);
295
+ assert.strictEqual(data[0].blockInfo.height, 100);
296
+ assert.strictEqual(data[1].blockInfo.distanceFromMaxBlockHeight, 0);
297
+ });
298
+ test('should not filter when only one block at distance 0', () => {
299
+ const data = [
300
+ makeBlockEntry(100, '1000', 5),
301
+ makeBlockEntry(200, '2000', 0),
302
+ ];
303
+ sortAndFilterBlocks(data);
304
+ assert.strictEqual(data.length, 2);
305
+ });
306
+ test('should handle empty array', () => {
307
+ const data = [];
308
+ sortAndFilterBlocks(data);
309
+ assert.strictEqual(data.length, 0);
310
+ });
311
+ });
312
+ });
313
+ //# sourceMappingURL=utils.test.js.map