@tradelayerprotocol/tradelayer 1.9.1

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 (249) hide show
  1. package/.claude/settings.local.json +13 -0
  2. package/.claude/skills/tl-algo/SKILL.md +255 -0
  3. package/.gitattributes +2 -0
  4. package/.github/workflows/publish.yaml +26 -0
  5. package/4mm.js +163 -0
  6. package/LICENSE +21 -0
  7. package/NPMSwapRefactor.zip +0 -0
  8. package/README.md +217 -0
  9. package/address.sh +26 -0
  10. package/algoAPI.js +581 -0
  11. package/analyzepsbt.js +92 -0
  12. package/apiEx.js +99 -0
  13. package/bb_hyperscalper.js +290 -0
  14. package/bbo_demo.js +111 -0
  15. package/buyer.js +622 -0
  16. package/client.js +50 -0
  17. package/createTxTest.js +26 -0
  18. package/createWallet.js +75 -0
  19. package/daytrader.js +531 -0
  20. package/decodeTest.js +69 -0
  21. package/fundingManager.js +144 -0
  22. package/index.js +4 -0
  23. package/listener.js +27 -0
  24. package/litecoreTxBuilder.js +1128 -0
  25. package/mmEx.js +356 -0
  26. package/networks.js +51 -0
  27. package/orderbook.js +200 -0
  28. package/package.json +34 -0
  29. package/perTradeQueue.js +36 -0
  30. package/projectsTLNPMTLNPM/package-lock.json +162 -0
  31. package/projectsTLNPMTLNPM/package.json +5 -0
  32. package/quick.js +32 -0
  33. package/quickFut.js +37 -0
  34. package/quickSell.js +37 -0
  35. package/relayerClient.js +117 -0
  36. package/run4mm.js +80 -0
  37. package/run_bbo_tracker.js +241 -0
  38. package/seller.js +443 -0
  39. package/session.js +45 -0
  40. package/setup-lin-ltc.sh +139 -0
  41. package/setup-lin.sh +203 -0
  42. package/setup-win-ltc.bat +108 -0
  43. package/setup-win.bat +167 -0
  44. package/spam_screamer_futures.js +222 -0
  45. package/tradelayer.js/.gitattributes +2 -0
  46. package/tradelayer.js/README.md +2 -0
  47. package/tradelayer.js/oldTests/activationTest.js +6 -0
  48. package/tradelayer.js/oldTests/base58.test.js +23 -0
  49. package/tradelayer.js/oldTests/base64Decode.test.js +16 -0
  50. package/tradelayer.js/oldTests/blocksRefactor.js +140 -0
  51. package/tradelayer.js/oldTests/checkVestBalance.js +25 -0
  52. package/tradelayer.js/oldTests/consensusHashProto.js +151 -0
  53. package/tradelayer.js/oldTests/contractOrderbook.js +243 -0
  54. package/tradelayer.js/oldTests/createPayload.js +0 -0
  55. package/tradelayer.js/oldTests/createTestnetAddr.js +43 -0
  56. package/tradelayer.js/oldTests/decode.js +205 -0
  57. package/tradelayer.js/oldTests/decodeTest.js +50 -0
  58. package/tradelayer.js/oldTests/displayTallyMap.js +19 -0
  59. package/tradelayer.js/oldTests/encodeDecode.js +340 -0
  60. package/tradelayer.js/oldTests/expressTest.js +29 -0
  61. package/tradelayer.js/oldTests/extractBlocksVanilla.js +214 -0
  62. package/tradelayer.js/oldTests/extractBlocksVanillaa.js +179 -0
  63. package/tradelayer.js/oldTests/extractPubkeyTest.js +60 -0
  64. package/tradelayer.js/oldTests/fillInputCacheProto.js +111 -0
  65. package/tradelayer.js/oldTests/getRawTxTest.js +22 -0
  66. package/tradelayer.js/oldTests/indexTest.js +26 -0
  67. package/tradelayer.js/oldTests/initTokensTest.js +32 -0
  68. package/tradelayer.js/oldTests/interfaceChild.js +129 -0
  69. package/tradelayer.js/oldTests/listenerChild.js +112 -0
  70. package/tradelayer.js/oldTests/opdecode.js +26 -0
  71. package/tradelayer.js/oldTests/options.js +79 -0
  72. package/tradelayer.js/oldTests/optxtest.js +116 -0
  73. package/tradelayer.js/oldTests/optxtest1.js +64 -0
  74. package/tradelayer.js/oldTests/oracle.test.js +32 -0
  75. package/tradelayer.js/oldTests/orderbook.test.js +36 -0
  76. package/tradelayer.js/oldTests/parsing.js +93 -0
  77. package/tradelayer.js/oldTests/payload.js +13 -0
  78. package/tradelayer.js/oldTests/persistenceUnitTest.js +23 -0
  79. package/tradelayer.js/oldTests/property.test.js +53 -0
  80. package/tradelayer.js/oldTests/propertyLevel.js +75 -0
  81. package/tradelayer.js/oldTests/propertyTest.js +32 -0
  82. package/tradelayer.js/oldTests/queryAddressTest.js +17 -0
  83. package/tradelayer.js/oldTests/salter.js +14 -0
  84. package/tradelayer.js/oldTests/tally.js +81 -0
  85. package/tradelayer.js/oldTests/tally.test.js +48 -0
  86. package/tradelayer.js/oldTests/tally2.js +124 -0
  87. package/tradelayer.js/oldTests/tally3.js +142 -0
  88. package/tradelayer.js/oldTests/tallyDiag.js +38 -0
  89. package/tradelayer.js/oldTests/testGetRaw.js +40 -0
  90. package/tradelayer.js/oldTests/testHexConvert.js +47 -0
  91. package/tradelayer.js/oldTests/testNewEncoding.js +96 -0
  92. package/tradelayer.js/oldTests/testNewEncoding2.js +113 -0
  93. package/tradelayer.js/oldTests/testNewEncoding3 +112 -0
  94. package/tradelayer.js/oldTests/testNewEncoding3.js +168 -0
  95. package/tradelayer.js/oldTests/testOPReturn.js +102 -0
  96. package/tradelayer.js/oldTests/testPayload.js +23 -0
  97. package/tradelayer.js/oldTests/testRaw.js +50 -0
  98. package/tradelayer.js/oldTests/testSendTooMuch.js +20 -0
  99. package/tradelayer.js/oldTests/testTxBuild +28 -0
  100. package/tradelayer.js/oldTests/testTxBuild.js +42 -0
  101. package/tradelayer.js/oldTests/tokenOrderbook.js +243 -0
  102. package/tradelayer.js/oldTests/txUtilsA.js +515 -0
  103. package/tradelayer.js/oldTests/validityUnitTest.js +53 -0
  104. package/tradelayer.js/oldTests/vaults.js +72 -0
  105. package/tradelayer.js/oldTests/volumeIndex.js +117 -0
  106. package/tradelayer.js/oldTests/volumeIndex2.js +88 -0
  107. package/tradelayer.js/output_base64.txt +1 -0
  108. package/tradelayer.js/package-lock.json +9967 -0
  109. package/tradelayer.js/package.json +61 -0
  110. package/tradelayer.js/server/index.js +88 -0
  111. package/tradelayer.js/server/litecoind.exe +0 -0
  112. package/tradelayer.js/src/activation.js +303 -0
  113. package/tradelayer.js/src/adjuster.js +77 -0
  114. package/tradelayer.js/src/amm.js +400 -0
  115. package/tradelayer.js/src/base256.js +55 -0
  116. package/tradelayer.js/src/base94.js +79 -0
  117. package/tradelayer.js/src/channels.js +1163 -0
  118. package/tradelayer.js/src/clearing.js +3109 -0
  119. package/tradelayer.js/src/clearlist.js +364 -0
  120. package/tradelayer.js/src/client.js +295 -0
  121. package/tradelayer.js/src/consensus.js +613 -0
  122. package/tradelayer.js/src/contractRegistry.js +964 -0
  123. package/tradelayer.js/src/db.js +89 -0
  124. package/tradelayer.js/src/init.js +24 -0
  125. package/tradelayer.js/src/insurance.js +347 -0
  126. package/tradelayer.js/src/interface.js +218 -0
  127. package/tradelayer.js/src/interfaceExpress.js +178 -0
  128. package/tradelayer.js/src/iou.js +509 -0
  129. package/tradelayer.js/src/listener.js +226 -0
  130. package/tradelayer.js/src/logic.js +1702 -0
  131. package/tradelayer.js/src/main.js +927 -0
  132. package/tradelayer.js/src/marginMap.js +2165 -0
  133. package/tradelayer.js/src/options.js +126 -0
  134. package/tradelayer.js/src/oracle.js +394 -0
  135. package/tradelayer.js/src/orderbook.js +4123 -0
  136. package/tradelayer.js/src/persistence.js +554 -0
  137. package/tradelayer.js/src/property.js +411 -0
  138. package/tradelayer.js/src/reOrg.js +41 -0
  139. package/tradelayer.js/src/scaling.js +145 -0
  140. package/tradelayer.js/src/tally.js +1275 -0
  141. package/tradelayer.js/src/tradeHistoryManager.js +552 -0
  142. package/tradelayer.js/src/txDecoder.js +584 -0
  143. package/tradelayer.js/src/txEncoder.js +610 -0
  144. package/tradelayer.js/src/txIndex.js +502 -0
  145. package/tradelayer.js/src/txUtils.js +1392 -0
  146. package/tradelayer.js/src/types.js +429 -0
  147. package/tradelayer.js/src/validity.js +3077 -0
  148. package/tradelayer.js/src/vaults.js +430 -0
  149. package/tradelayer.js/src/vesting.js +491 -0
  150. package/tradelayer.js/src/volumeIndex.js +618 -0
  151. package/tradelayer.js/src/walletInterface.js +220 -0
  152. package/tradelayer.js/src/walletListener.js +665 -0
  153. package/tradelayer.js/tests/256decode.js +82 -0
  154. package/tradelayer.js/tests/UTXOracle.js +205 -0
  155. package/tradelayer.js/tests/base94test.js +23 -0
  156. package/tradelayer.js/tests/cancelTxTest.js +62 -0
  157. package/tradelayer.js/tests/contractInterfaceTest.js +48 -0
  158. package/tradelayer.js/tests/decimalTest.js +65 -0
  159. package/tradelayer.js/tests/decoderTest.js +100 -0
  160. package/tradelayer.js/tests/deltaCount.js +47 -0
  161. package/tradelayer.js/tests/deltaCount2.js +60 -0
  162. package/tradelayer.js/tests/interfaceTest.js +37 -0
  163. package/tradelayer.js/tests/mainTest.js +53 -0
  164. package/tradelayer.js/tests/makeActivationTest.js +24 -0
  165. package/tradelayer.js/tests/maxHeightTest.js +49 -0
  166. package/tradelayer.js/tests/reverseHash.js +72 -0
  167. package/tradelayer.js/tests/sensitiveConsoleOutput.txt +267 -0
  168. package/tradelayer.js/tests/tallyTest.js +40 -0
  169. package/tradelayer.js/tests/testBuybacks.js +46 -0
  170. package/tradelayer.js/tests/testCodeHash.js +49 -0
  171. package/tradelayer.js/tests/testConsensusHash.js +91 -0
  172. package/tradelayer.js/tests/testDecode.js +30 -0
  173. package/tradelayer.js/tests/testEncodingLengths.js +129 -0
  174. package/tradelayer.js/tests/testGetTx +32 -0
  175. package/tradelayer.js/tests/testGetTx.js +32 -0
  176. package/tradelayer.js/tests/testHexHash.js +32 -0
  177. package/tradelayer.js/tests/testIndexHash.js +35 -0
  178. package/tradelayer.js/tests/testInitContracts.js +38 -0
  179. package/tradelayer.js/tests/testMaxConsensus.js +12 -0
  180. package/tradelayer.js/tests/testMaxSynth.js +44 -0
  181. package/tradelayer.js/tests/testMint.js +21 -0
  182. package/tradelayer.js/tests/testNetwork.js +33 -0
  183. package/tradelayer.js/tests/testOrderbookLoad.js +62 -0
  184. package/tradelayer.js/tests/testRebates.js +32 -0
  185. package/tradelayer.js/tests/testRedeem.js +22 -0
  186. package/tradelayer.js/tests/testTokenTrade.js +39 -0
  187. package/tradelayer.js/tests/testTxBuild.js +42 -0
  188. package/tradelayer.js/tests/testUTXOTrade.js +27 -0
  189. package/tradelayer.js/tests/tokenTradeHistory.js +27 -0
  190. package/tradelayer.js/tests/tradeFutures.js +40 -0
  191. package/tradelayer.js/tests/tradeHistoryExample.js +35 -0
  192. package/tradelayer.js/tests/tradeHistoryLoad.js +15 -0
  193. package/tradelayer.js/tests/txScanTest.js +134 -0
  194. package/tradelayer.js/tests/validateTest.js +136 -0
  195. package/tradelayer.js/tests/vestingTest.js +37 -0
  196. package/tradelayer.js/utils/activateMainnet.js +59 -0
  197. package/tradelayer.js/utils/activateMainnetDoge.js +63 -0
  198. package/tradelayer.js/utils/autocompactdb.js +23 -0
  199. package/tradelayer.js/utils/base64toHex.js +32 -0
  200. package/tradelayer.js/utils/broadcastDoge.js +38 -0
  201. package/tradelayer.js/utils/calcRedeem.js +19 -0
  202. package/tradelayer.js/utils/checkNetwork.js +27 -0
  203. package/tradelayer.js/utils/createAddress.js +48 -0
  204. package/tradelayer.js/utils/createAttestation.js +133 -0
  205. package/tradelayer.js/utils/createContract.js +118 -0
  206. package/tradelayer.js/utils/createOracle.js +94 -0
  207. package/tradelayer.js/utils/createwallet.js +20 -0
  208. package/tradelayer.js/utils/crossFuturesTrades.js +57 -0
  209. package/tradelayer.js/utils/crossTokenTrades.js +62 -0
  210. package/tradelayer.js/utils/dumpPriv.js +29 -0
  211. package/tradelayer.js/utils/generateChannel.js +34 -0
  212. package/tradelayer.js/utils/getInfo.js +21 -0
  213. package/tradelayer.js/utils/hardWipe.js +20 -0
  214. package/tradelayer.js/utils/hexTo64.js +16 -0
  215. package/tradelayer.js/utils/importAddress.js +28 -0
  216. package/tradelayer.js/utils/importpriv.js +20 -0
  217. package/tradelayer.js/utils/issueOracleContract.js +67 -0
  218. package/tradelayer.js/utils/issueTokens.js +41 -0
  219. package/tradelayer.js/utils/listunspent.js +66 -0
  220. package/tradelayer.js/utils/litecoinClient.js +30 -0
  221. package/tradelayer.js/utils/loadwallet.js +20 -0
  222. package/tradelayer.js/utils/publishOracle.js +113 -0
  223. package/tradelayer.js/utils/sendActivation.js +21 -0
  224. package/tradelayer.js/utils/sendChannelContractTrade.js +34 -0
  225. package/tradelayer.js/utils/sendChannelTokenTrade.js +34 -0
  226. package/tradelayer.js/utils/sendCommit.js +24 -0
  227. package/tradelayer.js/utils/sendDoge.js +62 -0
  228. package/tradelayer.js/utils/sendDogeMain.js +67 -0
  229. package/tradelayer.js/utils/sendDogeTx.js +46 -0
  230. package/tradelayer.js/utils/sendLTC.js +63 -0
  231. package/tradelayer.js/utils/sendMainnet.js +62 -0
  232. package/tradelayer.js/utils/sendTransfer.js +19 -0
  233. package/tradelayer.js/utils/sendVestTest.js +88 -0
  234. package/tradelayer.js/utils/sendWithdrawal.js +26 -0
  235. package/tradelayer.js/utils/simpleStart.js +8 -0
  236. package/tradelayer.js/utils/startStop.js +27 -0
  237. package/tradelayer.js/utils/structuredTrades.js +136 -0
  238. package/tradelayer.js/utils/verifySignature.js +90 -0
  239. package/tradelayer.js/utils/verifyWitnessAndScriptPubkey.js +41 -0
  240. package/tradelayer.js/utils/walletCache.js +172 -0
  241. package/tradelayer.js/utils/walletContractInterface.js +48 -0
  242. package/tradelayer.js/utils/walletFetchTxs.js +66 -0
  243. package/tradelayer.js/utils/walletUtils.js +97 -0
  244. package/tradelayer.js/utils/wipeDB.js +55 -0
  245. package/tradelayer.js/utils/wipeDBNotTx.js +50 -0
  246. package/txEncoder.js +529 -0
  247. package/utility.js +28 -0
  248. package/verifymessage.js +38 -0
  249. package/ws-transport.js +311 -0
