Skip to content

Commit 9bca5bd

Browse files
Merge branch 'v1.2'
2 parents 7679c8d + c5d8c78 commit 9bca5bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4526
-988
lines changed

.eslintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@
3131
"prefer-template": 0,
3232
"no-restricted-syntax": 0,
3333
"strict": 0,
34-
"no-underscore-dangle": ["error", {"allow": ["__set__"]}]
34+
"no-underscore-dangle": ["warn", {"allow": ["__set__", "_*"]}]
3535
}
3636
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ log.txt
77
npm-debug.log
88
config/default.json
99
.idea/
10+
11+
\.DS_Store

dist/navtech.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vendor.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ const apiInit = () => {
245245
}))
246246
return
247247
}
248+
// Logger.writeLog('APP_TEST_001', 'success get-addresses', { data })
248249
NavtechApi.runtime.res.send(JSON.stringify({
249250
status: 200,
250251
type: 'SUCCESS',
@@ -324,6 +325,18 @@ const apiInit = () => {
324325
return
325326
}
326327

328+
if (globalSettings.serverType === 'INCOMING' && IncomingServer.paused
329+
|| globalSettings.serverType === 'OUTGOING' && OutgoingServer.paused) {
330+
Logger.writeLog('APP_026A', 'this server is paused for manual recovery', { body: req.body })
331+
NavtechApi.runtime.res.send(JSON.stringify({
332+
status: 200,
333+
type: 'FAIL',
334+
code: 'APP_026A',
335+
message: 'server is not accepting transactions',
336+
}))
337+
return
338+
}
339+
327340
NavtechApi.runtime.numAddresses = parseInt(NavtechApi.runtime.req.body.num_addresses, 10)
328341

329342
if (globalSettings.serverType === 'INCOMING') {
@@ -452,7 +465,7 @@ const apiInit = () => {
452465
highestConf = pending.confirmations
453466
}
454467
}
455-
if (highestConf > 60) {
468+
if (highestConf > privateSettings.maxQueue) {
456469
Logger.writeLog('APP_030B', 'the queue is too long', { highestConf }, true)
457470
NavtechApi.runtime.res.send(JSON.stringify({
458471
status: 200,
@@ -571,13 +584,20 @@ const apiInit = () => {
571584

572585
returnData.nav_addresses = NavtechApi.runtime.navAddresses
573586

587+
// Logger.writeLog('APP_TEST_002', 'success check-node', {
588+
// returnData,
589+
// request: NavtechApi.runtime.req.body,
590+
// })
591+
574592
NavtechApi.runtime.res.send(JSON.stringify({
575593
status: 200,
576594
type: 'SUCCESS',
577595
data: returnData,
578596
}))
579597
}
580598

599+
// @TODO check if server paused before returning as valid incoming server
600+
581601
// -------------- CHECK IF SERVER IS PROCESSING ------------------------------------------------------------------------------------------
582602

583603
app.get('/api/status', (req, res) => {

src/incoming.js

Lines changed: 94 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22

33
const Client = require('bitcoin-core')
44
const config = require('config')
5+
const lodash = require('lodash')
56

6-
const EncryptionKeys = require('./lib/EncryptionKeys.js')
7-
const Logger = require('./lib/Logger.js')
8-
const PreFlight = require('./lib/PreFlight.js')
9-
const RefillOutgoing = require('./lib/RefillOutgoing.js')
10-
const SelectOutgoing = require('./lib/SelectOutgoing.js')
11-
const ReturnAllToSenders = require('./lib/ReturnAllToSenders.js')
12-
const PrepareIncoming = require('./lib/PrepareIncoming.js')
13-
const RetrieveSubchainAddresses = require('./lib/RetrieveSubchainAddresses.js')
14-
const ProcessIncoming = require('./lib/ProcessIncoming.js')
15-
const SpendToHolding = require('./lib/SpendToHolding.js')
7+
let EncryptionKeys = require('./lib/EncryptionKeys.js') //eslint-disable-line
8+
let Logger = require('./lib/Logger.js') //eslint-disable-line
9+
let PreFlight = require('./lib/PreFlight.js') //eslint-disable-line
10+
let RefillOutgoing = require('./lib/RefillOutgoing.js') //eslint-disable-line
11+
let SelectOutgoing = require('./lib/SelectOutgoing.js') //eslint-disable-line
12+
let ReturnAllToSenders = require('./lib/ReturnAllToSenders.js') //eslint-disable-line
13+
let PrepareIncoming = require('./lib/PrepareIncoming.js') //eslint-disable-line
14+
let RetrieveSubchainAddresses = require('./lib/RetrieveSubchainAddresses.js') //eslint-disable-line
15+
let ProcessIncoming = require('./lib/ProcessIncoming.js') //eslint-disable-line
16+
let SpendToHolding = require('./lib/SpendToHolding.js') //eslint-disable-line
1617

1718
const settings = config.get('INCOMING')
1819

@@ -41,10 +42,11 @@ IncomingServer.init = () => {
4142

4243
Logger.writeLog('INC_000', 'server starting')
4344
EncryptionKeys.findKeysToRemove({ type: 'private' }, IncomingServer.startProcessing)
44-
setInterval(() => {
45+
IncomingServer.cron = setInterval(() => {
4546
if (IncomingServer.paused === false) {
4647
EncryptionKeys.findKeysToRemove({ type: 'private' }, IncomingServer.startProcessing)
4748
} else {
49+
clearInterval(IncomingServer.cron)
4850
Logger.writeLog('INC_001', 'processing paused', { paused: IncomingServer.paused })
4951
}
5052
}, settings.scriptInterval)
@@ -80,6 +82,7 @@ IncomingServer.holdingProcessed = (success, data) => {
8082
if (!success) {
8183
Logger.writeLog('INC_004', 'failed to process the holding account', { success, data }, true)
8284
IncomingServer.processing = false
85+
IncomingServer.paused = true
8386
return
8487
}
8588
SelectOutgoing.run({
@@ -96,6 +99,9 @@ IncomingServer.outgoingSelected = (success, data) => {
9699
}
97100

98101
if (data.returnAllToSenders) {
102+
if (data.pause) {
103+
IncomingServer.paused = true
104+
}
99105
ReturnAllToSenders.run({
100106
navClient: IncomingServer.navClient,
101107
}, IncomingServer.allPendingReturned)
@@ -111,14 +117,15 @@ IncomingServer.outgoingSelected = (success, data) => {
111117
navClient: IncomingServer.navClient,
112118
outgoingNavBalance: data.outgoingNavBalance,
113119
subBalance: IncomingServer.runtime.subBalance,
120+
settings,
114121
}, IncomingServer.currentBatchPrepared)
115122
}
116123

117124
IncomingServer.allPendingReturned = (success, data) => {
118-
console.log('STATUS: IncomingServer.allPendingReturned', success, data)
119125
if (!success) {
120126
Logger.writeLog('INC_006', 'failed to return all pending to sender', { success, data }, true)
121127
IncomingServer.processing = false
128+
IncomingServer.paused = true
122129
return
123130
}
124131
Logger.writeLog('INC_007', 'returned all pending to sender', { success, data }, true)
@@ -127,15 +134,55 @@ IncomingServer.allPendingReturned = (success, data) => {
127134
}
128135

129136
IncomingServer.currentBatchPrepared = (success, data) => {
130-
if (!success || !data || !data.currentBatch) {
137+
if (!success || !data || ((!data.currentBatch || !data.currentFlattened || !data.numFlattened) && !data.pendingToReturn)) {
138+
Logger.writeLog('INC_011D', 'prepareIncoming returned bad data', { success, data })
131139
IncomingServer.processing = false
132140
return
133141
}
142+
134143
IncomingServer.runtime.currentBatch = data.currentBatch
144+
IncomingServer.runtime.currentFlattened = data.currentFlattened
145+
IncomingServer.runtime.numFlattened = data.numFlattened
146+
IncomingServer.runtime.pendingToReturn = data.pendingToReturn
147+
148+
if (IncomingServer.runtime.pendingToReturn && IncomingServer.runtime.pendingToReturn.length > 0) {
149+
Logger.writeLog('INC_011', 'failed to process some transactions', { success, data }, true)
150+
ReturnAllToSenders.fromList({
151+
navClient: IncomingServer.navClient,
152+
transactionsToReturn: IncomingServer.runtime.pendingToReturn,
153+
}, IncomingServer.pendingFailedReturned)
154+
return
155+
}
156+
157+
if (!IncomingServer.runtime.currentBatch || lodash.size(IncomingServer.runtime.currentBatch) === 0) {
158+
Logger.writeLog('INC_011B', 'no currentBatch to process', { currentBatch: IncomingServer.runtime.currentBatch })
159+
IncomingServer.processing = false
160+
return
161+
}
162+
RetrieveSubchainAddresses.run({
163+
subClient: IncomingServer.subClient,
164+
chosenOutgoing: IncomingServer.runtime.chosenOutgoing,
165+
numAddresses: IncomingServer.runtime.numFlattened,
166+
}, IncomingServer.retrievedSubchainAddresses)
167+
}
168+
169+
IncomingServer.pendingFailedReturned = (success, data) => {
170+
if (!success) {
171+
Logger.writeLog('INC_011A', 'failed to return failed pending to sender', { success, data }, true)
172+
IncomingServer.paused = true
173+
ReturnAllToSenders.run({
174+
navClient: IncomingServer.navClient,
175+
}, IncomingServer.allPendingReturned)
176+
}
177+
if (!IncomingServer.runtime.currentBatch || lodash.size(IncomingServer.runtime.currentBatch) === 0) {
178+
Logger.writeLog('INC_011C', 'no currentBatch to process', { currentBatch: IncomingServer.runtime.currentBatch })
179+
IncomingServer.processing = false
180+
return
181+
}
135182
RetrieveSubchainAddresses.run({
136183
subClient: IncomingServer.subClient,
137184
chosenOutgoing: IncomingServer.runtime.chosenOutgoing,
138-
currentBatch: data.currentBatch,
185+
numAddresses: IncomingServer.runtime.numFlattened,
139186
}, IncomingServer.retrievedSubchainAddresses)
140187
}
141188

@@ -147,8 +194,10 @@ IncomingServer.retrievedSubchainAddresses = (success, data) => {
147194
}, IncomingServer.allPendingReturned)
148195
return
149196
}
197+
// @TODO compile the correct transactions to return
150198
ProcessIncoming.run({
151199
currentBatch: IncomingServer.runtime.currentBatch,
200+
currentFlattened: IncomingServer.runtime.currentFlattened,
152201
outgoingPubKey: IncomingServer.runtime.outgoingPubKey,
153202
subClient: IncomingServer.subClient,
154203
navClient: IncomingServer.navClient,
@@ -159,21 +208,38 @@ IncomingServer.retrievedSubchainAddresses = (success, data) => {
159208

160209
IncomingServer.transactionsProcessed = (success, data) => {
161210
if (!success || !data) {
211+
if (data && data.partialFailure) {
212+
Logger.writeLog('INC_010A', 'failed part way through processing subchain transactions', { success, data }, true)
213+
IncomingServer.paused = true
214+
IncomingServer.processing = false
215+
return
216+
}
162217
Logger.writeLog('INC_010', 'failed to process transactions', { success, data }, true)
218+
IncomingServer.paused = true
163219
ReturnAllToSenders.run({
164220
navClient: IncomingServer.navClient,
165221
}, IncomingServer.allPendingReturned)
166222
return
167223
}
168224

169-
IncomingServer.runtime.successfulSubTransactions = data.successfulSubTransactions
170-
IncomingServer.runtime.transactionsToReturn = data.transactionsToReturn
225+
IncomingServer.runtime.successfulTxGroups = data.successfulTxGroups
226+
IncomingServer.runtime.txGroupsToReturn = data.txGroupsToReturn
227+
IncomingServer.runtime.transactionsToReturn = []
171228

172-
if (IncomingServer.runtime.transactionsToReturn && IncomingServer.runtime.transactionsToReturn.length > 0) {
229+
if (IncomingServer.runtime.txGroupsToReturn && IncomingServer.runtime.txGroupsToReturn.length > 0) {
173230
Logger.writeLog('INC_011', 'failed to process some transactions', { success, data }, true)
231+
232+
// extract the relevant transactions to return from the txGroupsToReturn
233+
for (let i = 0; i < IncomingServer.runtime.txGroupsToReturn.length; i++) {
234+
const txGroup = IncomingServer.runtime.txGroupsToReturn[i]
235+
for (let j = 0; j < txGroup.transactions.length; j++) {
236+
IncomingServer.runtime.transactionsToReturn.push(txGroup.transactions[j])
237+
}
238+
}
239+
174240
ReturnAllToSenders.fromList({
175241
navClient: IncomingServer.navClient,
176-
transactionsToReturn: data.transactionsToReturn,
242+
transactionsToReturn: IncomingServer.runtime.transactionsToReturn,
177243
}, IncomingServer.failedTransactionsReturned)
178244
return
179245
}
@@ -182,8 +248,18 @@ IncomingServer.transactionsProcessed = (success, data) => {
182248

183249
IncomingServer.failedTransactionsReturned = (success, data) => {
184250
if (!success) {
251+
IncomingServer.paused = true
185252
Logger.writeLog('INC_012', 'failed to return failed transactions to sender', { success, data }, true)
186253
}
254+
IncomingServer.runtime.successfulSubTransactions = []
255+
// extract the relevant transactions to return from the txGroupsToReturn
256+
for (let i = 0; i < IncomingServer.runtime.successfulTxGroups.length; i++) {
257+
const txGroup = IncomingServer.runtime.successfulTxGroups[i]
258+
lodash.forEach(txGroup.transactions, (transaction) => {
259+
IncomingServer.runtime.successfulSubTransactions.push(transaction)
260+
})
261+
}
262+
187263
SpendToHolding.run({
188264
successfulSubTransactions: IncomingServer.runtime.successfulSubTransactions,
189265
holdingEncrypted: IncomingServer.runtime.holdingEncrypted,

src/lib/EncryptedData.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ EncryptedData.decryptData = (options, callback) => {
6363
const key = ursa.createPrivateKey(fs.readFileSync(keyFile))
6464
const msg = key.decrypt(options.encryptedData, 'base64', 'utf8', ursa.RSA_PKCS1_PADDING)
6565
successfulDecryption = true
66-
decrypted = (globalSettings.serverType === 'INCOMING') ? msg : JSON.parse(msg)
66+
// Logger.writeLog('ECD_TEST', 'decrypted', { msg })
67+
decrypted = JSON.parse(msg)
6768
} catch (err2) {
6869
// do nothing
6970
}

src/lib/FlattenTransactions.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const lodash = require('lodash')
2+
3+
let Logger = require('./Logger.js') //eslint-disable-line
4+
5+
const FlattenTransactions = {}
6+
7+
FlattenTransactions.incoming = (options, callback) => {
8+
const required = ['amountToFlatten', 'anonFeePercent']
9+
if (lodash.intersection(Object.keys(options), required).length !== required.length) {
10+
Logger.writeLog('FLT_001', 'invalid options', { options, required })
11+
callback(false, { message: 'invalid options provided to FlattenTransactions.incoming' })
12+
return
13+
}
14+
const unsafeAmount = options.amountToFlatten / (1 + (options.anonFeePercent / 100))
15+
FlattenTransactions.runtime = {
16+
callback,
17+
amountToFlatten: FlattenTransactions.satoshiParser(unsafeAmount),
18+
}
19+
FlattenTransactions.flattenIncoming()
20+
}
21+
22+
FlattenTransactions.flattenIncoming = () => {
23+
const totalInt = Math.floor(FlattenTransactions.runtime.amountToFlatten)
24+
const totalIntString = totalInt.toString()
25+
const decimal = FlattenTransactions.runtime.amountToFlatten - totalInt
26+
const safeDecimal = FlattenTransactions.satoshiParser(decimal)
27+
28+
let flattened = []
29+
30+
for (let i = 0; i < totalIntString.length; i++) {
31+
const factor = 1 * Math.pow(10, totalIntString.length - (i + 1))
32+
const numFactors = parseInt(totalIntString[i], 10)
33+
for (let j = 0; j < numFactors; j++) {
34+
if (safeDecimal > 0 && lodash.sum(flattened) === totalInt - factor) {
35+
flattened.push(FlattenTransactions.satoshiParser(parseInt(factor, 10) + safeDecimal))
36+
} else {
37+
flattened.push(parseInt(factor, 10))
38+
}
39+
}
40+
}
41+
42+
if (flattened.length === 1) {
43+
flattened = []
44+
for (let k = 0; k < 10; k++) {
45+
if (safeDecimal > 0 && k === 9) {
46+
flattened.push(FlattenTransactions.satoshiParser((totalInt / 10) + safeDecimal))
47+
} else {
48+
flattened.push(totalInt / 10)
49+
}
50+
}
51+
}
52+
53+
const reduced = flattened.reduce((acc, x) => x + acc, 0)
54+
const safeReduced = FlattenTransactions.satoshiParser(reduced)
55+
56+
if (safeReduced !== FlattenTransactions.runtime.amountToFlatten) {
57+
Logger.writeLog('FLT_002', 'unable to correctly flatten amount', { runtime: FlattenTransactions.runtime, flattened })
58+
FlattenTransactions.runtime.callback(false, {
59+
flattened,
60+
})
61+
return
62+
}
63+
64+
FlattenTransactions.runtime.callback(true, {
65+
flattened,
66+
})
67+
}
68+
69+
FlattenTransactions.satoshiParser = (unsafe) => {
70+
const satoshiFactor = 100000000
71+
return Math.round(unsafe * satoshiFactor) / satoshiFactor
72+
}
73+
74+
module.exports = FlattenTransactions

0 commit comments

Comments
 (0)