Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

36 outgoing server delay #37

Merged
merged 60 commits into from
Aug 7, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
e7be42b
incoming server processing done & unit tested
proletesseract Jun 12, 2017
bc1e1fe
outgoing scripts done. tests added
proletesseract Jun 13, 2017
58ec7a8
update validation to handle smaller min amount
proletesseract Jun 14, 2017
7674582
log out decrypted data
proletesseract Jun 14, 2017
878c06b
parse both incoming and outgoing encrypted data as json
proletesseract Jun 14, 2017
137cb2b
version logging added
proletesseract Jun 15, 2017
967608e
log unspent data
proletesseract Jun 15, 2017
c0dcbdb
log out grouped partial data
proletesseract Jun 15, 2017
2626cf4
log out currentPending
proletesseract Jun 15, 2017
99ea723
logging out the encrypted data
proletesseract Jun 15, 2017
15e9228
log out the processed partials which arent ready
proletesseract Jun 15, 2017
ce76ee5
log out checked partials
proletesseract Jun 15, 2017
f80ca09
properly logged partial checking
proletesseract Jun 15, 2017
6d44a54
adding confirmations to stored data
proletesseract Jun 15, 2017
5d537b4
logging output
proletesseract Jun 15, 2017
6152de7
added max confs to private settings
proletesseract Jun 15, 2017
ccb3b1d
returned required params to incoming.js
proletesseract Jun 15, 2017
0ebe3ee
removed returned data, corrected condition
proletesseract Jun 15, 2017
f41fe3b
debugging condition
proletesseract Jun 15, 2017
cbf5807
added pause check in check-node api.
proletesseract Jun 15, 2017
6e8f468
added status readout and more logs
proletesseract Jun 15, 2017
9487d9c
used wrong variable
proletesseract Jun 15, 2017
a3d0263
push whole transaction into the partials list
proletesseract Jun 15, 2017
da19271
cant concatenate objecs in this verison of node.
proletesseract Jun 15, 2017
c7fc87a
tests updated.
proletesseract Jun 17, 2017
3bac819
log out decrypted for testing
proletesseract Jun 20, 2017
3351580
api logging
proletesseract Jun 20, 2017
bb15d4b
also log request
proletesseract Jun 20, 2017
0bf97cb
debug for prepare incoming
proletesseract Jun 20, 2017
1fd3406
fixed flattening logic to add the decimal
proletesseract Jun 22, 2017
be7be95
debug logging
proletesseract Jun 22, 2017
106fdb5
prep incoming debug
proletesseract Jun 22, 2017
3e97cd9
more debug
proletesseract Jun 22, 2017
eba7bee
cloned arrays to slice
proletesseract Jun 22, 2017
ccd10e8
more debug
proletesseract Jun 22, 2017
ef1fbb4
debug spend to holding runtime
proletesseract Jun 22, 2017
e9729a6
debug successful tx groups
proletesseract Jun 22, 2017
993ecfe
lodash each txgroup member
proletesseract Jun 22, 2017
599193d
updated decrypted data param
proletesseract Jun 22, 2017
5575a84
disabled mail
proletesseract Jun 22, 2017
96c5bd9
log to check blockheights
proletesseract Jun 22, 2017
3f07928
more debug in prepare outgoing
proletesseract Jun 22, 2017
04b6346
fixed decrypted value param name
proletesseract Jun 22, 2017
4e5d4b7
removed extra log
proletesseract Jun 22, 2017
f479c5d
added extra conditions to some outgoing logs
proletesseract Jun 22, 2017
6196e0f
test refill data
proletesseract Jun 22, 2017
6a2b620
removed un needed json parse.
proletesseract Jun 22, 2017
4a73799
added queue config param
proletesseract Jun 22, 2017
fa821f2
fixed tx-fee take
proletesseract Jun 22, 2017
d9ec664
check data
proletesseract Jun 22, 2017
8e48c69
case fixed to stop outgoing pausing
proletesseract Jun 22, 2017
89b35b1
fixed multiple tx peperation
proletesseract Jun 22, 2017
a942958
added safe rounding to amount additions
proletesseract Jun 23, 2017
77004ef
using the reduce function
proletesseract Jun 23, 2017
cf00227
fixed logs
proletesseract Jun 23, 2017
9464a10
correct amount being pushed
proletesseract Jun 23, 2017
33beac8
removed some of the debug
proletesseract Jun 23, 2017
c97052a
trying in satoshis
proletesseract Jun 23, 2017
1d17fb0
also track non satoshi
proletesseract Jun 23, 2017
557fa09
removed additional rounding tests
proletesseract Jun 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@
"prefer-template": 0,
"no-restricted-syntax": 0,
"strict": 0,
"no-underscore-dangle": ["error", {"allow": ["__set__"]}]
"no-underscore-dangle": ["warn", {"allow": ["__set__", "_*"]}]
}
}
2 changes: 2 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,8 @@ const apiInit = () => {
}))
}