@@ -0,0 +1,927 @@
1
+ // Define a global shutdown event
2
+ const EventEmitter = require('events');
3
+ class ShutdownEmitter extends EventEmitter {}
4
+ const shutdownEmitter = new ShutdownEmitter();
5
+ //const fetch = require('node-fetch'); // For HTTP requests (e.g., price lookups)
6
+ const util = require('util')
7
+ const ReOrgChecker = require('./reOrg.js');
8
+ // main.js
9
+ const initialize = require('./init');
10
+ let client
11
+ let db
12
+ (async () => {
13
+ try {
14
+ console.log('initializing from the top')
15
+ const { Client, Db } = await initialize();
16
+ client = Client
17
+ db = Db
18
+ console.log('Client and Database initialized successfully.');
19
+
20
+ // Now proceed with the rest of your app setup
21
+ /*const Main = require('./main-logic'); // Adjust based on your main logic setup
22
+ const app = new Main(client, db); // Pass the initialized instances if needed
23
+ app.start(); // Start your app logic*/
24
+
25
+ } catch (error) {
26
+ console.error('Failed to initialize client or database.', error);
27
+ process.exit(1);
28
+ }
29
+ })();
30
+
31
+ const fs = require('fs'); // File system module
32
+
33
+ const Validity = require('./validity.js'); // Module for checking transaction validity
34
+ const TxUtils = require('./txUtils.js'); // Utility functions for transactions
35
+ const TxIndex = require('./txIndex.js') // Indexes TradeLayer transactions
36
+ const TradeChannel = require('./channels.js'); // Manages Trade Channels
37
+ const TallyMap = require('./tally.js'); // Manages Tally Mapping
38
+ const MarginMap = require('./marginMap.js'); // Manages Margin Mapping
39
+ const Clearing = require('./clearing.js')
40
+ const Channels = require('./channels.js')
41
+ const PropertyManager = require('./property.js'); // Manages properties
42
+ const ContractsRegistry = require('./contractRegistry.js'); // Registry for contracts
43
+ const VolumeIndex = require('./volumeIndex.js')
44
+ const TradeLayerManager = require('./vesting.js')
45
+ const Consensus = require('./consensus.js'); // Functions for handling consensus
46
+ const Oracles = require('./oracle.js')
47
+ const Activation = require('./activation.js')
48
+ const Orderbook = require('./orderbook.js')
49
+ const Persistence = require('./persistence.js');
50
+ let activation
51
+
52
+ (async () => {
53
+ activation = Activation.getInstance()
54
+ await activation.init();
55
+ console.log(`App initialized with Chain: ${activation.chain}, Testnet: ${activation.test}, Admin Address: ${activation.adminAddress}`);
56
+
57
+ // Continue with the rest of your application setup
58
+ // Initialize other components or start the server, etc.
59
+ })();
60
+
61
+ const Encode = require('./txEncoder.js'); // Encodes transactions
62
+ const Types = require('./types.js'); // Defines different types used in the system
63
+ const Logic = require('./logic.js')
64
+ const AMM = require('./amm.js')
65
+ const Decode = require('./txDecoder.js'); // Decodes transactionsconst db = require('./db.js'); // Adjust the path if necessary
66
+ const genesisBlock = 3082500
67
+ const COIN = 100000000
68
+ const pause = false
69
+
70
+ const GENESIS_BLOCK_HEIGHTS = {
71
+ BTC: {
72
+ test: 3520000, // Replace with actual testnet genesis block height
73
+ main: 880000, // Replace with actual mainnet genesis block height
74
+ },
75
+ DOGE: {
76
+ test: 6815000, // Replace with actual testnet genesis block height
77
+ main: 5520000, // Replace with actual mainnet genesis block height
78
+ },
79
+ LTC: {
80
+ test: 3082500, // Replace with actual testnet genesis block height
81
+ main: 2819000, // Replace with actual mainnet genesis block height
82
+ }
83
+ };
84
+
85
+ class Main {
86
+ static instance;
87
+ static isInitializing = false; // Add a flag to track initialization
88
+
89
+
90
+ constructor() {
91
+ console.log('inside main constructor '+Boolean(Main.instance))
92
+ if (Main.instance) {
93
+ console.log('main already initialized')
94
+ return Main.instance;
95
+ }
96
+
97
+ this.client=client// Use the already initialized clientInstance // Initialize the client with the specified chain
98
+
99
+ console.log('client in main ' +this.client)
100
+ //this.tradeLayerManager = new TradeLayerManager();
101
+ this.txIndex = TxIndex.getInstance();
102
+ this.getBlockCountAsync = () => this.client.getBlockCount();
103
+ this.getNetworkInfoAsync = () => this.client.getNetworkInfo();
104
+ this.genesisBlock = 600000
105
+ this.parseBlock = 0
106
+ console.log(this.genesisBlock)
107
+ Main.instance = this;
108
+ }
109
+
110
+ static async getInstance() {
111
+ if (!Main.instance && !Main.isInitializing) {
112
+ Main.isInitializing = true;
113
+ console.log('Initializing Main instance...');
114
+
115
+ // 1. Construct Main first
116
+ Main.instance = new Main();
117
+
118
+ // 2. Detect network from the initialized client instance
119
+ const net = await Main.instance.client.getChain();
120
+ const test = await Main.instance.client.getTest();
121
+ console.log("[Main] Detected network:", net, "test:", test);
122
+
123
+ // 3. Initialize Persistence ONCE only via its own singleton
124
+ Main.instance.blockchainPersistence = await Persistence.getInstance({
125
+ network: net,
126
+ test: test,
127
+ snapshotInterval: 1000
128
+ });
129
+
130
+ Main.persistenceInitialized = true;
131
+ Main.isInitializing = false;
132
+ }
133
+
134
+ return Main.instance;
135
+ }
136
+
137
+
138
+ async delay(ms) {
139
+ return new Promise(resolve => setTimeout(resolve, ms));
140
+ }
141
+
142
+ async initialize() {
143
+ await this.delay(1500)
144
+ console.log('db status '+db)
145
+ if(!db&&this.client){
146
+ console.log('have client, awaiting db')
147
+ await db.init(this.client.chain)
148
+ await this.delay(300)
149
+ console.log('db status recheck '+db.initialized)
150
+ }else if(!db.initialized&&!this.client.chain){
151
+ console.log('no client no db, trying init again')
152
+ const { Client, Db } = await initialize();
153
+ await this.delay(300)
154
+ console.log('db+client status recheck '+db.initialized+this.client.chain)
155
+ }
156
+ const txIndex = await TxIndex.getInstance();
157
+ this.test = await this.client.getTest()
158
+ this.chain = await this.client.getChain()
159
+ console.log('this.test '+this.test+' '+this.chain)
160
+ console.log('block heights '+GENESIS_BLOCK_HEIGHTS)
161
+ if (this.test !== undefined && this.chain !== undefined) {
162
+ const networkType = this.test ? 'test' : 'main'; // Map boolean to 'test' or 'main'
163
+ const genesisConfig = GENESIS_BLOCK_HEIGHTS?.[this.chain];
164
+
165
+ if (genesisConfig && genesisConfig[networkType] !== undefined) {
166
+ this.genesisBlock = genesisConfig[networkType];
167
+ console.log(`Genesis Block for ${this.chain} (${networkType}): ${this.genesisBlock}`);
168
+ } else {
169
+ console.error(`Genesis block not configured for chain: ${this.chain} (${networkType})`);
170
+ }
171
+ } else {
172
+ console.error('Chain or test flag is undefined. Cannot set genesis block.');
173
+ }
174
+
175
+ console.log('genesis block in tx index init '+this.genesisBlock)
176
+ try {
177
+ await txIndex.initializeOrLoadDB(this.genesisBlock);
178
+ // Proceed with further operations after successful initialization
179
+ } catch (error) {
180
+ console.log('boop '+error)
181
+ }
182
+ console.log('about to check for Index')
183
+ const indexExists = await TxIndex.checkForIndex();
184
+ console.log('indexExists' + indexExists);
185
+ if (!indexExists) {
186
+ console.log('building txIndex');
187
+ await this.initOrLoadTxIndex()
188
+ //await TxIndex.initializeIndex(this.genesisBlock);
189
+
190
+ }
191
+
192
+ // Construct consensus from index, or load from Persistence if available
193
+ console.log('constructing consensus state')
194
+ const consensus = await this.constructOrLoadConsensus();
195
+
196
+ // Start processing incoming blocks
197
+ //await this.processIncomingBlocks(consensus);
198
+
199
+ }
200
+
201
+ async getCurrentBlockHeight() {
202
+ try {
203
+ const blockchainInfo = await this.getBlockCountAsync();
204
+ console.log(blockchainInfo)
205
+ return blockchainInfo;
206
+ } catch (error) {
207
+ console.error('Error fetching current block height:', error);
208
+ throw error; // or handle error as needed
209
+ }
210
+ }
211
+
212
+ async initOrLoadTxIndex() {
213
+ // Check if the txIndex exists by trying to find the max indexed block
214
+ var maxIndexedBlock = await TxIndex.findMaxIndexedBlock();
215
+ console.log('max Indexed Block ' + JSON.stringify(maxIndexedBlock))
216
+ if (maxIndexedBlock === 0 || maxIndexedBlock === null) {
217
+ // Initialize the txIndex if it doesn't exist
218
+ console.log('about to init index with ' +this.genesisBlock)
219
+ await TxIndex.initializeIndex(this.genesisBlock);
220
+ maxIndexedBlock= this.genesisBlock
221
+ }
222
+ // Proceed to synchronize the index
223
+ await this.syncIndex(maxIndexedBlock);
224
+ }
225
+
226
+ async syncIndex(maxIndexedBlock) {
227
+ console.log('sync Index maxIndexedBlock '+maxIndexedBlock)
228
+ try {
229
+ // Find the maximum indexed block in the database
230
+ if(maxIndexedBlock===null){this.initOrLoadTxIndex()}
231
+ // Fetch the current chain tip (latest block number) from the blockchain
232
+ const chainTip = await this.getBlockCountAsync()
233
+ console.log('sync index retrieved chaintip '+chainTip)
234
+ // If the chain tip is greater than the max indexed block, sync the index
235
+ if (chainTip > maxIndexedBlock && (maxIndexedBlock !=0 || maxIndexedBlock != {})){
236
+ // Loop through each block starting from maxIndexedBlock + 1 to chainTip
237
+ console.log('building tx index '+maxIndexedBlock)
238
+ return await TxIndex.extractBlockData(maxIndexedBlock)
239
+ } else if(maxIndexedBlock==0|| maxIndexedBlock == {}){
240
+ console.log('building txIndex from genesis')
241
+ return await TxIndex.extractBlockData(this.genesisBlock)
242
+ }else if(maxIndexedBlock==chainTip){
243
+
244
+ console.log("TxIndex is already up to date.");
245
+ return this.constructOrLoadConsensus(maxIndexedBlock)
246
+ }
247
+ } catch (error) {
248
+ console.error("Error during syncIndex:", error);
249
+ }
250
+ }
251
+
252
+ async constructOrLoadConsensus() {
253
+ let consensusState;
254
+
255
+ try {
256
+ //const lastSavedHeight = await persistenceDB.get('lastSavedHeight');
257
+ const startHeight = /*lastSavedHeight ||*/ this.genesisBlock;
258
+ return this.constructConsensusFromIndex(startHeight, false);
259
+ } catch (error) {
260
+ if (error.type === 'NotFoundError') {
261
+ // If no saved state, start constructing consensus from genesis block
262
+ console.log("no consensus found")
263
+ return this.constructConsensusFromIndex(genesisBlockHeight, false);
264
+ } else {
265
+ console.error('Error loading consensus state:', error);
266
+ throw error;
267
+ }
268
+ }
269
+ }
270
+
271
+ /*
272
+ Most important function, has two modes, realtime==false means we're catching up and constructing consensus,
273
+ from the txIndex, from genesis until chaintip.
274
+ Real-time==true means we're looping in a delayed timer to check for new blocks and include any new ones in the
275
+ txIndex then apply them to this to update the db and consensus.
276
+ */
277
+ async constructConsensusFromIndex(startHeight) {
278
+ let lastIndexBlock = await TxIndex.findMaxIndexedBlock();
279
+ let blockHeight;
280
+ let maxProcessedHeight = startHeight - 1;
281
+
282
+ const txIndexDB = await db.getDatabase('txIndex');
283
+ const tallyMapInstance = TallyMap.getInstance();
284
+ const lastConsensusHeight = await this.loadMaxProcessedHeight();
285
+
286
+ // Fetch all transaction data
287
+ const allTxData = await txIndexDB.findAsync({});
288
+ const txDataSet = allTxData.filter(txData => txData._id.startsWith('tx-'));
289
+
290
+ // Group transactions by block height
291
+ const txByBlockHeight = txDataSet.reduce((acc, txData) => {
292
+ const txBlockHeight = parseInt(txData._id.split('-')[1]);
293
+ if(!acc[txBlockHeight]){
294
+ acc[txBlockHeight] = {
295
+ fundingTx: [], // Bucket for funding transactions
296
+ tradeTx: [] // Bucket for regular trade transactions
297
+ };
298
+ }
299
+ //console.log('troubleshooting 1 '+txData.value)
300
+ // Determine if the transaction is a funding transaction (type starting with 4 or 20)
301
+ let counter1 = 0
302
+ let counter2 = 0
303
+ const valueData=txData.value
304
+ if (!valueData || !valueData.payload) return acc;
305
+ const payload = valueData.payload;
306
+ const type = parseInt(payload.slice(0, 1).toString(36), 36);
307
+ // Assuming types 4 and 20 are the funding types
308
+ if (type === 4 || type === 20) {
309
+ counter1++
310
+ //console.log('logging funding '+counter1+' '+JSON.stringify(txData))
311
+ acc[txBlockHeight].fundingTx.push(txData);
312
+ } else {
313
+ counter2++
314
+ //console.log('logging other '+counter2+' '+JSON.stringify(txData))
315
+ acc[txBlockHeight].tradeTx.push(txData);
316
+ }
317
+ return acc;
318
+ }, {});
319
+
320
+ //console.log(JSON.stringify(txByBlockHeight))
321
+
322
+ // Determine the last block height with transactions
323
+ const blockHeights = Object.keys(txByBlockHeight).map(Number);
324
+ if (blockHeights.length > 0) {
325
+ lastIndexBlock = Math.max(...blockHeights);
326
+ } else {
327
+ lastIndexBlock = null;
328
+ }
329
+
330
+ if (!lastIndexBlock) {
331
+ console.log('No transactions to process.');
332
+ return;
333
+ }
334
+
335
+ blockHeight = startHeight;
336
+ console.log('construct Consensus from Index max indexed block ' + lastIndexBlock, 'start height ' + startHeight);
337
+
338
+ for (; blockHeight <= lastIndexBlock; blockHeight++) {
339
+ this.parseBlock = blockHeight
340
+ if(blockHeight%10000==1){console.log('parsing towards real-time mode '+blockHeight)}
341
+ const blockData = txByBlockHeight[blockHeight];
342
+ let skip = true
343
+ //if(blockHeight%1000){console.log('block consensus processing '+blockHeight)}
344
+ if (blockData) {
345
+ // First process funding transactions
346
+ const skips = await this.processTxSet(blockData.fundingTx, blockHeight);
347
+ console.log('skips? '+skips)
348
+ // Then process trade transactions
349
+ const skips2 = await this.processTxSet(blockData.tradeTx, blockHeight);
350
+ console.log('skips 2? '+skips)
351
+ if((skips+skips2)<(blockData.fundingTx.length+blockData.tradeTx.length)){
352
+ console.log('skip to my lou my darlin '+skips +' '+skips2+' '+blockData.fundingTx.length+' '+blockData.tradeTx.length)
353
+ skip=false
354
+ if((skips+skips2)>0){
355
+ throw error("somehow there are already processed transactions in a partially processed block")
356
+ }
357
+ }
358
+ }
359
+ if(blockHeight%10000==0){skip=false}
360
+ if(skip==false){ //we don't do any post-processing on state for this block if it's already done, no replay of vesting, clearing
361
+ await Orderbook.processQueuedOnChainOrdersForBlock(blockHeight);
362
+ await Orderbook.processQueuedChannelTradesForBlock(blockHeight);
363
+ const cumulativeVolumes = await VolumeIndex.getCumulativeVolumes(blockHeight);
364
+ const thisBlockVolumes = await VolumeIndex.getBlockVolumes(blockHeight);
365
+ if (thisBlockVolumes.global > 0){
366
+ console.log('This is a block volume! ' + thisBlockVolumes);
367
+ const updateVesting = await TradeLayerManager.updateVesting(
368
+ cumulativeVolumes.ltcPairTotalVolume,
369
+ thisBlockVolumes.ltcPairs,
370
+ cumulativeVolumes.globalCumulativeVolume,
371
+ thisBlockVolumes.global
372
+ );
373
+ if (updateVesting != null && updateVesting != undefined && thisBlockVolumes != 0) {
374
+ console.log('Update Vesting in block ' + blockHeight + ' ' + JSON.stringify(updateVesting));
375
+ await TallyMap.applyVesting(2, updateVesting.two, blockHeight);
376
+ await TallyMap.applyVesting(3, updateVesting.three, blockHeight);
377
+ }
378
+ }
379
+
380
+ // Additional processing steps like withdrawal and clearing
381
+ await Channels.processWithdrawals(blockHeight);
382
+ await Clearing.clearingFunction(blockHeight,false);
383
+ }
384
+
385
+ maxProcessedHeight = blockHeight;
386
+ }
387
+
388
+ await this.saveMaxProcessedHeight(maxProcessedHeight,false,null);
389
+ return this.syncIfNecessary();
390
+ }
391
+
392
+ async checkSync(){
393
+ const consensusParse = this.parseBlock
394
+ const txIndex = await TxIndex.getInstance();
395
+ const txIndexParse = txIndex.parseBlock
396
+ return {consensus: consensusParse, txIndex: txIndexParse}
397
+ }
398
+
399
+ // Helper function to process a set of transactions
400
+ async processTxSet(txSet, blockHeight) {
401
+ let skips = 0
402
+ for (const txData of txSet) {
403
+ let flag = false;
404
+
405
+
406
+ const valueData = txData.value
407
+ const txId = valueData.txId;
408
+
409
+ if (await Consensus.checkIfTxProcessed(txId)) {
410
+ //console.log('scanning blockHeight '+blockHeight+' '+txId)
411
+ skips++
412
+ continue;
413
+ }
414
+
415
+ var payload = valueData.payload;
416
+ const marker = valueData.marker;
417
+ const type = parseInt(payload.slice(0, 1).toString(36), 36);
418
+ console.log('type is '+type + ' height is '+blockHeight)
419
+ payload = payload.slice(1, payload.length).toString(36);
420
+ const senderAddress = valueData.sender.senderAddress;
421
+ const referenceAddress = valueData.reference;
422
+ const senderUTXO = valueData.sender.amount;
423
+ const referenceUTXO = valueData.reference.amount / COIN;
424
+
425
+ if (flag) {
426
+ console.log('missing tx params ' + txId,
427
+ type,
428
+ marker,
429
+ payload,
430
+ senderAddress,
431
+ referenceAddress,
432
+ senderUTXO,
433
+ referenceUTXO,
434
+ blockHeight);
435
+ }
436
+
437
+ const decodedParams = await Types.decodePayload(
438
+ txId,
439
+ type,
440
+ marker,
441
+ payload,
442
+ senderAddress,
443
+ referenceAddress,
444
+ senderUTXO,
445
+ referenceUTXO,
446
+ blockHeight
447
+ );
448
+
449
+ if (flag) {
450
+ console.log('missing tx decode ' + decodedParams);
451
+ }
452
+ console.log('decoded params ' +JSON.stringify(decodedParams))
453
+ decodedParams.block = blockHeight;
454
+
455
+ if (decodedParams.valid === true) {
456
+ console.log('consensus marking valid tx '+decodedParams)
457
+ await Consensus.markTxAsProcessed(txId, decodedParams);
458
+ await Logic.typeSwitch(type, decodedParams);
459
+ //await TxIndex.upsertTxValidityAndReason(txId, type, decodedParams.valid, decodedParams.reason);
460
+ } else {
461
+ console.log('consensus marking invalid tx '+decodedParams)
462
+ await Consensus.markTxAsProcessed(txId, decodedParams);
463
+ await TxIndex.upsertTxValidityAndReason(txId, type, decodedParams.valid, decodedParams.reason);
464
+ }
465
+ }
466
+ return skips
467
+ }
468
+
469
+ async processTx(txSet, blockHeight) {
470
+ let processedAny = false;
471
+
472
+ for (const txData of txSet) {
473
+ console.log('tx data in real-time' + JSON.stringify(txData));
474
+ const txId = txData.txId;
475
+
476
+ if (await Consensus.checkIfTxProcessed(txId)) {
477
+ // We *skip* this tx, but keep going in case there are new ones
478
+ continue;
479
+ }
480
+
481
+ let payload = txData.payload;
482
+ const marker = 'tl';
483
+
484
+ const type = parseInt(payload.slice(0, 1).toString(36), 36);
485
+ payload = payload.slice(1, payload.length).toString(36);
486
+
487
+ const senderAddress = txData.sender.senderAddress;
488
+ const referenceAddress = txData.reference;
489
+ const senderUTXO = txData.sender.amount;
490
+ const referenceUTXO = txData.reference.amount / COIN;
491
+
492
+ console.log('params to go in during consensus builder ' + type + ' ' + payload + ' ' + senderAddress + blockHeight);
493
+
494
+ const decodedParams = await Types.decodePayload(
495
+ txId, type, marker, payload,
496
+ senderAddress, referenceAddress,
497
+ senderUTXO, referenceUTXO,
498
+ blockHeight
499
+ );
500
+ decodedParams.block = blockHeight;
501
+
502
+ // activation checks as you already have...
503
+ if (decodedParams.type > 0) {
504
+ const activationBlock = activationInstance.getActivationBlock(decodedParams.type);
505
+ if (blockHeight < activationBlock) {
506
+ decodedParams.valid = false;
507
+ decodedParams.reason += 'Tx not yet activated ';
508
+ }
509
+ }
510
+
511
+ await Consensus.markTxAsProcessed(txId, decodedParams);
512
+ await TxIndex.upsertTxValidityAndReason(txId, type, decodedParams.valid, decodedParams.reason);
513
+
514
+ if (decodedParams.valid === true) {
515
+ processedAny = true;
516
+ console.log('valid tx going in for processing ' + type + JSON.stringify(decodedParams) + ' ' + txId + 'blockHeight ' + blockHeight);
517
+ await Logic.typeSwitch(type, decodedParams);
518
+ } else {
519
+ console.log('invalid tx ' + decodedParams.reason);
520
+ }
521
+ }
522
+
523
+ return processedAny;
524
+ }
525
+
526
+
527
+ /*originally was an if-logic based switch function but refactoring real-time mode
528
+ it simply is a part of a flow, could be refactored into one function
529
+ */
530
+ async syncIfNecessary(restore) {
531
+ const blockLag = await this.checkBlockLag();
532
+ if(restore){
533
+ blockLag.maxTrack=restore
534
+ console.log('set max track to restore '+blockLag.maxTrack)
535
+ }
536
+
537
+ if(pause){
538
+ while(pause){
539
+ await delay(1000)
540
+ }
541
+ return syncIfNecessary()
542
+ }else{
543
+ this.processIncomingBlocks(blockLag.lag, blockLag.maxTrack, blockLag.chainTip); // Start processing new blocks as they come
544
+ }
545
+ }
546
+
547
+ setPause(){
548
+ if(!pause){
549
+ pause=true
550
+ }else if(pause){
551
+ pause=false
552
+ }
553
+ return pause
554
+ }
555
+
556
+ //updates max consensus block in real-time mode
557
+ async checkBlockLag(){
558
+ const chaintip = await this.getBlockCountAsync()
559
+ let track = await this.loadTrackHeight()
560
+ if(track==null){
561
+ track = await this.loadMaxProcessedHeight()
562
+ }
563
+ //console.log(maxConsensusBlock)
564
+ var lag = chaintip - track
565
+ return {'lag':lag, 'chainTip':chaintip, 'maxTrack':track}
566
+ }
567
+
568
+ /*main function of real-time mode*/
569
+ async processIncomingBlocks(lag, maxTrack, chainTip) {
570
+ // Continuously loop through incoming blocks and process them
571
+ let latestProcessedBlock = maxTrack
572
+ console.log('entering real-time mode '+latestProcessedBlock)
573
+ let lagObj
574
+ while (true) {
575
+ /*if (shutdownRequested) {
576
+ break; // Break the loop if shutdown is requested
577
+ }*/
578
+ chainTip = await this.getBlockCountAsync()
579
+ //console.log('latest block '+chainTip+' max track'+latestProcessedBlock)
580
+ let checkTrack = await this.loadTrackHeight()
581
+ if(checkTrack>latestProcessedBlock){latestProcessedBlock=checkTrack}
582
+ for (let blockNumber = latestProcessedBlock + 1; blockNumber <= chainTip; blockNumber++) {
583
+
584
+ const networkIsUp = await this.checkNetworkStatus();
585
+ if (!networkIsUp) {
586
+ console.log('Network down, entering recovery mode.');
587
+ blockNumber = await this.enterRecoveryMode(latestProcessedBlock, blockNumber);
588
+ }
589
+
590
+ //const blockData = await TxIndex.fetchBlockData(blockNumber);
591
+ const blockData = await this.fetchWithRetry(blockNumber);
592
+ const block= await this.processBlock(blockData, blockNumber);
593
+
594
+ if(block.reOrg==true){
595
+ console.log('returned block to restore '+JSON.stringify(block))
596
+ return this.syncIfNecessary(block.restore)
597
+ }
598
+ let trackHeight = blockNumber;
599
+ //console.log('updating trackHeight'+trackHeight)
600
+ await this.saveTrackHeight(trackHeight)
601
+ }
602
+
603
+ if(pause==true){
604
+ console.log('exiting real-time mode '+latestProcessedBlock)
605
+ break
606
+ };
607
+ // Wait for a short period before checking for new blocks
608
+ await new Promise(resolve => setTimeout(resolve, 10000)); // 10 seconds
609
+ //console.log('checking block lag '+maxConsensusBlock+' '+chainTip)
610
+ await this.saveTrackHeight(chainTip)
611
+ }
612
+ return syncIfNecessary()
613
+ }
614
+
615
+ async checkNetworkStatus() {
616
+ try {
617
+ // Fetch network info using the promisified getnetworkinfo RPC call
618
+ //console.log('about to ping')
619
+ const networkInfo = await this.getNetworkInfoAsync();
620
+
621
+ // Check if the network is active
622
+ const networkActive = networkInfo.networkactive;
623
+ const connections = networkInfo.connections;
624
+
625
+ //console.log('Network Status:', networkInfo);
626
+
627
+ // Determine if there is a potential network outage or issue
628
+ if (!networkActive) {
629
+ console.error('Network is inactive! The node is not connected to the Bitcoin network.');
630
+ return { status: false, reason: 'Network inactive' };
631
+ }
632
+
633
+ if (connections === 0) {
634
+ console.warn('Node has 0 connections. It may be isolated from the network.');
635
+ return { status: false, reason: 'No connections' };
636
+ }
637
+
638
+ // If everything seems fine
639
+ //console.log('Network is active with', connections, 'connections.');
640
+ return { status: true, connections: connections };
641
+
642
+ } catch (error) {
643
+ // Handle errors such as ECONNREFUSED (cannot connect to the node)
644
+ if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT') {
645
+ console.error(`Network error: ${error.message}. Could not reach the Bitcoin node.`);
646
+ return { status: 'down', reason: 'Connection refused or timeout' };
647
+ } else {
648
+ console.error('An unexpected error occurred:', error);
649
+ throw error; // Rethrow if it's an unexpected error
650
+ }
651
+ }
652
+ }
653
+
654
+ async enterRecoveryMode(latestProcessedBlock, trackHeight) {
655
+ console.log('Entering recovery mode, last processed block:', latestProcessedBlock);
656
+
657
+ while (true) {
658
+ const networkIsUp = await this.checkNetworkStatus();
659
+ if (networkIsUp.status) {
660
+ console.log('Network restored, resuming block processing.');
661
+
662
+ // Reload state from the database to ensure we're starting from the correct point
663
+ const savedTrackHeight = await this.loadTrackHeight();
664
+ const maxConsensusBlock = await this.loadMaxProcessedHeight();
665
+
666
+ console.log(`Resuming from block: ${latestProcessedBlock}, track height: ${trackHeight}`);
667
+ return savedTrackHeight; // Exit recovery mode and resume normal processing
668
+ }
669
+
670
+ // Retry after a short delay before checking the network again
671
+ await new Promise(resolve => setTimeout(resolve, 10000));
672
+ }
673
+ }
674
+
675
+
676
+ /*sub-function of real-time mode, breaks things into 3 steps*/
677
+ async processBlock(blockData, blockNumber) {
678
+ // Process the beginning of the block
679
+ const tx= await this.blockHandlerBegin(blockData, blockNumber);
680
+ if(typeof tx=='number'){return {reOrg: true, restore: tx}}//re-org recovery at block
681
+ // Process each transaction in the block
682
+ blockNumber = await this.blockHandlerMid(tx, blockNumber);
683
+
684
+ // Process the end of the block
685
+ await this.blockHandlerEnd(blockData.hash, blockNumber);
686
+ return {reOrg:false, restore: blockNumber}
687
+ }
688
+
689
+ async shutdown() {
690
+ console.log('Saving state to database...');
691
+ // Code to save state to database
692
+ console.log('Shutdown completed.');
693
+ process.exit(0); // or use another method to exit gracefully
694
+ }
695
+
696
+ async fetchWithRetry(blockNumber, retries = 3, delayMs = 1000) {
697
+ for (let attempt = 0; attempt <= retries; attempt++) {
698
+ try {
699
+ return await TxIndex.fetchBlockData(blockNumber); // Directly call the function
700
+ } catch (error) {
701
+ if (error.code === 'ETIMEDOUT') {
702
+ console.warn(`Attempt ${attempt + 1} failed with ETIMEDOUT.`);
703
+ if (attempt === retries) throw error; // Re-throw if max retries reached
704
+ await this.delay(delayMs * Math.pow(2, attempt)); // Exponential backoff
705
+ } else {
706
+ throw error; // Rethrow non-timeout errors
707
+ }
708
+ }
709
+ }
710
+ }
711
+
712
+ async blockHandlerBegin(blockData, blockHeight) {
713
+ const persistence = await Persistence.getInstance();
714
+
715
+ //try {
716
+ if (persistence) {
717
+ // 1) Live reorg detection
718
+ const reorg = await persistence.checkForReorgForNewBlock(
719
+ blockHeight,
720
+ blockData.previousblockhash
721
+ );
722
+ if (reorg) {
723
+ // Handle deep reorg (offline or multiple blocks)
724
+ const info = await persistence.detectAndHandleReorg(blockHeight);
725
+ if (info && typeof info.restoredFrom === 'number') {
726
+ console.log(
727
+ `Replaying consensus from snapshot at ${info.restoredFrom + 1} ` +
728
+ `after reorg (common ancestor ${info.commonAncestor}).`
729
+ );
730
+
731
+ //await this.constructConsensusFromIndex(info.restoredFrom + 1, true);
732
+ return info.restoredFrom
733
+ }
734
+ }
735
+
736
+ // 2) Record this block header for future comparisons
737
+ await persistence.recordBlockHeader(
738
+ blockHeight,
739
+ blockData.hash,
740
+ blockData.previousblockhash
741
+ );
742
+
743
+ // 3) Maybe write a snapshot + consensus checkpoint
744
+ await persistence.maybeCheckpoint(blockHeight);
745
+ }
746
+ //const blockData = await TxIndex.fetchBlockData(blockHeight);
747
+ const txDetails = await TxIndex.processBlockData(blockData, blockHeight);
748
+
749
+ if(txDetails.length>=1){
750
+ console.log('processing new tx '+JSON.stringify(txDetails))
751
+ }
752
+ // Separate out Commit/Transfer transactions from others
753
+ const fundingTxs = [];
754
+ const otherTxs = [];
755
+
756
+ for (const tx of txDetails) {
757
+ if (tx.payload.startsWith('4') || tx.payload.startsWith('m')) {
758
+ fundingTxs.push(tx);
759
+ } else {
760
+ otherTxs.push(tx);
761
+ }
762
+ console.log('funding tx '+JSON.stringify(fundingTxs))
763
+ }
764
+
765
+ // Process Commit/Transfer transactions first
766
+ if (fundingTxs.length > 0) {
767
+ await this.processTx(fundingTxs, blockHeight);
768
+ console.log(`Processed funding txs for block ${blockHeight}`);
769
+ }
770
+
771
+ // Pass other transactions to `blockHandlerMid` for processing later
772
+ return otherTxs; // Store remaining txs for mid-processing
773
+ /*} catch (error) {
774
+ console.error(`Error in blockHandlerBegin at block ${blockHeight}:`, error);
775
+
776
+ // Normalize error message into a string safely
777
+ const msg = (error?.message || error?.toString?.() || "");
778
+
779
+ if (msg.includes("ETIMEDOUT")) {
780
+ // retry
781
+ return this.blockHandlerBegin('', blockHeight);
782
+ }
783
+
784
+ return [];
785
+ }*/
786
+ }
787
+
788
+
789
+ /*middle part of real-time mode processed new tx */
790
+ async blockHandlerMid(txData, blockHeight) {
791
+ let didWork = false;
792
+
793
+ try {
794
+ if (txData && txData.length > 0) {
795
+ console.log(`tx Data for block ${blockHeight} txData ${JSON.stringify(txData)}`);
796
+
797
+ // processTx now returns true if any tx was newly processed
798
+ didWork = await this.processTx(txData, blockHeight);
799
+
800
+ // Save max height regardless, to persist progress
801
+ this.saveMaxProcessedHeight(blockHeight);
802
+ }
803
+
804
+ console.log(`Processed block ${blockHeight} successfully...`);
805
+ } catch (error) {
806
+ console.error(`Blockhandler Mid Error processing block ${blockHeight}:`, error);
807
+ }
808
+
809
+ // Run clearing only if there was actual new TL work done
810
+ if (didWork) {
811
+ await Orderbook.processQueuedOnChainOrdersForBlock(blockHeight);
812
+ await Orderbook.processQueuedChannelTradesForBlock(blockHeight);
813
+ console.log(`[CLEARING] Running for block ${blockHeight} (new TL work detected)`);
814
+ await Clearing.clearingFunction(blockHeight, /*skip=*/false);
815
+ } else {
816
+ //console.log(`[CLEARING] Skipped for block ${blockHeight} (no new TL work)`);
817
+ }
818
+
819
+ // Always return block number for chain continuity
820
+ return blockHeight;
821
+ }
822
+
823
+ /*here's where we finish a block processing in real-time mode, handling anything that is done after
824
+ the main tx processing. But since I've stuck the clearing function, channel removal and others in the constructConsensus function
825
+ this is currently also redundant */
826
+ async blockHandlerEnd(blockHash, blockHeight) {
827
+ const cumVolumes = await VolumeIndex.getCumulativeVolumes()
828
+ const thisBlockVolumes = await VolumeIndex.getBlockVolumes(blockHeight)
829
+ if(thisBlockVolumes>0){
830
+ console.log('this is a block volume! '+thisBlockVolumes)
831
+ const updateVesting = await TradeLayerManager.updateVesting(cumVolumes.ltcPairTotalVolume,thisBlockVolumes.ltcPairs,cumVolumes.globalCumulativeVolume,thisBlockVolumes.global)
832
+ if(updateVesting!=null&&updateVesting!=undefined&&thisBlockVolumes!=0){
833
+ console.log('update Vesting in block' +blockHeight+ ' '+JSON.stringify(updateVesting))
834
+ await TallyMap.applyVesting(2,updateVesting.two,blockHeight)
835
+ await TallyMap.applyVesting(3,updateVesting.three,blockHeight)
836
+ }
837
+ }
838
+
839
+ return //console.log('block finish '+blockHeight)
840
+ }
841
+
842
+ async handleReorg(blockHeight) {
843
+ //console.log(`Handling reorganization at block ${blockHeight}`);
844
+ // Add logic to handle a blockchain reorganization
845
+ await this.blockchainPersistence.handleReorg();
846
+ // This could involve reverting to a previous state, re-processing blocks, etc.
847
+ }
848
+
849
+ async saveMaxProcessedHeight(maxProcessedHeight){
850
+ try {
851
+ const base = await db.getDatabase('consensus')
852
+ await base.updateAsync(
853
+ { _id: 'MaxProcessedHeight' },
854
+ { $set: { value: maxProcessedHeight } },
855
+ { upsert: true }
856
+ );
857
+ //console.log('realtime mode update '+maxProcessedHeight)
858
+ } catch (error) {
859
+ console.error('Error updating MaxProcessedHeight:', error);
860
+ throw error; // or handle the error as needed
861
+ }
862
+ }
863
+
864
+ async saveTrackHeight(saveHeight){
865
+ const base = await db.getDatabase('consensus')
866
+ await base.updateAsync(
867
+ { _id: 'TrackHeight' },
868
+ { $set: { value: saveHeight } },
869
+ { upsert: true }
870
+ )
871
+ }
872
+
873
+ async loadMaxProcessedHeight() {
874
+ const consensusDB = await db.getDatabase('consensus'); // Access the consensus sub-database
875
+
876
+ try {
877
+ const maxProcessedHeightDoc = await consensusDB.findOneAsync({ _id: 'MaxProcessedHeight' });
878
+ if (maxProcessedHeightDoc) {
879
+ const maxProcessedHeight = maxProcessedHeightDoc.value;
880
+ //console.log('MaxProcessedHeight retrieved:', maxProcessedHeight);
881
+ return maxProcessedHeight; // Return the retrieved value
882
+ } else {
883
+ console.log('MaxProcessedHeight not found in the database.');
884
+ return null; // Return null or an appropriate default value if not found
885
+ }
886
+ } catch (error) {
887
+ console.error('Error retrieving MaxProcessedHeight:', error);
888
+ throw error; // Rethrow the error or handle it as needed
889
+ }
890
+ }
891
+
892
+ async loadTrackHeight() {
893
+ const consensusDB = await db.getDatabase('consensus'); // Access the consensus sub-database
894
+
895
+ try {
896
+ let track = await consensusDB.findOneAsync({ _id: 'TrackHeight' });
897
+ if (track) {
898
+ track = track.value;
899
+ //console.log('MaxProcessedHeight retrieved:', maxProcessedHeight);
900
+ return track; // Return the retrieved value
901
+ } else {
902
+ console.log('MaxTrackHeight not found in the database.');
903
+ return null; // Return null or an appropriate default value if not found
904
+ }
905
+ } catch (error) {
906
+ console.error('Error retrieving MaxProcessedHeight:', error);
907
+ throw error; // Rethrow the error or handle it as needed
908
+ }
909
+ }
910
+
911
+ static async getGenesisBlock() {
912
+ const mainInstance = await Main.getInstance();
913
+ return mainInstance.genesisBlock;
914
+ }
915
+
916
+ static async getLastBlock() {
917
+ try {
918
+ return await TxUtils.getLatestBlockHeight(); // Calls the blockchain for last block height
919
+ } catch (error) {
920
+ console.error("Error getting latest block height:", error);
921
+ throw error;
922
+ }
923
+ }
924
+ // ... other methods ...
925
+ }
926
+
927
+ module.exports = Main