// @TODO check if server paused before returning as valid incoming server

// -------------- CHECK IF SERVER IS PROCESSING ------------------------------------------------------------------------------------------

app.get('/api/status', (req, res) => {
Expand Down
94 changes: 76 additions & 18 deletions src/incoming.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
const Client = require('bitcoin-core')
const config = require('config')

const EncryptionKeys = require('./lib/EncryptionKeys.js')
const Logger = require('./lib/Logger.js')
const PreFlight = require('./lib/PreFlight.js')
const RefillOutgoing = require('./lib/RefillOutgoing.js')
const SelectOutgoing = require('./lib/SelectOutgoing.js')
const ReturnAllToSenders = require('./lib/ReturnAllToSenders.js')
const PrepareIncoming = require('./lib/PrepareIncoming.js')
const RetrieveSubchainAddresses = require('./lib/RetrieveSubchainAddresses.js')
const ProcessIncoming = require('./lib/ProcessIncoming.js')
const SpendToHolding = require('./lib/SpendToHolding.js')
let EncryptionKeys = require('./lib/EncryptionKeys.js') //eslint-disable-line
let Logger = require('./lib/Logger.js') //eslint-disable-line
let PreFlight = require('./lib/PreFlight.js') //eslint-disable-line
let RefillOutgoing = require('./lib/RefillOutgoing.js') //eslint-disable-line
let SelectOutgoing = require('./lib/SelectOutgoing.js') //eslint-disable-line
let ReturnAllToSenders = require('./lib/ReturnAllToSenders.js') //eslint-disable-line
let PrepareIncoming = require('./lib/PrepareIncoming.js') //eslint-disable-line
let RetrieveSubchainAddresses = require('./lib/RetrieveSubchainAddresses.js') //eslint-disable-line
let ProcessIncoming = require('./lib/ProcessIncoming.js') //eslint-disable-line
let SpendToHolding = require('./lib/SpendToHolding.js') //eslint-disable-line

const settings = config.get('INCOMING')

Expand Down Expand Up @@ -41,10 +41,11 @@ IncomingServer.init = () => {

Logger.writeLog('INC_000', 'server starting')
EncryptionKeys.findKeysToRemove({ type: 'private' }, IncomingServer.startProcessing)
setInterval(() => {
IncomingServer.cron = setInterval(() => {
if (IncomingServer.paused === false) {
EncryptionKeys.findKeysToRemove({ type: 'private' }, IncomingServer.startProcessing)
} else {
clearInterval(IncomingServer.cron)
Logger.writeLog('INC_001', 'processing paused', { paused: IncomingServer.paused })
}
}, settings.scriptInterval)
Expand Down Expand Up @@ -80,6 +81,7 @@ IncomingServer.holdingProcessed = (success, data) => {
if (!success) {
Logger.writeLog('INC_004', 'failed to process the holding account', { success, data }, true)
IncomingServer.processing = false
IncomingServer.paused = true
return
}
SelectOutgoing.run({
Expand All @@ -96,6 +98,9 @@ IncomingServer.outgoingSelected = (success, data) => {
}

if (data.returnAllToSenders) {
if (data.pause) {
IncomingServer.paused = true
}
ReturnAllToSenders.run({
navClient: IncomingServer.navClient,
}, IncomingServer.allPendingReturned)
Expand All @@ -116,10 +121,10 @@ IncomingServer.outgoingSelected = (success, data) => {
}

IncomingServer.allPendingReturned = (success, data) => {
console.log('STATUS: IncomingServer.allPendingReturned', success, data)
if (!success) {
Logger.writeLog('INC_006', 'failed to return all pending to sender', { success, data }, true)
IncomingServer.processing = false
IncomingServer.paused = true
return
}
Logger.writeLog('INC_007', 'returned all pending to sender', { success, data }, true)
Expand All @@ -128,17 +133,42 @@ IncomingServer.allPendingReturned = (success, data) => {
}

IncomingServer.currentBatchPrepared = (success, data) => {
if (!success || !data || !data.currentBatch || !data.currentFlattened || !data.numFlattened) {
if (!success || !data || !data.currentBatch || !data.currentFlattened || !data.numFlattened || !data.pendingToReturn) {
IncomingServer.processing = false
return
}
IncomingServer.runtime.currentBatch = data.currentBatch
IncomingServer.runtime.currentFlattened = data.currentFlattened
IncomingServer.runtime.numFlattened = data.numFlattened
IncomingServer.runtime.pendingToReturn = data.pendingToReturn

if (IncomingServer.runtime.pendingToReturn && IncomingServer.runtime.pendingToReturn.length > 0) {
Logger.writeLog('INC_011', 'failed to process some transactions', { success, data }, true)
ReturnAllToSenders.fromList({
navClient: IncomingServer.navClient,
transactionsToReturn: IncomingServer.runtime.pendingToReturn,
}, IncomingServer.pendingFailedReturned)
return
}
RetrieveSubchainAddresses.run({
subClient: IncomingServer.subClient,
chosenOutgoing: IncomingServer.runtime.chosenOutgoing,
numAddresses: IncomingServer.runtime.numFlattened,
}, IncomingServer.retrievedSubchainAddresses)
}

IncomingServer.pendingFailedReturned = (success, data) => {
if (!success) {
Logger.writeLog('INC_011A', 'failed to return failed pending to sender', { success, data }, true)
IncomingServer.paused = true
ReturnAllToSenders.run({
navClient: IncomingServer.navClient,
}, IncomingServer.allPendingReturned)
}
RetrieveSubchainAddresses.run({
subClient: IncomingServer.subClient,
chosenOutgoing: IncomingServer.runtime.chosenOutgoing,
numAddresses: data.numFlattened,
numAddresses: IncomingServer.runtime.numFlattened,
}, IncomingServer.retrievedSubchainAddresses)
}

Expand All @@ -150,6 +180,7 @@ IncomingServer.retrievedSubchainAddresses = (success, data) => {
}, IncomingServer.allPendingReturned)
return
}
// @TODO compile the correct transactions to return
ProcessIncoming.run({
currentBatch: IncomingServer.runtime.currentBatch,
currentFlattened: IncomingServer.runtime.currentFlattened,
Expand All @@ -163,21 +194,38 @@ IncomingServer.retrievedSubchainAddresses = (success, data) => {

IncomingServer.transactionsProcessed = (success, data) => {
if (!success || !data) {
if (data && data.partialFailure) {
Logger.writeLog('INC_010A', 'failed part way through processing subchain transactions', { success, data }, true)
IncomingServer.paused = true
IncomingServer.processing = false
return
}
Logger.writeLog('INC_010', 'failed to process transactions', { success, data }, true)
IncomingServer.paused = true
ReturnAllToSenders.run({
navClient: IncomingServer.navClient,
}, IncomingServer.allPendingReturned)
return
}

IncomingServer.runtime.successfulSubTransactions = data.successfulSubTransactions
IncomingServer.runtime.transactionsToReturn = data.transactionsToReturn
IncomingServer.runtime.successfulTxGroups = data.successfulTxGroups
IncomingServer.runtime.txGroupsToReturn = data.txGroupsToReturn
IncomingServer.runtime.transactionsToReturn = []

if (IncomingServer.runtime.transactionsToReturn && IncomingServer.runtime.transactionsToReturn.length > 0) {
if (IncomingServer.runtime.txGroupsToReturn && IncomingServer.runtime.txGroupsToReturn.length > 0) {
Logger.writeLog('INC_011', 'failed to process some transactions', { success, data }, true)

// extract the relevant transactions to return from the txGroupsToReturn
for (let i = 0; i < IncomingServer.runtime.txGroupsToReturn.length; i++) {
const txGroup = IncomingServer.runtime.txGroupsToReturn[i]
for (let j = 0; j < txGroup.transactions.length; j++) {
IncomingServer.runtime.transactionsToReturn.push(txGroup.transactions[j])
}
}

ReturnAllToSenders.fromList({
navClient: IncomingServer.navClient,
transactionsToReturn: data.transactionsToReturn,
transactionsToReturn: IncomingServer.runtime.transactionsToReturn,
}, IncomingServer.failedTransactionsReturned)
return
}
Expand All @@ -186,8 +234,18 @@ IncomingServer.transactionsProcessed = (success, data) => {

IncomingServer.failedTransactionsReturned = (success, data) => {
if (!success) {
IncomingServer.paused = true
Logger.writeLog('INC_012', 'failed to return failed transactions to sender', { success, data }, true)
}
IncomingServer.runtime.successfulSubTransactions = []
// extract the relevant transactions to return from the txGroupsToReturn
for (let i = 0; i < IncomingServer.runtime.successfulTxGroups.length; i++) {
const txGroup = IncomingServer.runtime.successfulTxGroups[i]
for (let j = 0; j < txGroup.transactions.length; j++) {
IncomingServer.runtime.successfulSubTransactions.push(txGroup.transactions[j])
}
}

SpendToHolding.run({
successfulSubTransactions: IncomingServer.runtime.successfulSubTransactions,
holdingEncrypted: IncomingServer.runtime.holdingEncrypted,
Expand Down
168 changes: 168 additions & 0 deletions src/lib/GroupPartials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
const lodash = require('lodash')

let Logger = require('./Logger.js') // eslint-disable-line
let EncryptedData = require('./EncryptedData.js') // eslint-disable-line

const GroupPartials = {}

GroupPartials.run = (options, callback) => {
const required = ['currentPending', 'client']
if (lodash.intersection(Object.keys(options), required).length !== required.length) {
Logger.writeLog('GRP_001', 'invalid options', { options, required })
callback(false, { message: 'invalid options provided to GroupPartials.run' })
return
}

GroupPartials.runtime = {
client: options.client,
currentPending: options.currentPending,
remainingToDecrypt: options.currentPending,
transactionsToReturn: [],
readyToProcess: {},
partials: {},
callback,
}
GroupPartials.getDecryptedData()
}

GroupPartials.getDecryptedData = () => {
if (GroupPartials.runtime.remainingToDecrypt.length < 1) {
GroupPartials.checkPartials()
return
}

EncryptedData.getEncrypted({
transaction: GroupPartials.runtime.remainingToDecrypt[0],
client: GroupPartials.runtime.client,
}, GroupPartials.checkDecrypted)
}

GroupPartials.partialFailed = (transaction) => {
const returnIndex = lodash.findIndex(GroupPartials.runtime.transactionsToReturn, (tx) => tx.txid === transaction.txid)
if (returnIndex === -1) {
GroupPartials.runtime.transactionsToReturn.push(transaction)
}
GroupPartials.runtime.remainingToDecrypt.splice(0, 1)
GroupPartials.getDecryptedData()
}

GroupPartials.checkDecrypted = (success, data) => {
if (!success || !data || !data.decrypted || !data.transaction) {
Logger.writeLog('GRP_002', 'failed to decrypt transaction data', { success })
GroupPartials.partialFailed(GroupPartials.runtime.remainingToDecrypt[0])
return
}
if (!data.decrypted.n || !data.decrypted.t || !data.decrypted.p || !data.decrypted.o || !data.decrypted.u) {
Logger.writeLog('GRP_003', 'failed to receive correct encrypted params', {
n: data.decrypted.n, // @TODO remove logging n before deployment
t: data.decrypted.t,
p: data.decrypted.p,
o: data.decrypted.o,
u: data.decrypted.u,
})
GroupPartials.partialFailed(data.transaction)
return
}

GroupPartials.runtime.client.validateAddress(data.decrypted.n).then((addressInfo) => {
if (addressInfo.isvalid !== true) {
Logger.writeLog('GRP_003A', 'encrypted address invalid', { success, data })
GroupPartials.partialFailed(data.transaction)
return
}
GroupPartials.groupPartials(data.decrypted, data.transaction)
}).catch((err) => {
Logger.writeLog('GRP_003B', 'failed to decrypt transaction data', { success, error: err })
GroupPartials.partialFailed(data.transaction)
return
})
}

GroupPartials.groupPartials = (decrypted, transaction) => {
if (!GroupPartials.runtime.partials[decrypted.u]) {
GroupPartials.runtime.partials[decrypted.u] = {
destination: decrypted.n,
unique: decrypted.u,
timeDelay: parseInt(decrypted.t, 10),
parts: parseInt(decrypted.o, 10),
partsSum: 0,
amount: 0,
transactions: {},
readyToProcess: false,
}
}

if (GroupPartials.runtime.partials[decrypted.u].readyToProcess === true) {
Logger.writeLog('GRP_006', 'this partial group is already flagged as completed', {
partials: GroupPartials.runtime.partials[decrypted.u],
transaction,
n: decrypted.n, // @TODO remove logging n before deployment
t: decrypted.t,
p: decrypted.p,
o: decrypted.o,
u: decrypted.u,
})
GroupPartials.partialFailed(transaction)
return
}

if (GroupPartials.runtime.partials[decrypted.u].destination !== decrypted.n) {
Logger.writeLog('GRP_004', 'decrypted address different from other partials', {
partials: GroupPartials.runtime.partials[decrypted.u],
transaction,
})
GroupPartials.partialFailed(transaction)
return
}

if (GroupPartials.runtime.partials[decrypted.u].transactions[transaction.txid]) {
Logger.writeLog('GRP_005', 'txid already processed', {
partials: GroupPartials.runtime.partials[decrypted.u],
transaction,
})
GroupPartials.partialFailed(transaction)
return
}

const unsafeTotal = GroupPartials.runtime.partials[decrypted.u].amount += transaction.amount
const safeTotal = Math.round(unsafeTotal * 100000000) / 100000000

GroupPartials.runtime.partials[decrypted.u].amount = safeTotal
GroupPartials.runtime.partials[decrypted.u].partsSum += parseInt(decrypted.p, 10)
GroupPartials.runtime.partials[decrypted.u].transactions[transaction.txid] = {
txid: transaction.txid,
amount: transaction.amount,
part: decrypted.p,
}

const numParts = GroupPartials.runtime.partials[decrypted.u].parts
const numTransactions = lodash.size(GroupPartials.runtime.partials[decrypted.u].transactions)

if (numTransactions === numParts
&& (numParts * (numParts + 1)) / 2 === GroupPartials.runtime.partials[decrypted.u].partsSum) {
GroupPartials.runtime.partials[decrypted.u].readyToProcess = true
GroupPartials.runtime.readyToProcess[decrypted.u] = GroupPartials.runtime.partials[decrypted.u]
}
GroupPartials.runtime.remainingToDecrypt.splice(0, 1)
GroupPartials.getDecryptedData()
}

GroupPartials.checkPartials = () => {
lodash.forEach(GroupPartials.runtime.partials, (partial) => {
if (!partial.readyToProcess) {
lodash.forEach(partial.transactions, (partialTx) => {
const returnIndex = lodash.findIndex(GroupPartials.runtime.transactionsToReturn, (tx) => tx.txid === partialTx.txid)
if (returnIndex === -1 && partialTx.confirmations > 120) { // if its not already flagged as returning & too old
GroupPartials.runtime.transactionsToReturn.push(partialTx)
}
})
}
})

GroupPartials.runtime.callback(true, {
readyToProcess: GroupPartials.runtime.readyToProcess,
transactionsToReturn: GroupPartials.runtime.transactionsToReturn,
})
}

module.exports = GroupPartials
4 changes: 4 additions & 0 deletions src/lib/PayoutFee.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ PayoutFee.send = () => {
address: PayoutFee.runtime.settings.anonTxFeeAddress,
amount: txFeeAccrued,
}, PayoutFee.sent)
}).catch((err) => {
Logger.writeLog('PAY_002A', 'error getting balance', { error: err })
PayoutFee.runtime.callback(false, { message: 'error getting balance' })
return
})
}

Expand Down
Loading