Compare commits

...

184 Commits

Author SHA1 Message Date
sairajzero
8121a2ba96 Bug fix
- Fixed: mempool (unconfirmed tx) getting repeated in chain query when using before option
2023-04-27 04:15:43 +05:30
sairajzero
31344d770e Adding 'before' option to address APIs
- Similar to 'after' option but inverse of it. ie, if before txid is passed, then query list/values before the given txid
- 'before' and 'after' option can be use in combination or individually
- cache system for address summary api wont be used with 'after' and/or 'before' option is used
2023-04-27 03:48:09 +05:30
sairajzero
96677310c2 Bug fixes 2023-04-27 01:41:22 +05:30
sairajzero
e180672583 Adding reverse option to address history query
- Using option `reverse` as true will query the latest 1000 (max val) tx instead of the 1st 1000 tx.
2023-04-23 02:55:49 +05:30
sairajzero
158d5aefc2 Decrease MAX_TX_QUERY_LIMIT_SUMMARY to 500
- Summary cache is triggered for addresses with more than 500 tx
2023-04-22 23:55:11 +05:30
sairajzero
e7248320a6 bug fix: txid & blockhash not cached correctly 2023-04-22 22:19:23 +05:30
sairajzero
60289a644b Fix: Incorrect values in cache during reorg
- store the blockhash of lastTx in cache value
- If last cached tx-block was removed (during reorg), then delete the cache and recalculate the values.
2023-04-21 22:51:45 +05:30
sairajzero
d42e569008 update address-cache key prefix 2023-04-19 03:03:21 +05:30
sairajzero
6beb2ecd06 Adding function to delete cache for a given addr
Adding _deleteCache: deletes the cache for given address (useful for dev purposes or to recalculate caches)
2023-04-19 02:31:04 +05:30
sairajzero
4d023760ad Adding del (delete) function in db service 2023-04-19 02:28:44 +05:30
sairajzero
10d9459f26 Bug fix: unconfirmed-tx values corrupting cache 2023-04-19 01:24:37 +05:30
sairajzero
8b07a1e4a5 separate MAX_TX_QUERY_LIMIT for each query type 2023-04-19 01:03:45 +05:30
sairajzero
4afb0dfaaa Bug fix: cache summary not working properly 2023-04-19 00:45:44 +05:30
sairajzero
f8260541ef Fix: Cache value encoding
- Using BigInt (uInt64) for cache value (balance, sent, received) as they are large for uInt32
- Reflect the changes for BigInt (uInt64) in decode cache value
- Removed default values in cache encoding, as if a value is invalid then it must throw error and not write db
2023-04-19 00:42:47 +05:30
sairajzero
6b794aa9a3 Fixes: cache storing unconfirmed values
- removed unconfirmed values from cache store and get
-  do not update lastItem value for unconfirmed tx
2023-04-18 04:37:01 +05:30
sairajzero
adb81616aa Run cache summary
run cache storage for address summary in background when queried result is incomplete
2023-04-18 04:23:41 +05:30
sairajzero
3982807b32 Cache address-summary
Store cache of address summary in db when address has more than MAX_TX_QUERY_LIMIT
2023-04-17 20:13:29 +05:30
sairajzero
0a3a1b5ea6 changing typeof to equivalent lodash 2023-04-17 20:07:12 +05:30
sairajzero
df7710ded1 Adding option mempoolOnly in querying
- mempoolOnly option make the query in db from mempool only (ie, unconfirmed tx only
2023-04-13 03:52:02 +05:30
sairajzero
27f3993884 Fixed: inconsistency addrs API on multiple address
- Fixed: addrs API on multiple addresses when total tx is more than 1000 (MAX_TX_QUERY_LIMIT) giving inconsistent list of tx due to order messed up in parallel query
2023-04-13 02:26:33 +05:30
sairajzero
71bcafb243 Limited data responses identification
- address-query responses data has `incomplete` property set to `true` when addr has more than 1000 (MAX_TX_QUERY_LIMIT)
2023-04-11 04:04:19 +05:30
sairajzero
1b6352573f Limit all address query to MAX_TX_QUERY_LIMIT
- any address data API will now max out at 1000 (MAX_TX_QUERY_LIMIT)
- For addrs with more than 1000 tx, use chained API query to get the complete data (like balance, txid, etc)

- set parallel queue limit to 1: preserve consistency in API queries (and prevent incorrect data)
2023-04-11 03:49:21 +05:30
sairajzero
7f86e488e4 bug fix
Fixed bug: api on addr not giving response (timeoout) when it has only 1 tx
2023-04-06 22:25:03 +05:30
sairajzero
37e08b0801 Bug fix
- Fixed: Incorrect ordering of tx list with unconfirmed tx
2023-02-06 02:02:52 +05:30
Sai Raj
16bed1b811
Merge pull request #9 from ranchimall/api-improvements
API Improvements
2023-02-06 00:18:20 +05:30
sairajzero
bca4fe4f97 Bug fix
- Fixed: data inconsistency and continuity lost in chain querying of tx details
- Fixed: Not getting response when query has no tx. (ie, either address has no tx, or using the most recent tx as the key in `after` option)
2023-02-05 23:01:06 +05:30
sairajzero
7409dbb77d Bug fixes
- Fixed: incorrect data returned via `from` and `to` option
- Fixed: Missing data due to unordered items in getAddressHistory
- Fixed: callback invoked multiple items in _streamAddressSummary due to queue parallel limit
- Fixed: Queue drain being invoked before mempool txs are pushed into queue
2023-02-05 19:03:11 +05:30
sairajzero
774d830fff Improvements to API query options
- Stop request-stream process when stop-flag is on
- Changed: order of reading db to forward (so that continuity will be preserved with `after` option and ws api calls). And changes required for the same.
- Deprecating options (from and to) in calls that are not supported
- Added: Temporary support for from and to option in getAddressHistory
2023-02-05 03:12:04 +05:30
sairajzero
3a75002efc API Query options
- Fixed: option `start` to query from blockheight
- Added option `after`: pass this option in API to get list after the given txid
Note: If both `start` and `after` are given, then greater height will be used
Note: invalid or unconfirmed txid cannot be used in `after` option and will be ignored
2023-02-04 20:29:41 +05:30
sairajzero
d9579853ad Improve handling of duplicate tx query
- temporarily store txids to ignore duplication
- removed the queue pause() and resume() in _streamAddressSummary
2023-02-02 19:14:29 +05:30
sairajzero
3fbcbbe7bc Fixed: APIs giving incorrect data
- Fixed: addr API giving decimals in satoshi values
- Fixed: Incorrect balance, totalSent, totalReceived values returned in API calls (issue: duplication)
- Fixed: incorrect totalCount value in addr API and duplication of tx list
2023-01-28 21:55:58 +05:30
sairajzero
dbfe39991f Fixed: Address-summary request not responding 2023-01-28 02:04:40 +05:30
sairajzero
6c164993bf Update package.json 2023-01-27 22:33:30 +05:30
sairajzero
2145fdb056 pass 'express-ws' module to service setupRoutes
- flosight-api uses 'express-ws' module for ws api calls
2023-01-27 18:07:38 +05:30
sairajzero
4472ed8394 Changing fns to use _streamAddressSummary
Functions updated:
- getAddressHistory
- getAddressSummary

(old fns are kept as it is and renamed to __getAddressHistory and __getAddressSummary respectively)
2023-01-27 17:38:37 +05:30
sairajzero
e13bd5e3e6 Adding _streamAddressSummary
- Fn uses streamer to process data. Thus doesnt store the entire list of txid or tx details
- streamer fn can process the tx data as required
2023-01-27 17:36:39 +05:30
sairajzero
0283be05db Limit max response size 2023-01-27 17:31:02 +05:30
Sai Raj
25eb992cf1
Merge pull request #8 from ranchimall/block-subscribe-stuck-fix
Fix: Block subscribe getting stuck
2023-01-18 00:24:09 +05:30
sairajzero
69e9465b93 block service: set MAX_IGNORED_BLOCK to 16 2023-01-18 00:19:20 +05:30
sairajzero
700abe0500 hotfix: block subscription getting stuck
- Issue: Block subscription getting stuck when a (missing) block wasn't received by block service.
- Solution: Re-trigger the sync process when too many blocks ignored

- Others: fixed a typo in _reportInterval property
2023-01-17 21:54:48 +05:30
sairajzero
0572ee6b35 header: clear _syncCheckInterval upon synced
Header service: clear _syncCheckInterval to null when clearing interval after sync completed
2023-01-17 16:44:42 +05:30
Sai Raj
e6826c7dfc
Merge pull request #6 from ranchimall/startup-sync-fix
Startup sync fix
2023-01-15 12:33:50 +05:30
sairajzero
ece347c825 hotfix: best header not updating for prev fix
- updated header service best header from fcoin node directly.
- set interval check only if fcoin is started by flocore (else header best height ll not get updated and sync complete incorrectly)
2023-01-15 00:02:25 +05:30
sairajzero
b831cbce7e Update .gitignore 2023-01-14 23:56:18 +05:30
sairajzero
f9e2ed304b hotfix for unresponsive header sync 2023-01-11 03:38:38 +05:30
00515c5378
Update index.js
Added a missing return HeaderService.prototype._handleError
2023-01-09 05:12:39 +05:30
Sai Raj
e3f5de4df5
Merge pull request #3 from ranchimall/uncaught-no-shut
hotfix: Do not shutdown on unhandled exceptions
2023-01-08 17:36:33 +05:30
sairajzero
26b65d63a8 hotfix: Do not shutdown on unhandled exceptions 2023-01-08 17:13:30 +05:30
4113d9cfd0
Update index.js 2022-01-25 11:23:06 +05:30
7fa2f096df
Update reorg.js 2022-01-25 11:18:46 +05:30
fcecf08ac0
Update reorg.js 2022-01-25 11:18:13 +05:30
af6048de93
Update index.js 2022-01-25 11:13:27 +05:30
d47b6047e5
Update index.js 2022-01-25 11:00:27 +05:30
c525516a95
Update reorg.js 2022-01-25 10:57:40 +05:30
0eaa4b6fd2
Update index.js 2022-01-25 10:54:54 +05:30
2921e389df
Update block_handler.js 2022-01-25 00:31:31 +05:30
522d00bd52
Update index.js 2022-01-25 00:25:25 +05:30
821aae706d
Update index.js 2022-01-25 00:22:55 +05:30
18d1a16b0c
Update reorg.js 2022-01-25 00:07:57 +05:30
9c0ec67ccf
Update index.js 2022-01-25 00:03:52 +05:30
f0768027c9
Update index.js 2022-01-24 18:06:15 +05:30
80f22f731f
Update index.js 2022-01-24 17:57:48 +05:30
81a3d5f8ff
Update reorg.js 2022-01-24 17:56:37 +05:30
69fc6790ae
Update reorg.js 2022-01-24 17:55:39 +05:30
5db68b6bb7
Update reorg.js 2022-01-24 17:53:30 +05:30
091d7aa863
Update reorg.js 2022-01-24 17:52:14 +05:30
582bdd698a
Update reorg.js 2022-01-24 17:50:10 +05:30
726156843e
Update index.js 2022-01-24 17:45:10 +05:30
846f85e2f8
Update block_handler.js 2022-01-24 17:40:20 +05:30
ca47013c5a
Update block_handler.js 2022-01-24 15:17:50 +05:30
82357f2ecc
Update reorg.js 2022-01-24 15:17:02 +05:30
c3cc5f7465
Update index.js 2022-01-24 15:16:15 +05:30
1888b4a4ae
Throwing error removed
new Error was stopping the running instance of flosight. Substituted by log.info
2022-01-24 15:15:11 +05:30
1edc88f14b
Update node.js 2021-05-26 19:54:53 +05:30
0966ec124b
Stop the stoppage of service 2021-05-25 14:58:20 +05:30
05c6cd7739
Fixed header existence conditions 2021-05-25 11:07:56 +05:30
2c37e05ff7
Added test to check header.height 2021-05-25 11:01:31 +05:30
sairajzero
0cfb80a164 reverting log.info to log.debug 2021-05-24 17:56:13 +05:30
11b0a58351
Fixed syntax issue 2021-05-24 16:54:44 +05:30
869a7c21b4
Converted _sync log.debug to log.info 2021-05-24 16:29:15 +05:30
17dd83de10
db index.js asserts removed for resilience 2021-05-20 09:40:40 +05:30
bad1fb2552
Updated definition of index.log 2021-05-18 11:02:41 +05:30
5344d9cd5b
Fixed the conditional operator 2021-05-17 16:14:54 +05:30
89c43cd9a7
Fixing the conditional operator 2021-05-17 16:11:11 +05:30
0d4a7e3e42
Modification of condition operator 2021-05-17 16:06:06 +05:30
d689045002
Updated comparison operator 2021-05-17 16:00:27 +05:30
Vivek Teega
1efed08a39 1.0.9 Removing assertions in transction and p2p service 2021-05-17 14:02:31 +05:30
Vivek Teega
56e5cb1f25 1.0.8 Commented out assertion stops 2021-05-17 13:37:19 +05:30
Vivek Teega
453d11c64c 1.0.7 Commented out assertion stops 2021-05-17 12:59:36 +05:30
Vivek Teega
3598c92e0f 1.0.6 Commented out more node.stop() calls
- Commented out all node.stop() calls to prevent the node from exiting under various error conditions
2021-05-13 18:46:20 +05:30
Vivek Teega
0061285204 1.0.5 "return" was missing from lib/services/block/index.js
- Reverted back the previous 2 commits
- Added return to lib/services/block/index.js
2021-05-11 13:21:45 +05:30
Vivek Teega
3b8d992504 1.0.4 FLOsight Error Resolution
Keeping the return as, return next();
2021-05-11 13:11:51 +05:30
Vivek Teega
79fff4051b 1.0.3 FLOsight Error Resolution
Commenting out the part which makes the node
2021-05-11 13:09:50 +05:30
Vivek Teega
c3d32b7ffc FLO Crash Error Resolution 2021-05-10 12:39:02 +05:30
Vivek Teega
861e908080 Change in reorg operation
Reorg operation previously used to nuke 2000 block headers and redownload them from peers upon detecting a fork in the blockchain. Flosight has been crashing a lot because of this. We have updated the number of block headers to nuke to 20000
2021-04-12 15:04:07 +05:30
Sky Young
452596702a v5.0.8 2020-06-04 18:08:38 -06:00
Sky Young
0293a7acb2 Bump fcoin to v1.1.4
This fixes an issue on Regtest sync where blocks would stop at 4949
2020-06-04 18:07:33 -06:00
Sky Young
5ca1e5132b
Merge pull request #9 from oipwg/regtest-paramaters
Fix Regtest Support!
2020-01-09 12:09:21 -07:00
Sky Young
a7c8cd4563 Revert changes to header service 2020-01-09 12:02:17 -07:00
Sky Young
80912cc83f bump fcoin version 2020-01-09 11:52:03 -07:00
Sky Young
1eb2dbf29a v5.0.7 2020-01-09 09:11:32 -07:00
Sky Young
d8da495b38 Fix Regtest Support! 2020-01-08 16:14:59 -07:00
Sky Young
8e8e2310a0
Merge pull request #8 from oipwg/fcoin-1-1-2
Bump fcoin version to 1.1.2
2019-10-28 14:06:15 -06:00
Sky Young
45abcd6fa0 Bump fcoin version 2019-10-28 14:03:36 -06:00
Sky Young
c5e5d5a35e
Merge pull request #7 from oipwg/update-flosight-api-5.0.0-beta.75
Update `flosight-api` to 5.0.0 beta.75
2019-09-10 10:23:08 -06:00
Sky Young
9c19c84822 Update Mocha to fix security issue 2019-09-10 09:54:32 -06:00
Sky Young
9e3850b5c7 Update fcoin and flosight-api to latest 2019-09-10 09:52:28 -06:00
Sky Young
cbec5630d3
Merge pull request #6 from oipwg/fix-testnet-addresses
Pass network to Address.toString()
2019-08-16 10:19:38 -06:00
Sky Young
02cc97b0a1 Pass network to Address.toString() 2019-08-16 09:24:20 -06:00
Sky Young
6cd5093d4f
Merge pull request #5 from oipwg/fix-testnet-addresses
Update flosight-api to 5.0.0-beta.74
2019-08-15 17:11:49 -06:00
Sky Young
edf4b2a4f5 Update flosight-api to 5.0.0-beta.74 2019-08-15 17:10:19 -06:00
Sky Young
6e8d452174
Merge pull request #4 from oipwg/update-fcoin
Update fcoin to 1.1.0
2019-07-25 10:53:23 -06:00
Sky Young
cfc422600b Update to published npm versions 2019-07-25 10:50:34 -06:00
Sky Young
978679cad7 Pass fcoin Block template 2019-07-24 17:46:08 -06:00
Sky Young
b13b4f667b Update flocore-lib dependencies 2019-07-23 11:28:43 -06:00
Sky Young
ecf9bbaeea Properly import TX and Block from fcoin 2019-07-22 17:26:54 -06:00
Sky Young
4118f2f140 Update flocore-lib version 2019-07-22 17:25:29 -06:00
Sky Young
59d6cc0867 Handle shutdown of fcoin 2019-07-19 17:33:19 -06:00
Sky Young
53511b021d Gracefully handle SIGTERM 2019-07-19 15:58:38 -06:00
Sky Young
3a2f8d19de Update fcoin 2019-07-19 15:19:59 -06:00
Sky Young
10b25628ba
Merge pull request #3 from oipwg/5.0.1-ancestor-limit-increase
Update fcoin to use new utxo ancestor limit
2019-04-23 16:01:16 -06:00
Sky Young
416c804d8d Update fcoin to use new utxo ancestor limit 2019-04-23 16:00:25 -06:00
Sky Young
885b366422 Bump fcoin one last time :) 2018-10-18 19:26:32 -06:00
Sky Young
4dc88e2bc7 Update fcoin 2018-10-18 18:58:22 -06:00
Sky Young
be533c026f Update fcoin to fix testnet activation period 2018-10-18 18:23:51 -06:00
Sky Young
dad804eb64 Update fcoin dep again 2018-10-16 15:00:32 -06:00
Sky Young
66f2eba199 Update fcoin version 2018-10-16 14:54:40 -06:00
Sky Young
bab703a102 up dep 2018-10-04 13:48:01 -06:00
Sky Young
02006ed18c Set the network version of fcoin before importing wallet
https://github.com/oipwg/fcoin/blob/master/docs/Examples/fullnode-and-wallet.js#L2
2018-10-04 12:37:34 -06:00
Sky Young
b139c33726 use self._bcoin 2018-10-04 12:05:27 -06:00
Sky Young
1268b47d85 Startup a bcoin wallet as well 2018-10-04 12:00:57 -06:00
Sky Young
2b0815df6c plugin id is zmq not bzmq 2018-10-04 11:12:33 -06:00
Sky Young
6c6e0ad446 Add bzmq plugin to allow zmq access 2018-10-04 10:30:00 -06:00
Sky Young
06bb34123a Add config: true to fcoin config to allow use of fcoin.conf file in datadir
This is mainly to allow the setting and changing of API keys in a seperate file, in case people want to access
2018-10-03 13:04:34 -06:00
Sky Young
375ee80b5d Make sure it is the initial sync to log Sync Complete
this prevents logging of Sync Complete every time a new block is added
2018-08-27 12:13:00 -07:00
Sky Young
8715aa5071 Small formatting changes 2018-08-27 12:10:09 -07:00
Sky Young
f488a02d2d Fix syncComplete calculations
The _lastHeaderCount would always be 2000 behind upon startup, even if it is synced with the last header, causing no more headers to be synced. This fixes the issue that prevented syncing occasionally after restart.
2018-08-27 12:10:02 -07:00
Sky Young
db11257a43 Update p2p http RPC port 2018-08-06 15:48:13 -07:00
Sky Young
f37a3556e3 Merge branch 'bitpay-master' 2018-08-06 11:14:03 -07:00
Sky Young
e7ef0db2cb Merge branch 'master' of https://github.com/bitpay/bitcore-node into bitpay-master 2018-08-06 11:12:20 -07:00
Sky Young
ce85a3bede Add flosight-api and flosight-ui as default packages 2018-07-28 16:19:12 -07:00
Sky Young
b081c0a5f8 Only add tx to cache if it has at least 6 transactions 2018-06-08 15:48:39 -07:00
Sky Young
224733811c Update fcoin 2018-05-21 13:35:09 -07:00
Sky Young
c75c1fad61 Update fcoin 2018-05-21 13:12:33 -07:00
Sky Young
383f9f8b12 Update packages 2018-05-18 17:55:44 -07:00
Sky Young
b04ac5466f Update version 2018-05-17 09:58:59 -07:00
Sky Young
b1f828bea9 Revert "Update P2P Ports"
This reverts commit 57bc11a592.
2018-05-17 09:53:52 -07:00
Sky Young
dc7eacb112 Update Genesis Info 2018-05-17 09:47:23 -07:00
Sky Young
d45f6aecac Update protocol version 2018-05-17 09:38:20 -07:00
Sky Young
210b2fbcd7 Replace ts with time due to fcoin based on a higher version of lcoin 2018-05-17 09:36:43 -07:00
Sky Young
799675b234 Update printed version to 5.0.0 2018-05-17 09:35:44 -07:00
Sky Young
b9e4c8a6a5 move fcoin to bcoin 2018-05-17 09:35:30 -07:00
Sky Young
57bc11a592 Update P2P Ports 2018-05-17 09:35:18 -07:00
Sky Young
7ac4d51db1 Update Genesis Hashes to Flo 2018-05-17 08:59:20 -07:00
Sky Young
6358953553 Add Flo Ports 2018-05-16 11:03:32 -07:00
Sky Young
53b970cda7 Update default config path 2018-05-16 10:42:37 -07:00
Sky Young
01ebc7a521 update insight ref to flosight 2018-05-15 15:05:27 -07:00
Sky Young
fe2e29d74a Rename bcoin to fcoin 2018-05-15 15:04:33 -07:00
Sky Young
0588a5f69d Update version number 2018-05-15 14:25:59 -07:00
Sky Young
118280090c Update fcoin package version 2018-05-15 14:25:31 -07:00
Justin Langston
8e9ecff905
Merge branch 'feature/rpc-broadcast-transaction' 2018-05-11 00:12:49 -04:00
Micah Riggan
eb637d3125
Adding rpc for broadcastRawTransaction 2018-05-10 16:32:08 -04:00
Sky Young
2a2f661529 Dependencies: Update fcoin 2018-05-08 13:57:16 -07:00
Sky Young
17a4e0f0cc Use fcoin instead of bcoin 2018-05-08 13:48:43 -07:00
Sky Young
e0e8db1d43 Rename sample json 2018-05-07 16:39:01 -07:00
Sky Young
2fed6b4768 Rename to flocore 2018-05-07 16:30:08 -07:00
Sky Young
9f7587bd71 Update Package 2018-04-30 12:13:06 -07:00
Sky Young
7c8f7f4548 Update Packages 2018-04-30 11:00:14 -07:00
Justin Langston
e65689ab5d
Merge pull request #555 from bitpay/revert-553-revert-548-opt/txlist-cache
add txIdList cache
2018-04-12 14:57:54 -04:00
Matias Alejo Garcia
34f31ac57d
Revert "Revert "add txIdList cache"" 2018-04-12 14:41:18 -03:00
Matias Alejo Garcia
76c81c1dab
Merge pull request #553 from bitpay/revert-548-opt/txlist-cache
Revert "add txIdList cache"
2018-04-12 12:30:41 -03:00
Matias Alejo Garcia
bf8f25d9eb
Revert "add txIdList cache" 2018-04-12 12:30:09 -03:00
Matias Alejo Garcia
20a3f6e9fd
Merge pull request #548 from bitpay/opt/txlist-cache
add txIdList cache
2018-04-12 12:28:31 -03:00
Matias Alejo Garcia
ddda913ccd add txIdList cache 2018-02-12 00:48:30 -03:00
Justin Langston
11612e0877
Merge pull request #547 from bitpay/bug/sort-by-hash
fix history sorting when paging results
2018-02-11 18:55:04 -05:00
Matias Alejo Garcia
0c24271833 change order to 'desc' 2018-02-11 19:47:52 -03:00
Matias Alejo Garcia
01a3df31c8 fix history sorting when paging results 2018-02-11 15:44:39 -03:00
OstlerDev
4a9658184a btc -> flo 2018-01-15 16:43:07 -08:00
Chris Kleeschulte
9db5f2bb34
Bumped version. 2017-11-22 16:02:20 -05:00
Chris Kleeschulte
0e421de897
Fixed spent status from getAddressHistory. 2017-11-22 15:56:36 -05:00
Chris Kleeschulte
6e20b78b12
Bumped version. 2017-11-13 14:22:15 -05:00
Chris Kleeschulte
1dd17c92f2
Bumped version. 2017-11-13 09:54:02 -05:00
Chris Kleeschulte
aa44f2e18c
Bumped version. 2017-11-09 21:59:07 -05:00
Chris Kleeschulte
18a52c214d
Added a reorg to block. 2017-11-09 21:53:37 -05:00
73 changed files with 4980 additions and 3231 deletions

7
.gitignore vendored
View File

@ -21,13 +21,16 @@ coverage/*
**/*.config
**/*.creator
*.log
*.tmp
*.tmp.*
.DS_Store
bin/bitcoin*
bin/florincoin*
bin/SHA256SUMS.asc
regtest/data/node1/regtest
regtest/data/node2/regtest
regtest/data/node3/regtest
bitcore-node.json*
flocore-node.json*
*.bak
*.orig
lib/services/insight-api
testnet/*

View File

@ -22,12 +22,12 @@ coverage/*
**/*.creator
*.log
.DS_Store
bin/bitcoin*
bin/florincoin*
bin/SHA256SUMS.asc
regtest/data/node1/regtest
regtest/data/node2/regtest
regtest/data/node3/regtest
bitcore-node.json*
flocore-node.json*
*.bak
*.orig
lib/services/insight-api

View File

@ -1,7 +1,7 @@
Copyright (c) 2014-2015 BitPay, Inc.
Parts of this software are based on Bitcoin Core
Copyright (c) 2009-2015 The Bitcoin Core developers
Parts of this software are based on Florincoin Core
Copyright (c) 2009-2015 The Florincoin Core developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,20 +1,20 @@
Bitcore Node
Flocore Node
============
A Bitcoin blockchain indexing and query service. Intended to be used with as a Bitcoin full node or in conjunction with a Bitcoin full node.
A Florincoin blockchain indexing and query service. Intended to be used with as a Florincoin full node or in conjunction with a Florincoin full node.
## Upgrading from previous versions of Bitcore Node
## Upgrading from previous versions of Flocore Node
There is no upgrade path from previous versions of Bitcore Node due to the removal of the included Bitcoin Core software. By installing this version, you must resynchronize the indexes from scratch.
There is no upgrade path from previous versions of Flocore Node due to the removal of the included Florincoin Core software. By installing this version, you must resynchronize the indexes from scratch.
## Install
```bash
npm install
./bin/bitcore-node start
./bin/flocore-node start
```
Note: A default configuration file is placed in the bitcore user's home directory (~/.bitcore/bitcore-node.json). Or, alternatively, you can copy the provided "bitcore-node.json.sample" file to the project's root directory as bitcore-node.json and edit it for your preferences. If you don't have a preferred block source (trusted peer), [Bcoin](https://github.com/bcoin-org/bcoin) will be started automatically and synchronized with the mainnet chain.
Note: A default configuration file is placed in the flocore user's home directory (~/.flocore/flocore-node.json). Or, alternatively, you can copy the provided "flocore-node.json.sample" file to the project's root directory as flocore-node.json and edit it for your preferences. If you don't have a preferred block source (trusted peer), [Bcoin](https://github.com/bcoin-org/bcoin) will be started automatically and synchronized with the mainnet chain.
## Prerequisites
@ -24,21 +24,21 @@ Note: A default configuration file is placed in the bitcore user's home director
## Configuration
The main configuration file is called "bitcore-node.json". This file instructs bitcore-node for the following options:
The main configuration file is called "flocore-node.json". This file instructs flocore-node for the following options:
- location of database files (datadir)
- tcp port for web services, if configured (port)
- bitcoin network type (e.g. mainnet, testnet3, regtest), (network)
- florincoin network type (e.g. mainnet, testnet3, regtest), (network)
- what services to include (services)
- the services' configuration (servicesConfig)
## Add-on Services
There are several add-on services available to extend the functionality of Bitcore:
There are several add-on services available to extend the functionality of Flocore:
- [Insight API](https://github.com/bitpay/insight-api)
- [Insight UI](https://github.com/bitpay/insight-ui)
- [Bitcore Wallet Service](https://github.com/bitpay/bitcore-wallet-service)
- [Flocore Wallet Service](https://github.com/bitpay/flocore-wallet-service)
## Documentation
@ -60,12 +60,12 @@ There are several add-on services available to extend the functionality of Bitco
## Contributing
Please send pull requests for bug fixes, code optimization, and ideas for improvement. For more information on how to contribute, please refer to our [CONTRIBUTING](https://github.com/bitpay/bitcore/blob/master/CONTRIBUTING.md) file.
Please send pull requests for bug fixes, code optimization, and ideas for improvement. For more information on how to contribute, please refer to our [CONTRIBUTING](https://github.com/bitpay/flocore/blob/master/CONTRIBUTING.md) file.
## License
Code released under [the MIT license](https://github.com/bitpay/bitcore-node/blob/master/LICENSE).
Code released under [the MIT license](https://github.com/bitpay/flocore-node/blob/master/LICENSE).
Copyright 2013-2017 BitPay, Inc.
- bitcoin: Copyright (c) 2009-2015 Bitcoin Core Developers (MIT License)
- florincoin: Copyright (c) 2009-2015 Florincoin Core Developers (MIT License)

View File

@ -1 +0,0 @@
mtLDA41NWe9rLm7nuMvAnTs2SbP49cz1ZR

View File

@ -1,4 +0,0 @@
#!/usr/bin/env node
var bitcore = require('../lib/cli/bitcore');
bitcore();

4
bin/flocore-node Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env node
var flocore = require('../lib/cli/flocore');
flocore();

View File

@ -3,8 +3,8 @@
var levelup = require('levelup');
var leveldown = require('leveldown');
var Encoding = require('../lib/services/address/encoding');
var dbPath = '/Users/chrisk/.bwdb/bitcore-node.db';
var bitcore = require('bitcore-lib');
var dbPath = '/Users/chrisk/.bwdb/flocore-node.db';
var flocore = require('flocore-lib');
var db = levelup(dbPath, {keyEncoding: 'binary', valueEncoding: 'binary'});
var prefix = new Buffer('0002', 'hex');
@ -33,7 +33,7 @@ stream.on('data', function(data) {
for(var i = 0; i < inputValuesLength / 8; i++) {
inputValues.push(buffer.readDoubleBE(i * 8 + 14));
}
var transaction = new bitcore.Transaction(data.value.slice(inputValues.length * 8 + 14));
var transaction = new flocore.Transaction(data.value.slice(inputValues.length * 8 + 14));
transaction.__height = height;
transaction.__inputValues = inputValues;
transaction.__timestamp = timestamp;

View File

@ -6,6 +6,6 @@
# e.g. ./contrib/restart_bwdb.sh && tail -f /tmp/bwdb-out
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
pkill -2 -x bitcore
pkill -2 -x flocore
wait
exec $DIR/../bin/bitcore-node start >> /tmp/bwdb-out 2>&1 &
exec $DIR/../bin/flocore-node start >> /tmp/bwdb-out 2>&1 &

View File

@ -4,14 +4,14 @@ Requires=network.target
[Service]
Type=simple
WorkingDirectory=/usr/opt/bitcore
WorkingDirectory=/usr/opt/flocore
ExecStart=/usr/bin/bwdb
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=15
User=bitcore
User=flocore
ExecStartPre=/bin/mkdir -p /run/bwdb
ExecStartPre=/bin/chown bitcore:bitcore /run/bwdb
ExecStartPre=/bin/chown flocore:flocore /run/bwdb
ExecStartPre=/bin/chmod 755 /run/bwdb
PermissionsStartOnly=true
TimeoutStopSec=300

View File

@ -1,5 +1,5 @@
# Bus
The bus provides a way to subscribe to events from any of the services running. It's implemented abstract from transport specific implementation. The primary use of the bus in Bitcore Node is for subscribing to events via a web socket.
The bus provides a way to subscribe to events from any of the services running. It's implemented abstract from transport specific implementation. The primary use of the bus in Flocore Node is for subscribing to events via a web socket.
## Opening/Closing
@ -20,11 +20,11 @@ bus.close();
```javascript
// subscribe to all transaction events
bus.subscribe('bitcoind/rawtransaction');
bus.subscribe('florincoind/rawtransaction');
// to subscribe to new block hashes
bus.subscribe('bitcoind/hashblock');
bus.subscribe('florincoind/hashblock');
// unsubscribe
bus.unsubscribe('bitcoind/rawtransaction');
bus.unsubscribe('florincoind/rawtransaction');
```

View File

@ -10,22 +10,22 @@ nvm install v4
## Fork and Download Repositories
To develop bitcore-node:
To develop flocore-node:
```bash
cd ~
git clone git@github.com:<yourusername>/bitcore-node.git
git clone git@github.com:<yourusername>/bitcore-lib.git
git clone git@github.com:<yourusername>/flocore-node.git
git clone git@github.com:<yourusername>/flocore-lib.git
```
To develop bitcoin or to compile from source:
To develop florincoin or to compile from source:
```bash
git clone git@github.com:<yourusername>/bitcoin.git
git clone git@github.com:<yourusername>/florincoin.git
git fetch origin <branchname>:<branchname>
git checkout <branchname>
```
**Note**: See bitcoin documentation for building bitcoin on your platform.
**Note**: See florincoin documentation for building florincoin on your platform.
## Install Development Dependencies
@ -46,27 +46,27 @@ brew install zeromq
## Install and Symlink
```bash
cd bitcore-lib
cd flocore-lib
npm install
cd ../bitcore-node
cd ../flocore-node
npm install
```
**Note**: If you get a message about not being able to download bitcoin distribution, you'll need to compile bitcoind from source, and setup your configuration to use that version.
**Note**: If you get a message about not being able to download florincoin distribution, you'll need to compile florincoind from source, and setup your configuration to use that version.
We now will setup symlinks in `bitcore-node` *(repeat this for any other modules you're planning on developing)*:
We now will setup symlinks in `flocore-node` *(repeat this for any other modules you're planning on developing)*:
```bash
cd node_modules
rm -rf bitcore-lib
ln -s ~/bitcore-lib
rm -rf bitcoind-rpc
ln -s ~/bitcoind-rpc
rm -rf flocore-lib
ln -s ~/flocore-lib
rm -rf florincoind-rpc
ln -s ~/florincoind-rpc
```
And if you're compiling or developing bitcoin:
And if you're compiling or developing florincoin:
```bash
cd ../bin
ln -sf ~/bitcoin/src/bitcoind
ln -sf ~/florincoin/src/florincoind
```
## Run Tests
@ -78,19 +78,19 @@ npm install mocha -g
To run all test suites:
```bash
cd bitcore-node
cd flocore-node
npm run regtest
npm run test
```
To run a specific unit test in watch mode:
```bash
mocha -w -R spec test/services/bitcoind.unit.js
mocha -w -R spec test/services/florincoind.unit.js
```
To run a specific regtest:
```bash
mocha -R spec regtest/bitcoind.js
mocha -R spec regtest/florincoind.js
```
## Running a Development Node
@ -102,27 +102,27 @@ cd ~
mkdir devnode
cd devnode
mkdir node_modules
touch bitcore-node.json
touch flocore-node.json
touch package.json
```
Edit `bitcore-node.json` with something similar to:
Edit `flocore-node.json` with something similar to:
```json
{
"network": "livenet",
"port": 3001,
"services": [
"bitcoind",
"florincoind",
"web",
"insight-api",
"insight-ui",
"<additional_service>"
],
"servicesConfig": {
"bitcoind": {
"florincoind": {
"spawn": {
"datadir": "/home/<youruser>/.bitcoin",
"exec": "/home/<youruser>/bitcoin/src/bitcoind"
"datadir": "/home/<youruser>/.florincoin",
"exec": "/home/<youruser>/florincoin/src/florincoind"
}
}
}
@ -135,13 +135,13 @@ Setup symlinks for all of the services and dependencies:
```bash
cd node_modules
ln -s ~/bitcore-lib
ln -s ~/bitcore-node
ln -s ~/flocore-lib
ln -s ~/flocore-node
ln -s ~/insight-api
ln -s ~/insight-ui
```
Make sure that the `<datadir>/bitcoin.conf` has the necessary settings, for example:
Make sure that the `<datadir>/florincoin.conf` has the necessary settings, for example:
```
server=1
whitelist=127.0.0.1
@ -152,11 +152,11 @@ spentindex=1
zmqpubrawtx=tcp://127.0.0.1:28332
zmqpubhashblock=tcp://127.0.0.1:28332
rpcallowip=127.0.0.1
rpcuser=bitcoin
rpcuser=florincoin
rpcpassword=local321
```
From within the `devnode` directory with the configuration file, start the node:
```bash
../bitcore-node/bin/bitcore-node start
../flocore-node/bin/flocore-node start
```

View File

@ -14,17 +14,17 @@ A node represents a collection of services that are loaded together. For more in
```js
var index = require('bitcore-node');
var Bitcoin = index.services.Bitcoin;
var index = require('flocore-node');
var Florincoin = index.services.Florincoin;
var Node = index.Node;
var configuration = {
datadir: '/home/user/.bitcoin',
datadir: '/home/user/.florincoin',
network: 'testnet',
services: [
{
name: 'bitcoind',
module: Bitcoin,
name: 'florincoind',
module: Florincoin,
config: {}
}
]
@ -37,7 +37,7 @@ node.start(function() {
});
node.on('ready', function() {
console.log('Bitcoin Node Ready');
console.log('Florincoin Node Ready');
});
node.on('error', function(err) {

View File

@ -1,10 +1,10 @@
# Release Process
Binaries for bitcoind are distributed for convenience and built deterministically with Gitian, signatures for bitcoind are located at the [gitian.sigs](https://github.com/bitpay/gitian.sigs) respository.
Binaries for florincoind are distributed for convenience and built deterministically with Gitian, signatures for florincoind are located at the [gitian.sigs](https://github.com/bitpay/gitian.sigs) respository.
## How to Release
When publishing to npm, the .gitignore file is used to exclude files from the npm publishing process. Be sure that the bitcore-node directory has only the directories and files that you would like to publish to npm. You might need to run the commands below on each platform that you intend to publish (e.g. Mac and Linux).
When publishing to npm, the .gitignore file is used to exclude files from the npm publishing process. Be sure that the flocore-node directory has only the directories and files that you would like to publish to npm. You might need to run the commands below on each platform that you intend to publish (e.g. Mac and Linux).
To make a release, bump the `version` of the `package.json`:

View File

@ -1,20 +1,20 @@
# Scaffold
A collection of functions for creating, managing, starting, stopping and interacting with a Bitcore node.
A collection of functions for creating, managing, starting, stopping and interacting with a Flocore node.
## Install
This function will add a service to a node by installing the necessary dependencies and modifying the `bitcore-node.json` configuration.
This function will add a service to a node by installing the necessary dependencies and modifying the `flocore-node.json` configuration.
## Start
This function will load a configuration file `bitcore-node.json` and instantiate and start a node based on the configuration.
This function will load a configuration file `flocore-node.json` and instantiate and start a node based on the configuration.
## Find Config
This function will recursively find a configuration `bitcore-node.json` file in parent directories and return the result.
This function will recursively find a configuration `flocore-node.json` file in parent directories and return the result.
## Default Config
This function will return a default configuration with the default services based on environment variables, and will default to using the standard `/home/user/.bitcoin` data directory.
This function will return a default configuration with the default services based on environment variables, and will default to using the standard `/home/user/.florincoin` data directory.
## Uninstall
This function will remove a service from a node by uninstalling the necessary dependencies and modifying the `bitcore-node.json` configuration.
This function will remove a service from a node by uninstalling the necessary dependencies and modifying the `flocore-node.json` configuration.
## Call Method
This function will call an API method on a node via the JSON-RPC interface.

View File

@ -1,16 +1,16 @@
# Services
Bitcore Node has a service module system that can start up additional services that can include additional:
Flocore Node has a service module system that can start up additional services that can include additional:
- Blockchain indexes (e.g. querying balances for addresses)
- API methods
- HTTP routes
- Event types to publish and subscribe
The `bitcore-node.json` file describes which services will load for a node:
The `flocore-node.json` file describes which services will load for a node:
```json
{
"services": [
"bitcoind", "web"
"florincoind", "web"
]
}
```
@ -20,36 +20,36 @@ Services correspond with a Node.js module as described in 'package.json', for ex
```json
{
"dependencies": {
"bitcore-lib": "^0.13.7",
"bitcore-node": "^0.2.0",
"flocore-lib": "^0.13.7",
"flocore-node": "^0.2.0",
"insight-api": "^3.0.0"
}
}
```
_Note:_ If you already have a bitcore-node database, and you want to query data from previous blocks in the blockchain, you will need to reindex. Reindexing right now means deleting your bitcore-node database and resyncing.
_Note:_ If you already have a flocore-node database, and you want to query data from previous blocks in the blockchain, you will need to reindex. Reindexing right now means deleting your flocore-node database and resyncing.
## Using Services Programmatically
If, instead, you would like to run a custom node, you can include services by including them in your configuration object when initializing a new node.
```js
//Require bitcore
var bitcore = require('bitcore-node');
//Require flocore
var flocore = require('flocore-node');
//Services
var Bitcoin = bitcore.services.Bitcoin;
var Web = bitcore.services.Web;
var Florincoin = flocore.services.Florincoin;
var Web = flocore.services.Web;
var myNode = new bitcore.Node({
var myNode = new flocore.Node({
network: 'regtest'
services: [
{
name: 'bitcoind',
module: Bitcoin,
name: 'florincoind',
module: Florincoin,
config: {
spawn: {
datadir: '/home/<username>/.bitcoin',
exec: '/home/<username>/bitcore-node/bin/bitcoind'
datadir: '/home/<username>/.florincoin',
exec: '/home/<username>/flocore-node/bin/florincoind'
}
}
},
@ -67,7 +67,7 @@ var myNode = new bitcore.Node({
Now that you've loaded your services you can access them via `myNode.services.<service-name>.<method-name>`. For example if you wanted to check the balance of an address, you could access the address service like so.
```js
myNode.services.bitcoind.getAddressBalance('1HB5XMLmzFVj8ALj6mfBsbifRoD4miY36v', false, function(err, total) {
myNode.services.florincoind.getAddressBalance('1HB5XMLmzFVj8ALj6mfBsbifRoD4miY36v', false, function(err, total) {
console.log(total.balance); //Satoshi amount of this address
});
```
@ -82,7 +82,7 @@ A new service can be created by inheriting from `Node.Service` and implementing
- `Service.prototype.getPublishEvents()` - Describes which events can be subscribed to for this service, useful to subscribe to events over the included web socket API.
- `Service.prototype.setupRoutes()` - A service can extend HTTP routes on an express application by implementing this method.
The `package.json` for the service module can either export the `Node.Service` directly, or specify a specific module to load by including `"bitcoreNode": "lib/bitcore-node.js"`.
The `package.json` for the service module can either export the `Node.Service` directly, or specify a specific module to load by including `"flocoreNode": "lib/flocore-node.js"`.
Please take a look at some of the existing services for implementation specifics.

View File

@ -1,13 +1,13 @@
# Address Service
The address service provides an address index for the Bitcoin blockchain. Specifically, it builds and maintains the following information about every address ever used on the Bitcoin network:
The address service provides an address index for the Florincoin blockchain. Specifically, it builds and maintains the following information about every address ever used on the Florincoin network:
- block heights the address appeared in
- transaction ids and the index in the transaction
- whether the address appeared in an input or output
- the timestamp for the block
Additionally, the address index also maintains the unspent transaction output index for the Bitcoin blockchain. Example queries for this type of data is provided by 'getAddressUnspentOutputs', 'getAddressSummary', and 'getAddressHistory'.
Additionally, the address index also maintains the unspent transaction output index for the Florincoin blockchain. Example queries for this type of data is provided by 'getAddressUnspentOutputs', 'getAddressSummary', and 'getAddressHistory'.
This service is generally used to support other services and is not used externally.

View File

@ -1,6 +1,6 @@
# Block Service
The block service provides a block index for the Bitcoin blockchain. Specifically, there are two data points this service tracks:
The block service provides a block index for the Florincoin blockchain. Specifically, there are two data points this service tracks:
- block hash
- raw block

View File

@ -1,6 +1,6 @@
# Db Service
The db service provides an abstraction over the underlying database used to store the indexes in bitcore-node.
The db service provides an abstraction over the underlying database used to store the indexes in flocore-node.
## Service Configuration

View File

@ -1,6 +1,6 @@
# Fee Service
The fee service is a requirement of the insight-api service (not a bitcore-node built-in service). Its primary purpose is to query a bitcoin full node for the most up-to-date miner fees for transactions. A bitcoin full node such as [BTC1](https://github.com/btc1/bitcoin) or [bcoin](https://github.com/bcoin-org/bcoin) with an available RPC interface is required.
The fee service is a requirement of the insight-api service (not a flocore-node built-in service). Its primary purpose is to query a florincoin full node for the most up-to-date miner fees for transactions. A florincoin full node such as [BTC1](https://github.com/btc1/florincoin) or [bcoin](https://github.com/bcoin-org/bcoin) with an available RPC interface is required.
## Service Configuration

View File

@ -1,6 +1,6 @@
# Header Service
The header service provides a header index for the Bitcoin blockchain. Specifically, it builds and maintains the following information about every bitcoin block header:
The header service provides a header index for the Florincoin blockchain. Specifically, it builds and maintains the following information about every florincoin block header:
- block hash
- block height

View File

@ -1,6 +1,6 @@
# Mempool Service
The mempool service provides a mempool transaction index for the Bitcoin blockchain. Specifically, it maintains a larger index of mempool transactions than a typical full node can manage on its own.
The mempool service provides a mempool transaction index for the Florincoin blockchain. Specifically, it maintains a larger index of mempool transactions than a typical full node can manage on its own.
- transaction id
- transaction

View File

@ -1,9 +1,9 @@
# P2P Service
The p2p service provides a peer-to-peer interface for the Bitcoin blockchain. This service abstracts the connection and commnuication interface between the Bitcoin and the rest of bitcore node.
The p2p service provides a peer-to-peer interface for the Florincoin blockchain. This service abstracts the connection and commnuication interface between the Florincoin and the rest of flocore node.
This service also provides the publisher interface on bitcore-node bus architecture. The P2P service will publish header, block and transaction events.
This service also provides the publisher interface on flocore-node bus architecture. The P2P service will publish header, block and transaction events.
## Service Configuration

View File

@ -1,6 +1,6 @@
# Timestamp Service
The timestamp service provides a block timestamp index for the Bitcoin blockchain. The only reason this index needs to exist is to ensure that block timestamps are always strictly greater than all the previous block timestamps. In the native block timestamps, this is not always the case. Without this index, accounting systems that are based on time spans (pretty much all of them), there will be issues accounting for transactions accurately.
The timestamp service provides a block timestamp index for the Florincoin blockchain. The only reason this index needs to exist is to ensure that block timestamps are always strictly greater than all the previous block timestamps. In the native block timestamps, this is not always the case. Without this index, accounting systems that are based on time spans (pretty much all of them), there will be issues accounting for transactions accurately.
- block timestamp
- block hash

View File

@ -1,6 +1,6 @@
# Transaction Service
The transaction service provides a transaction index for the Bitcoin blockchain. Specifically, it builds and maintains the following information about every transaction on the Bitcoin network:
The transaction service provides a transaction index for the Florincoin blockchain. Specifically, it builds and maintains the following information about every transaction on the Florincoin network:
- transaction ids and transactions
- input values for every transaction

View File

@ -1,5 +1,5 @@
# Web Service
The web service creates an express app which can be used by services for setting up web routes for API's, static content, web applications, etc. This allows users to interact with various bitcore node services over one http or https port.
The web service creates an express app which can be used by services for setting up web routes for API's, static content, web applications, etc. This allows users to interact with various flocore node services over one http or https port.
In order for your service to add routes, it must implement the `setupRoutes()` and `getRoutePrefix()` methods.
@ -22,7 +22,7 @@ MyService.prototype.getRoutePrefix = function() {
```
## Configuring Web Service for HTTPS
You can run the web service over https by editing your bitcore node config, setting https to true and adding httpsOptions:
You can run the web service over https by editing your flocore node config, setting https to true and adding httpsOptions:
```json
{

View File

@ -1,14 +1,14 @@
# Upgrade Notes
## From Bitcore 3.0.0 to 4.0.0
## From Flocore 3.0.0 to 4.0.0
`bitcore-node@2.1.1` to `bitcore-node@3.0.0`
`flocore-node@2.1.1` to `flocore-node@3.0.0`
This major upgrade includes changes to indexes, API methods and services. Please review below details before upgrading.
### Indexes
Indexes include *more information* and are now also *faster*. Because of this a **reindex will be necessary** when upgrading as the address and database indexes are now a part of bitcoind with three new `bitcoin.conf` options:
Indexes include *more information* and are now also *faster*. Because of this a **reindex will be necessary** when upgrading as the address and database indexes are now a part of florincoind with three new `florincoin.conf` options:
- `-addressindex`
- `-timestampindex`
- `-spentindex`
@ -17,18 +17,18 @@ To start reindexing add `reindex=1` during the **first startup only**.
### Configuration Options
- The `bitcoin.conf` file in will need to be updated to include additional indexes *(see below)*.
- The `datadir` option is now a part of `bitcoind` spawn configuration, and there is a new option to connect to multiple bitcoind processes (Please see [Bitcoin Service Docs](services/bitcoind.md) for more details). The services `db` and `address` are now a part of the `bitcoind` service. Here is how to update `bitcore-node.json` configuration options:
- The `florincoin.conf` file in will need to be updated to include additional indexes *(see below)*.
- The `datadir` option is now a part of `florincoind` spawn configuration, and there is a new option to connect to multiple florincoind processes (Please see [Florincoin Service Docs](services/florincoind.md) for more details). The services `db` and `address` are now a part of the `florincoind` service. Here is how to update `flocore-node.json` configuration options:
**Before**:
```json
{
"datadir": "/home/<username>/.bitcoin",
"datadir": "/home/<username>/.florincoin",
"network": "livenet",
"port": 3001,
"services": [
"address",
"bitcoind",
"florincoind",
"db",
"web"
]
@ -41,21 +41,21 @@ To start reindexing add `reindex=1` during the **first startup only**.
"network": "livenet",
"port": 3001,
"services": [
"bitcoind",
"florincoind",
"web"
],
"servicesConfig": {
"bitcoind": {
"florincoind": {
"spawn": {
"datadir": "/home/<username>/.bitcoin",
"exec": "/home/<username>/bitcore-node/bin/bitcoind"
"datadir": "/home/<username>/.florincoin",
"exec": "/home/<username>/flocore-node/bin/florincoind"
}
}
}
}
```
It will also be necessary to update `bitcoin.conf` settings, to include these fields:
It will also be necessary to update `florincoin.conf` settings, to include these fields:
```
server=1
whitelist=127.0.0.1
@ -70,8 +70,8 @@ rpcuser=<user>
rpcpassword=<password>
```
**Important**: Once changes have been made you'll also need to add the `reindex=1` option **only for the first startup** to regenerate the indexes. Once this is complete you should be able to remove the `bitcore-node.db` directory with the old indexes.
**Important**: Once changes have been made you'll also need to add the `reindex=1` option **only for the first startup** to regenerate the indexes. Once this is complete you should be able to remove the `flocore-node.db` directory with the old indexes.
### API and Service Changes
- Many API methods that were a part of the `db` and `address` services are now a part of the `bitcoind` service. Please see [Bitcoin Service Docs](services/bitcoind.md) for more details.
- The `db` and `address` services are deprecated, most of the functionality still exists. Any services that were extending indexes with the `db` service, will need to manage chain state itself, or build the indexes within `bitcoind`.
- Many API methods that were a part of the `db` and `address` services are now a part of the `florincoind` service. Please see [Florincoin Service Docs](services/florincoind.md) for more details.
- The `db` and `address` services are deprecated, most of the functionality still exists. Any services that were extending indexes with the `db` service, will need to manage chain state itself, or build the indexes within `florincoind`.

View File

@ -20,7 +20,7 @@ module.exports.scaffold.defaultConfig = require('./lib/scaffold/default-config')
module.exports.cli = {};
module.exports.cli.main = require('./lib/cli/main');
module.exports.cli.daemon = require('./lib/cli/daemon');
module.exports.cli.bitcore = require('./lib/cli/bitcore');
module.exports.cli.bitcored = require('./lib/cli/bitcored');
module.exports.cli.flocore = require('./lib/cli/flocore');
module.exports.cli.flocored = require('./lib/cli/flocored');
module.exports.lib = require('bitcore-lib');
module.exports.lib = require('flocore-lib');

View File

@ -2,20 +2,20 @@
var program = require('commander');
var path = require('path');
var bitcore = require('..');
var flocore = require('..');
function main(servicesPath, additionalServices) {
/* jshint maxstatements: 100 */
var version = bitcore.version;
var start = bitcore.scaffold.start;
var findConfig = bitcore.scaffold.findConfig;
var defaultConfig = bitcore.scaffold.defaultConfig;
var version = flocore.version;
var start = flocore.scaffold.start;
var findConfig = flocore.scaffold.findConfig;
var defaultConfig = flocore.scaffold.defaultConfig;
program
.version(version)
.description('Start the current node')
.option('-c, --config <dir>', 'Specify the directory with Bitcore Node configuration');
.option('-c, --config <dir>', 'Specify the directory with Flocore Node configuration');
program.parse(process.argv);

View File

@ -5,10 +5,10 @@ var Liftoff = require('liftoff');
function main(parentServicesPath, additionalServices) {
var liftoff = new Liftoff({
name: 'bitcore',
moduleName: 'bitcore-node',
configName: 'bitcore-node',
processTitle: 'bitcore'
name: 'flocore',
moduleName: 'flocore-node',
configName: 'flocore-node',
processTitle: 'flocore'
}).on('require', function (name) {
console.log('Loading:', name);
}).on('requireFail', function (name, err) {
@ -31,6 +31,15 @@ function main(parentServicesPath, additionalServices) {
node.cli.main(parentServicesPath, additionalServices);
}
// Gracefully Shut Down
process.on('SIGTERM', function () {
console.log("Shutting down flocore-node")
node.stop(function() {
console.log("flocore-node successfully stopped!")
process.exit(0)
})
})
});
}

View File

@ -5,10 +5,10 @@ var Liftoff = require('liftoff');
function main(parentServicesPath, additionalServices) {
var liftoff = new Liftoff({
name: 'bitcored',
moduleName: 'bitcore-node',
configName: 'bitcore-node',
processTitle: 'bitcored'
name: 'flocored',
moduleName: 'flocore-node',
configName: 'flocore-node',
processTitle: 'flocored'
}).on('require', function (name) {
console.log('Loading:', name);
}).on('requireFail', function (name, err) {

View File

@ -2,20 +2,20 @@
var program = require('commander');
var path = require('path');
var bitcorenode = require('..');
var flocorenode = require('..');
var utils = require('../utils');
function main(servicesPath, additionalServices) {
/* jshint maxstatements: 100 */
var version = bitcorenode.version;
var create = bitcorenode.scaffold.create;
var add = bitcorenode.scaffold.add;
var start = bitcorenode.scaffold.start;
var remove = bitcorenode.scaffold.remove;
var callMethod = bitcorenode.scaffold.callMethod;
var findConfig = bitcorenode.scaffold.findConfig;
var defaultConfig = bitcorenode.scaffold.defaultConfig;
var version = flocorenode.version;
var create = flocorenode.scaffold.create;
var add = flocorenode.scaffold.add;
var start = flocorenode.scaffold.start;
var remove = flocorenode.scaffold.remove;
var callMethod = flocorenode.scaffold.callMethod;
var findConfig = flocorenode.scaffold.findConfig;
var defaultConfig = flocorenode.scaffold.defaultConfig;
program
.version(version);
@ -23,7 +23,7 @@ function main(servicesPath, additionalServices) {
program
.command('create <directory>')
.description('Create a new node')
.option('-d, --datadir <dir>', 'Specify the bitcoin database directory')
.option('-d, --datadir <dir>', 'Specify the florincoin database directory')
.option('-t, --testnet', 'Enable testnet as the network')
.action(function(dirname, cmd){
if (cmd.datadir) {
@ -49,7 +49,7 @@ function main(servicesPath, additionalServices) {
program
.command('start')
.description('Start the current node')
.option('-c, --config <dir>', 'Specify the directory with Bitcore Node configuration')
.option('-c, --config <dir>', 'Specify the directory with Flocore Node configuration')
.action(function(cmd){
if (cmd.config) {
cmd.config = path.resolve(process.cwd(), cmd.config);
@ -72,7 +72,7 @@ function main(servicesPath, additionalServices) {
.action(function(services){
var configInfo = findConfig(process.cwd());
if (!configInfo) {
throw new Error('Could not find configuration, see `bitcore-node create --help`');
throw new Error('Could not find configuration, see `flocore-node create --help`');
}
var opts = {
path: configInfo.path,
@ -87,8 +87,8 @@ function main(servicesPath, additionalServices) {
}).on('--help', function() {
console.log(' Examples:');
console.log();
console.log(' $ bitcore-node add wallet-service');
console.log(' $ bitcore-node add insight-api');
console.log(' $ flocore-node add wallet-service');
console.log(' $ flocore-node add insight-api');
console.log();
});
@ -98,7 +98,7 @@ function main(servicesPath, additionalServices) {
.action(function(services){
var configInfo = findConfig(process.cwd());
if (!configInfo) {
throw new Error('Could not find configuration, see `bitcore-node create --help`');
throw new Error('Could not find configuration, see `flocore-node create --help`');
}
var opts = {
path: configInfo.path,
@ -113,8 +113,8 @@ function main(servicesPath, additionalServices) {
}).on('--help', function() {
console.log(' Examples:');
console.log();
console.log(' $ bitcore-node remove wallet-service');
console.log(' $ bitcore-node remove insight-api');
console.log(' $ flocore-node remove wallet-service');
console.log(' $ flocore-node remove insight-api');
console.log();
});

View File

@ -3,9 +3,9 @@
module.exports = {
BITCOIN_GENESIS_HASH: {
livenet: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f',
regtest: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206',
testnet: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943', //this is testnet3
livenet: '09c7781c9df90708e278c35d38ea5c9041d7ecfcdd1c56ba67274b7cff3e1cea',
regtest: 'ec42fa26ca6dcb1103b59a1d24b161935ea4566f8d5736db8917d5b9a8dee0d7',
testnet: '9b7bc86236c34b5e3a39367c036b7fe8807a966c22a7a1f0da2a198a27e03731', //this is testnet3
testnet5: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943' //this is testnet5
},
DB_PREFIX: new Buffer('ffff', 'hex')

View File

@ -2,11 +2,11 @@
var createError = require('errno').create;
var BitcoreNodeError = createError('BitcoreNodeError');
var FlocoreNodeError = createError('FlocoreNodeError');
var RPCError = createError('RPCError', BitcoreNodeError);
var RPCError = createError('RPCError', FlocoreNodeError);
module.exports = {
Error: BitcoreNodeError,
Error: FlocoreNodeError,
RPCError: RPCError
};

View File

@ -1,7 +1,7 @@
'use strict';
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var _ = flocore.deps._;
var colors = require('colors/safe');
/**

View File

@ -4,8 +4,8 @@ var util = require('util');
var EventEmitter = require('events').EventEmitter;
var async = require('async');
var assert = require('assert');
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var _ = flocore.deps._;
var index = require('./');
var log = index.log;
var Bus = require('./bus');
@ -226,7 +226,7 @@ Node.prototype.stop = function(callback) {
if (callback) {
callback();
}
});
});
};
module.exports = Node;

View File

@ -4,10 +4,10 @@ var async = require('async');
var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var bitcore = require('bitcore-lib');
var flocore = require('flocore-lib');
var utils = require('../utils');
var $ = bitcore.util.preconditions;
var _ = bitcore.deps._;
var $ = flocore.util.preconditions;
var _ = flocore.deps._;
/**
* @param {String} configFilePath - The absolute path to the configuration file
@ -62,7 +62,7 @@ function addService(configDir, service, done) {
/**
* @param {String} options.cwd - The current working directory
* @param {String} options.dirname - The bitcore-node configuration directory
* @param {String} options.dirname - The flocore-node configuration directory
* @param {Array} options.services - An array of strings of service names
* @param {Function} done - A callback function called when finished
*/
@ -78,12 +78,12 @@ function add(options, done) {
var configPath = options.path;
var services = options.services;
var bitcoreConfigPath = path.resolve(configPath, 'bitcore-node.json');
var flocoreConfigPath = path.resolve(configPath, 'flocore-node.json');
var packagePath = path.resolve(configPath, 'package.json');
if (!fs.existsSync(bitcoreConfigPath) || !fs.existsSync(packagePath)) {
if (!fs.existsSync(flocoreConfigPath) || !fs.existsSync(packagePath)) {
return done(
new Error('Directory does not have a bitcore-node.json and/or package.json file.')
new Error('Directory does not have a flocore-node.json and/or package.json file.')
);
}
@ -108,8 +108,8 @@ function add(options, done) {
oldPackage = updatedPackage;
var serviceName = newDependencies[0];
// add service to bitcore-node.json
addConfig(bitcoreConfigPath, serviceName, next);
// add service to flocore-node.json
addConfig(flocoreConfigPath, serviceName, next);
});
}, done
);

View File

@ -1,10 +1,10 @@
'use strict';
var spawn = require('child_process').spawn;
var bitcore = require('bitcore-lib');
var flocore = require('flocore-lib');
var async = require('async');
var $ = bitcore.util.preconditions;
var _ = bitcore.deps._;
var $ = flocore.util.preconditions;
var _ = flocore.deps._;
var path = require('path');
var packageFile = require('../../package.json');
var mkdirp = require('mkdirp');
@ -14,22 +14,22 @@ var defaultConfig = require('./default-config');
var version = '^' + packageFile.version;
var BASE_PACKAGE = {
description: 'A full Bitcoin node build with Bitcore',
description: 'A full Florincoin node build with Flocore',
repository: 'https://github.com/user/project',
license: 'MIT',
readme: 'README.md',
dependencies: {
'bitcore-lib': '^' + bitcore.version,
'bitcore-node': version
'flocore-lib': '^' + flocore.version,
'flocore-node': version
}
};
/**
* Will create a directory and bitcoin.conf file for Bitcoin.
* Will create a directory and florincoin.conf file for Florincoin.
* @param {String} dataDir - The absolute path
* @param {Function} done - The callback function called when finished
*/
function createBitcoinDirectory(datadir, done) {
function createFlorincoinDirectory(datadir, done) {
mkdirp(datadir, function(err) {
if (err) {
throw err;
@ -42,10 +42,10 @@ function createBitcoinDirectory(datadir, done) {
}
/**
* Will create a base Bitcore Node configuration directory and files.
* Will create a base Flocore Node configuration directory and files.
* @param {Object} options
* @param {String} options.network - "testnet" or "livenet"
* @param {String} options.datadir - The bitcoin database directory
* @param {String} options.datadir - The florincoin database directory
* @param {String} configDir - The absolute path
* @param {Boolean} isGlobal - If the configuration depends on globally installed node services.
* @param {Function} done - The callback function called when finished
@ -61,7 +61,7 @@ function createConfigDirectory(options, configDir, isGlobal, done) {
var configJSON = JSON.stringify(config, null, 2);
var packageJSON = JSON.stringify(BASE_PACKAGE, null, 2);
try {
fs.writeFileSync(configDir + '/bitcore-node.json', configJSON);
fs.writeFileSync(configDir + '/flocore-node.json', configJSON);
if (!isGlobal) {
fs.writeFileSync(configDir + '/package.json', packageJSON);
}
@ -74,13 +74,13 @@ function createConfigDirectory(options, configDir, isGlobal, done) {
}
/**
* Will setup a directory with a Bitcore Node directory, configuration file,
* bitcoin configuration, and will install all necessary dependencies.
* Will setup a directory with a Flocore Node directory, configuration file,
* florincoin configuration, and will install all necessary dependencies.
*
* @param {Object} options
* @param {String} options.cwd - The current working directory
* @param {String} options.dirname - The name of the bitcore node configuration directory
* @param {String} options.datadir - The path to the bitcoin datadir
* @param {String} options.dirname - The name of the flocore node configuration directory
* @param {String} options.datadir - The path to the florincoin datadir
* @param {Function} done - A callback function called when finished
*/
function create(options, done) {
@ -103,7 +103,7 @@ function create(options, done) {
async.series([
function(next) {
// Setup the the bitcore-node directory and configuration
// Setup the the flocore-node directory and configuration
if (!fs.existsSync(absConfigDir)) {
var createOptions = {
network: options.network,
@ -115,9 +115,9 @@ function create(options, done) {
}
},
function(next) {
// Setup the bitcoin directory and configuration
// Setup the florincoin directory and configuration
if (!fs.existsSync(absDataDir)) {
createBitcoinDirectory(absDataDir, next);
createFlorincoinDirectory(absDataDir, next);
} else {
next();
}

View File

@ -10,8 +10,8 @@ function getMajorVersion(versionString) {
}
/**
* Will return the path and default bitcore-node configuration. It will search for the
* configuration file in the "~/.bitcore" directory, and if it doesn't exist, it will create one
* Will return the path and default flocore-node configuration. It will search for the
* configuration file in the "~/.flocore" directory, and if it doesn't exist, it will create one
* based on default settings.
* @param {Object} [options]
* @param {Array} [options.additionalServices] - An optional array of services.
@ -22,8 +22,8 @@ function getDefaultConfig(options) {
options = {};
}
var defaultPath = path.resolve(process.env.HOME, './.bitcore');
var defaultConfigFile = path.resolve(defaultPath, './bitcore-node.json');
var defaultPath = path.resolve(process.env.HOME, './.flocore');
var defaultConfigFile = path.resolve(defaultPath, './flocore-node.json');
if (!fs.existsSync(defaultPath)) {
mkdirp.sync(defaultPath);
@ -40,11 +40,11 @@ function getDefaultConfig(options) {
};
}
console.log(`The configuration file at '${defaultConfigFile}' is incompatible with this version of Bitcore.`);
console.log(`The configuration file at '${defaultConfigFile}' is incompatible with this version of Flocore.`);
var now = new Date();
// bitcore-node.YYYY-MM-DD.UnixTimestamp.json
var backupFileName = `bitcore-node.${now.getUTCFullYear()}-${now.getUTCMonth()}-${now.getUTCDate()}.${now.getTime()}.json`;
// flocore-node.YYYY-MM-DD.UnixTimestamp.json
var backupFileName = `flocore-node.${now.getUTCFullYear()}-${now.getUTCMonth()}-${now.getUTCDate()}.${now.getTime()}.json`;
var backupFile = path.resolve(defaultPath, backupFileName);
fs.renameSync(defaultConfigFile, backupFile);
console.log(`The previous configuration file has been moved to: ${backupFile}.`);
@ -78,11 +78,11 @@ function getDefaultConfig(options) {
services: options.additionalServices ? defaultServices.concat(options.additionalServices) : defaultServices,
datadir: defaultDataDir,
servicesConfig: {
'insight-api': {
cwdRequirePath: 'node_modules/insight-api'
'flosight-api': {
cwdRequirePath: 'node_modules/flosight-api'
},
'insight-ui': {
cwdRequirePath: 'node_modules/insight-ui'
'flosight-ui': {
cwdRequirePath: 'node_modules/flosight-ui'
}
}
};

View File

@ -1,21 +1,21 @@
'use strict';
var bitcore = require('bitcore-lib');
var $ = bitcore.util.preconditions;
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var $ = flocore.util.preconditions;
var _ = flocore.deps._;
var path = require('path');
var fs = require('fs');
var utils = require('../utils');
/**
* Will return the path and bitcore-node configuration
* Will return the path and flocore-node configuration
* @param {String} cwd - The absolute path to the current working directory
*/
function findConfig(cwd) {
$.checkArgument(_.isString(cwd), 'Argument should be a string');
$.checkArgument(utils.isAbsolutePath(cwd), 'Argument should be an absolute path');
var directory = String(cwd);
while (!fs.existsSync(path.resolve(directory, 'bitcore-node.json'))) {
while (!fs.existsSync(path.resolve(directory, 'flocore-node.json'))) {
directory = path.resolve(directory, '../');
if (directory === '/') {
return false;
@ -23,7 +23,7 @@ function findConfig(cwd) {
}
return {
path: directory,
config: require(path.resolve(directory, 'bitcore-node.json'))
config: require(path.resolve(directory, 'flocore-node.json'))
};
}

View File

@ -4,13 +4,13 @@ var async = require('async');
var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var bitcore = require('bitcore-lib');
var $ = bitcore.util.preconditions;
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var $ = flocore.util.preconditions;
var _ = flocore.deps._;
var utils = require('../utils');
/**
* Will remove a service from bitcore-node.json
* Will remove a service from flocore-node.json
* @param {String} configFilePath - The absolute path to the configuration file
* @param {String} service - The name of the module
* @param {Function} done
@ -82,9 +82,9 @@ function removeService(configDir, service, done) {
}
/**
* Will remove the Node.js service and from the bitcore-node configuration.
* Will remove the Node.js service and from the flocore-node configuration.
* @param {String} options.cwd - The current working directory
* @param {String} options.dirname - The bitcore-node configuration directory
* @param {String} options.dirname - The flocore-node configuration directory
* @param {Array} options.services - An array of strings of service names
* @param {Function} done - A callback function called when finished
*/
@ -100,12 +100,12 @@ function remove(options, done) {
var configPath = options.path;
var services = options.services;
var bitcoreConfigPath = path.resolve(configPath, 'bitcore-node.json');
var flocoreConfigPath = path.resolve(configPath, 'flocore-node.json');
var packagePath = path.resolve(configPath, 'package.json');
if (!fs.existsSync(bitcoreConfigPath) || !fs.existsSync(packagePath)) {
if (!fs.existsSync(flocoreConfigPath) || !fs.existsSync(packagePath)) {
return done(
new Error('Directory does not have a bitcore-node.json and/or package.json file.')
new Error('Directory does not have a flocore-node.json and/or package.json file.')
);
}
@ -117,8 +117,8 @@ function remove(options, done) {
if (err) {
return next(err);
}
// remove service to bitcore-node.json
removeConfig(bitcoreConfigPath, service, next);
// remove service to flocore-node.json
removeConfig(flocoreConfigPath, service, next);
});
}, done
);

View File

@ -1,10 +1,10 @@
'use strict';
var path = require('path');
var BitcoreNode = require('../node');
var FlocoreNode = require('../node');
var index = require('../');
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var _ = flocore.deps._;
var log = index.log;
var shuttingDown = false;
var fs = require('fs');
@ -20,17 +20,17 @@ function start(options) {
servicesPath = options.path;
}
fullConfig.path = path.resolve(options.path, './bitcore-node.json');
fullConfig.path = path.resolve(options.path, './flocore-node.json');
fullConfig.services = start.setupServices(require, servicesPath, options.config);
var node = new BitcoreNode(fullConfig);
var node = new FlocoreNode(fullConfig);
// setup handlers for uncaught exceptions and ctrl+c
start.registerExitHandlers(process, node);
node.on('ready', function() {
log.info('Bitcore Node ready');
log.info('Flocore Node ready');
});
node.on('error', function(err) {
@ -113,8 +113,8 @@ function lookInModuleManifest(req, service) {
try {
var servicePackage = req(service.name + '/package.json');
var serviceModule = service.name;
if (servicePackage.bitcoreNode) {
serviceModule = serviceModule + '/' + servicePackage.bitcoreNode;
if (servicePackage.flocoreNode) {
serviceModule = serviceModule + '/' + servicePackage.flocoreNode;
return req(serviceModule);
}
} catch(e) {
@ -139,7 +139,7 @@ function loadModule(req, service) {
}
//fourth, see if there is directory in our module search path that has a
//package.json file, if so, then see if there is a bitcoreNode field, if so
//package.json file, if so, then see if there is a flocoreNode field, if so
//use this as the path to the service module
if(!serviceCode) {
serviceCode = lookInModuleManifest(req, service);
@ -149,7 +149,7 @@ function loadModule(req, service) {
throw new Error('Attempted to load the ' + service.name + ' service from: ' +
'the requirePath in the services\' config, then "' +
process.cwd() + '" then from: "' + __dirname + '/../lib/services' + '" finally from: "' +
process.cwd() + '/package.json" - bitcoreNode field. All paths failed to find valid nodeJS code.');
process.cwd() + '/package.json" - flocoreNode field. All paths failed to find valid nodeJS code.');
}
service.module = serviceCode;
@ -160,9 +160,9 @@ function loadModule(req, service) {
* specified modules, and assemble an array in this format:
* [
* {
* name: 'bitcoind',
* name: 'florincoind',
* config: {},
* module: BitcoinService
* module: FlorincoinService
* }
* ]
* @param {Function} req - The require function to use
@ -201,23 +201,26 @@ function cleanShutdown(_process, node) {
return _process.exit(1);
}
log.info('Halted');
_process.exit(0);
process.exit(0);
});
}
function exitHandler(options, _process, node, err) {
if (err) {
// Handle and log errors other than SIGINT shutdown
if (err && err !== "SIGINT") {
log.error('uncaught exception:', err);
if(err.stack) {
log.error(err.stack);
}
node.stop(function(err) {
if(err) {
log.error('Failed to stop services: ' + err);
}
_process.exit(-1);
});
if(options.exit)
node.stop(function(err) {
if(err) {
log.error('Failed to stop services: ' + err);
}
_process.exit(-1);
});
}
// Handle SIGINT (Ctrl+C)
if (options.sigint) {
if (!shuttingDown) {
shuttingDown = true;
@ -227,7 +230,7 @@ function exitHandler(options, _process, node, err) {
}
function registerExitHandlers(_process, node) {
_process.on('uncaughtException', exitHandler.bind(null, {exit:true}, _process, node));
_process.on('uncaughtException', exitHandler.bind(null, {exit:false}, _process, node));
_process.on('SIGINT', exitHandler.bind(null, {sigint:true}, _process, node));
}

View File

@ -72,7 +72,7 @@ Service.prototype.start = function(done) {
};
/**
* Function to be called when bitcore-node is stopped
* Function to be called when flocore-node is stopped
*/
Service.prototype.stop = function(done) {
setImmediate(done);

View File

@ -2,11 +2,13 @@
function Encoding(servicePrefix) {
this.servicePrefix = servicePrefix;
this.addressIndex = new Buffer('00', 'hex');
this.utxoIndex = new Buffer('01', 'hex');
this.addressCache = new Buffer('fe', 'hex');
}
Encoding.prototype.encodeAddressIndexKey = function(address, height, txid, index, input, timestamp) {
var prefix = new Buffer('00', 'hex');
var buffers = [this.servicePrefix, prefix];
var buffers = [this.servicePrefix, this.addressIndex];
var addressSizeBuffer = new Buffer(1);
addressSizeBuffer.writeUInt8(address.length);
@ -58,8 +60,7 @@ Encoding.prototype.decodeAddressIndexKey = function(buffer) {
};
Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) {
var prefix = new Buffer('01', 'hex');
var buffers = [this.servicePrefix, prefix];
var buffers = [this.servicePrefix, this.utxoIndex];
var addressSizeBuffer = new Buffer(1);
addressSizeBuffer.writeUInt8(address.length);
@ -114,5 +115,53 @@ Encoding.prototype.decodeUtxoIndexValue = function(buffer) {
};
};
Encoding.prototype.encodeAddressCacheKey = function(address) {
return Buffer.concat([this.servicePrefix, this.addressCache, new Buffer(address, 'utf8')]);
}
Encoding.prototype.decodeAddressCacheKey = function(buffer) {
return buffer.slice(3).toString('utf8');
}
Encoding.prototype.encodeAddressCacheValue = function(lastTx, lastBlock, balance, received, sent, txApperances) {
var buffer = [];
var balanceBuffer = new Buffer(8);
balanceBuffer.writeBigUInt64BE(BigInt(balance));
buffer.push(balanceBuffer);
var receivedBuffer = new Buffer(8);
receivedBuffer.writeBigUInt64BE(BigInt(received));
buffer.push(receivedBuffer);
var sentBuffer = new Buffer(8);
sentBuffer.writeBigUInt64BE(BigInt(sent));
buffer.push(sentBuffer);
var txApperancesBuffer = new Buffer(4);
txApperancesBuffer.writeUInt32BE(txApperances);
buffer.push(txApperancesBuffer);
var txidBuffer = new Buffer(lastTx, 'hex');
buffer.push(txidBuffer);
var blkBuffer = new Buffer(lastBlock, 'hex');
buffer.push(blkBuffer);
return Buffer.concat(buffer);
}
Encoding.prototype.decodeAddressCacheValue = function(buffer) {
var balance = parseInt(buffer.readBigUInt64BE(0));
var received = parseInt(buffer.readBigUInt64BE(8));
var sent = parseInt(buffer.readBigUInt64BE(16));
var txApperances = buffer.readUInt32BE(24);
var lastTx = buffer.slice(28, 60).toString('hex'); //28 + 32 (tx hash buffer length) = 60
var lastBlock = buffer.slice(60).toString('hex');
return { lastTx, lastBlock, balance, received, sent, txApperances };
}
module.exports = Encoding;

View File

@ -5,14 +5,27 @@ var inherits = require('util').inherits;
var async = require('async');
var index = require('../../');
var log = index.log;
var bitcore = require('bitcore-lib');
var Unit = bitcore.Unit;
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var Unit = flocore.Unit;
var _ = flocore.deps._;
var lodash = require('lodash');
var Encoding = require('./encoding');
var Transform = require('stream').Transform;
var assert = require('assert');
var utils = require('../../utils');
var LRU = require('lru-cache');
var XXHash = require('xxhash');
const MAX_TX_QUERY_LIMIT_HISTORY = 1000;
const MAX_TX_QUERY_LIMIT_UTXO = 1000;
const MAX_TX_QUERY_LIMIT_SUMMARY = 500;
// See rationale about this cache at function getTxList(next)
const TXID_LIST_CACHE_ITEMS = 250; // nr of items (this translates to: consecutive
// clients downloading their tx history)
const TXID_LIST_CACHE_EXPIRATION = 1000 * 30; // ms
const TXID_LIST_CACHE_MIN = 100; // Min items to cache
const TXID_LIST_CACHE_SEED = 0x3233DE; // Min items to cache
var AddressService = function(options) {
@ -24,6 +37,11 @@ var AddressService = function(options) {
this._network = this.node.network;
this._db = this.node.services.db;
this._mempool = this.node.services.mempool;
this._txIdListCache = new LRU({
max: TXID_LIST_CACHE_ITEMS,
maxAge: TXID_LIST_CACHE_EXPIRATION
});
if (this._network === 'livenet') {
this._network = 'main';
@ -49,8 +67,12 @@ AddressService.dependencies = [
// for example if the query /api/addrs/txs?from=0&to=5&noAsm=1&noScriptSig=1&noSpent=1, and the addresses passed
// in are [addr1, addr2, addr3], then if addr3 has tx1 at height 10, addr2 has tx2 at height 9 and tx1 has no txs,
// then I would pass back [tx1, tx2] in that order
AddressService.prototype.getAddressHistory = function(addresses, options, callback) {
//
// Instead of passing addresses, with from>0, options.cacheKey can be used to define the address set.
//(old one: non-optimized for large data)
AddressService.prototype.__getAddressHistory = function(addresses, options, callback) {
var self = this;
var cacheUsed = false;
options = options || {};
options.from = options.from || 0;
@ -65,31 +87,75 @@ AddressService.prototype.getAddressHistory = function(addresses, options, callba
addresses = [addresses];
}
async.eachLimit(addresses, 4, function(address, next) {
self._getAddressTxidHistory(address, options, next);
function getTxList(next) {
}, function(err) {
function hashAddresses(addresses) {
// Given there are only TXID_LIST_CACHE_ITEMS ~ 250 items cached at the sametime
// a 32 bits hash is secure enough
return XXHash.hash(Buffer.from(addresses.join('')), TXID_LIST_CACHE_SEED);
};
var calculatedCacheKey;
// We use the cache ONLY on from > 0 queries.
//
// Rationale: The a full history is downloaded, the client do
// from =0, to=x
// then from =x+1 to=y
// then [...]
// The objective of this cache is to speed up the from>0 queries, and also
// "freeze" the txid list during download.
//
if (options.from >0 ) {
let cacheKey = options.cacheKey;
if (!cacheKey) {
calculatedCacheKey = hashAddresses(addresses);
cacheKey = calculatedCacheKey;
}
var txIdList = self._txIdListCache.get(cacheKey);
if (txIdList) {
options.txIdList = txIdList;
cacheUsed = true;
return next();
}
}
// Get the list from the db
async.eachLimit(addresses, 4, function(address, next) {
self._getAddressTxidHistory(address, options, next);
}, function(err) {
if (err) return next(err);
var list = lodash.uniqBy(options.txIdList, function(x) {
return x.txid + x.height;
});
options.txIdList = lodash.orderBy(list,['height','txid'], ['desc','asc']);
if (list.length > TXID_LIST_CACHE_MIN) {
calculatedCacheKey = calculatedCacheKey || hashAddresses(addresses);
self._txIdListCache.set(calculatedCacheKey, options.txIdList);
}
return next();
});
};
getTxList(function(err) {
if(err) {
return callback(err);
}
var unique = {};
var list = [];
for (let i = 0; i < options.txIdList.length; i++) {
unique[options.txIdList[i].txid + options.txIdList[i].height] = options.txIdList[i];
}
for (var prop in unique) {
list.push(unique[prop]);
}
options.txIdList = list.sort(function(a, b) {
return b.height - a.height;
});
self._getAddressTxHistory(options, function(err, txList) {
if (err) {
@ -98,18 +164,117 @@ AddressService.prototype.getAddressHistory = function(addresses, options, callba
var results = {
totalCount: options.txIdList.length || 0,
items: txList
items: txList,
};
callback(null, results);
// cacheUsed is returned for testing
callback(null, results, cacheUsed);
});
});
};
AddressService.prototype.getAddressHistory = function(addresses, options, streamer, callback) {
var self = this;
options = options || {};
//options.from = options.from || 0; //Deprecated, use `after` and `before` option
//options.to = options.to || 0xffffffff; //Deprecated, use `after` and `before` option
if(!_.isFunction(callback)){ //if only 3 args, then streamer is callback
callback = streamer;
streamer = () => null; //NULL fn
}
if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true;
}
if (_.isUndefined(options.mempoolOnly)) {
options.mempoolOnly = false;
}
if(_.isUndefined(options.reverse)) {
options.reverse = false;
}
var old_support = false;
//Quick support for `from` and `to` options (DEPRECATED! Not recommeded to use)
if(!_.isUndefined(options.from) || !_.isUndefined(options.to)) {
old_support = true;
options.from = options.from || 0;
options.to = options.to || 0xffffffff; //Max value of to will actually be MAX_TX_QUERY_LIMIT_HISTORY
}
if (_.isString(addresses)) {
addresses = [addresses];
}
var results = {
totalCount: 0,
items: [],
}
async.eachLimit(addresses, 4, function(address, next) {
var addr_options = Object.assign({}, options), addr_count = 0;
self._streamAddressSummary(address, addr_options, function(err, tx){
if(err)
return log.error(err);
addr_count++;
if(!results.items.some(x => x.txid() === tx.txid())) {//add only if tx not already in array
if(!options.reverse)
results.items.unshift(tx); //using unshift, so that recent tx (low) are at front
else
results.items.push(tx);
}
if(results.items.length > MAX_TX_QUERY_LIMIT_HISTORY) { //remove items from array when overflown
results.items.sort((a, b) => (b.__height || 0xffffffff) - (a.__height || 0xffffffff) || b.txid().localeCompare(a.txid()));
let del_count = results.items.length - MAX_TX_QUERY_LIMIT_HISTORY;
let start_index = (old_support || options.reverse) ? MAX_TX_QUERY_LIMIT_HISTORY : 0;
results.items.splice(start_index, del_count);
results.incomplete = true;
if(!old_support && addr_count >= MAX_TX_QUERY_LIMIT_HISTORY)
addr_options.flag_stop = true; //limit has reached, stop quering db for more tx
}
streamer(null, tx);
}, next);
}, function(err) {
if (err) {
return callback(err);
}
//sort items in desc block-height, then asc txid (if same height)
results.items.sort((a, b) => (b.__height || 0xffffffff) - (a.__height || 0xffffffff) || b.txid().localeCompare(a.txid()));
results.totalCount = results.items.length ;
//Quick support for `from` and `to` options (DEPRECATED! Not recommeded to use)
if(old_support) {
results.items = results.items.slice(options.from, options.to);
}
callback(null, results);
})
}
// this is basically the same as _getAddressHistory apart from the summary
AddressService.prototype.getAddressSummary = function(address, options, callback) {
//(old one: non-optimized for large data)
AddressService.prototype.__getAddressSummary = function(address, options, callback) {
var self = this;
@ -135,7 +300,7 @@ AddressService.prototype.getAddressSummary = function(address, options, callback
txApperances: 0,
};
self.getAddressHistory(address, options, function(err, results) {
self.__getAddressHistory(address, options, function(err, results) { //old fn
if (err) {
return callback(err);
@ -153,6 +318,229 @@ AddressService.prototype.getAddressSummary = function(address, options, callback
};
AddressService.prototype.getAddressSummary = function(address, options, streamer, callback) {
var self = this;
options = options || {};
//options.from = options.from || 0; //Deprecated, use `after` and `before` option
//options.to = options.to || 0xffffffff; //Deprecated, use `after` and `before` option
if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true;
}
if(!_.isFunction(callback)){ //if only 3 args, then streamer is callback
callback = streamer;
streamer = () => null; //NULL fn
}
var count = 0;
var result = {
addrStr: address,
balance: 0,
balanceSat: 0,
totalReceived: 0,
totalReceivedSat: 0,
totalSent: 0,
totalSentSat: 0,
unconfirmedBalance: 0,
unconfirmedBalanceSat: 0,
unconfirmedTxApperances: 0,
txApperances: 0,
};
var useCache = _.isUndefined(options.after) && _.isUndefined(options.before);
var lastTx, lastBlock;
self._loadCache(address, result, useCache, function(err, lastCachedTx) {
if(err)
log.error(err);
if(!_.isUndefined(lastCachedTx))
options.after = lastCachedTx;
self._streamAddressSummary(address, options, function(err, tx) {
if(err)
return log.error(err);
if(tx) {
count++;
self._aggregateAddressSummaryResult(tx, address, result, options);
if(tx.confirmations) {
lastTx = tx.txid();
lastBlock = tx.blockhash;
}
}
if(count >= MAX_TX_QUERY_LIMIT_SUMMARY) {//stop quering db when limit reached
options.flag_stop = true;
result.incomplete = true;
}
streamer(null, tx);
}, function(err) {
if (err) {
return callback(err);
}
result.balanceSat = parseInt(result.balanceSat.toFixed());
result.totalReceivedSat = parseInt(result.totalReceivedSat.toFixed());
result.totalSentSat = parseInt(result.totalSentSat.toFixed());
result.txApperances = parseInt(result.txApperances.toFixed());
result.unconfirmedBalanceSat = parseInt(result.unconfirmedBalanceSat.toFixed());
result.unconfirmedTxApperances = parseInt(result.unconfirmedTxApperances.toFixed());
result.balance = Unit.fromSatoshis(result.balanceSat).toBTC();
result.totalReceived = Unit.fromSatoshis(result.totalReceivedSat).toBTC();
result.totalSent = Unit.fromSatoshis(result.totalSentSat).toBTC();
result.unconfirmedBalance = Unit.fromSatoshis(result.unconfirmedBalanceSat).toBTC();
result.lastItem = lastTx;
callback(null, result);
//store in cache if needed
if(useCache) {
if(result.incomplete) //full summary needs to be calculated in background
self._cacheSummaryInBackground(address, lastTx, lastBlock, result);
else if (!_.isUndefined(lastCachedTx) && !_.isUndefined(lastTx)
&& lastTx != lastCachedTx && !self._cacheInstance.has(address)) //update cache if needed
self._storeCache(address, lastTx, lastBlock, result);
}
});
})
}
AddressService.prototype._cacheInstance = new Set();
AddressService.prototype._cacheSummaryInBackground = function(address, lastTx, lastBlock, result){
const self = this;
if(self._cacheInstance.has(address))
return;
self._cacheInstance.add(address);
const cache = {
balanceSat: result.balanceSat,
totalReceivedSat: result.totalReceivedSat,
totalSentSat: result.totalSentSat,
txApperances: result.txApperances,
unconfirmedBalanceSat: 0, //unconfirmed (mempool) values should not be cached
unconfirmedTxApperances: 0
};
const options = { queryMempool: false, after: lastTx, noTxList: true };
self._streamAddressSummary(address, options, function(err, tx) {
if(err)
return log.error(err);
if(tx) {
self._aggregateAddressSummaryResult(tx, address, cache, options);
if(tx.confirmations){
lastTx = tx.txid();
lastBlock = tx.blockhash;
}
}
}, function(err) {
if (err)
return log.error(err);
cache.balanceSat = parseInt(cache.balanceSat.toFixed());
cache.totalReceivedSat = parseInt(cache.totalReceivedSat.toFixed());
cache.totalSentSat = parseInt(cache.totalSentSat.toFixed());
cache.txApperances = parseInt(cache.txApperances.toFixed());
if(!_.isUndefined(lastTx))
self._storeCache(address, lastTx, lastBlock, cache);
self._cacheInstance.delete(address); //remove from running instance
});
}
AddressService.prototype._storeCache = function(address, lastCacheTx, lastCacheBlock, result, callback) {
const self = this;
var key = self._encoding.encodeAddressCacheKey(address);
var value = self._encoding.encodeAddressCacheValue(lastCacheTx, lastCacheBlock, result.balanceSat, result.totalReceivedSat, result.totalSentSat, result.txApperances)
if(!_.isFunction(callback)) //if callback is not passed, call a empty function
callback = () => null;
self._db.put(key, value, callback);
}
AddressService.prototype._loadCache = function(address, result, useCache, callback) {
const self = this;
if(!useCache) //skip if useCache is false (cases like 'after' and/or 'before' parameter is used by client)
return callback();
var key = self._encoding.encodeAddressCacheKey(address);
self._db.get(key, function(err, value) {
if (err) {
return callback(err);
}
if (!value) {
return callback();
}
var addressCache = self._encoding.decodeAddressCacheValue(value);
var lastCacheTx = addressCache.lastTx, lastCacheBlock = addressCache.lastBlock
self._block.getBlock(lastCacheBlock, function(err, block) {
if(err) {
return callback(err);
}
if (!block) { //block not found, probably removed in reorg.
//delete the existing cache and recalc values freshly
self._deleteCache(address, function() {
callback();
});
} else {
//values are in satoshis
result.balanceSat = addressCache.balance;
result.totalReceivedSat = addressCache.received;
result.totalSentSat = addressCache.sent;
result.txApperances = addressCache.txApperances;
callback(null, lastCacheTx);
}
})
});
}
AddressService.prototype._deleteCache = function(address, callback) {
const self = this;
var key = self._encoding.encodeAddressCacheKey(address);
if(!_.isFunction(callback)) //if callback is not passed, call a empty function
callback = () => null;
self._db.del(key, callback);
}
AddressService.prototype._setOutputResults = function(tx, address, result) {
for(var j = 0; j < tx.outputs.length; j++) {
@ -200,7 +588,6 @@ AddressService.prototype._getAddressSummaryResult = function(txs, address, resul
var self = this;
for(var i = 0; i < txs.length; i++) {
var tx = txs[i];
self._setOutputResults(tx, address, result);
@ -218,6 +605,110 @@ AddressService.prototype._getAddressSummaryResult = function(txs, address, resul
return result;
};
AddressService.prototype._getOccurrenceCount = function(tx, address) {
let count = 0;
for(var i = 0; i < tx.inputs.length; i++) {
var input = tx.inputs[i];
if(utils.getAddress(input, this._network) === address)
count++;
}
for(var j = 0; j < tx.outputs.length; j++) {
var output = tx.outputs[j];
if(utils.getAddress(output, this._network) === address)
count++;
}
return count;
}
AddressService.prototype._getOutputResults = function(tx, address) {
let value = 0;
for(var j = 0; j < tx.outputs.length; j++) {
var output = tx.outputs[j];
if (utils.getAddress(output, this._network) === address)
value += output.value;
}
return value;
};
AddressService.prototype._getInputResults = function(tx, address) {
let value = 0;
for(var i = 0; i < tx.inputs.length; i++) {
var input = tx.inputs[i];
if (utils.getAddress(input, this._network) === address)
value += tx.__inputValues[i];
}
return value;
};
AddressService.prototype._aggregateAddressSummaryResult = function (tx, address, result, options) {
var self = this;
let output_val = self._getOutputResults(tx, address);
let input_val = self._getInputResults(tx, address);
//aggregate the result
if(tx.confirmations) {
result.txApperances++;
result.totalReceivedSat += output_val;
result.balanceSat += output_val;
result.totalSentSat += input_val;
result.balanceSat -= input_val;
} else {
result.unconfirmedTxApperances++;
result.unconfirmedBalanceSat += output_val;
result.unconfirmedBalanceSat -= input_val;
}
if (!options.noTxList) {
if (!result.transactions) {
result.transactions = [];
}
let txid = tx.txid();
if(!result.transactions.includes(txid)) { //push txid only if its not in the array
result.transactions.unshift(txid); //using unshift, so that recent tx (low confirmation) are at front
if(result.transactions.length > MAX_TX_QUERY_LIMIT_SUMMARY)
result.transactions.pop(); //pop the oldest tx in list (when list limit is maxed out)
}
}
}
AddressService.prototype.getAddressUnspentOutputs = function(address, options, callback) {
var self = this;
@ -300,6 +791,11 @@ AddressService.prototype.getAddressUnspentOutputs = function(address, options, c
utxoStream.on('data', function(data) {
if(results.length >= MAX_TX_QUERY_LIMIT_UTXO) { //Max array limit reached, end response
utxoStream.emit('end');
return;
}
var key = self._encoding.decodeUtxoIndexKey(data.key);
var value = self._encoding.decodeUtxoIndexValue(data.value);
@ -375,19 +871,21 @@ AddressService.prototype.stop = function(callback) {
AddressService.prototype._getTxidStream = function(address, options) {
var start = this._encoding.encodeAddressIndexKey(address);
var end = Buffer.concat([
start.slice(0, address.length + 4),
options.endHeightBuf,
new Buffer(new Array(83).join('f'), 'hex')
]);
var criteria = {
gte: start,
lte: end,
reverse: true // txids stream from low confirmations to high confirmations
};
var criteria = {};
if(options.after)
criteria.gt = this._encoding.encodeAddressIndexKey(address, options.start, options.after, 0xffffffff, 1, 0xffffffff); //0xffffffff is for getting after the txid
else
criteria.gte = this._encoding.encodeAddressIndexKey(address, options.start);
if(options.before)
criteria.lt = this._encoding.encodeAddressIndexKey(address, options.end, options.before); //get before the txid
else
criteria.lte = this._encoding.encodeAddressIndexKey(address, options.end, Array(65).join('f'), 0xffffffff, 1, 0xffffffff);
//reverse option can be used explictly when latest tx are required
if(options.reverse)
criteria.reverse = true;
// txid stream
var txidStream = this._db.createKeyStream(criteria);
@ -398,6 +896,7 @@ AddressService.prototype._getTxidStream = function(address, options) {
return txidStream;
};
//(used by old fn)
AddressService.prototype._getAddressTxHistory = function(options, callback) {
var self = this;
@ -420,14 +919,14 @@ AddressService.prototype._getAddressTxHistory = function(options, callback) {
});
}
self._transaction.getTransaction(id.txid, next);
self._transaction.getDetailedTransaction(id.txid, options, next);
}, callback);
};
//(used by old fn)
AddressService.prototype._getAddressTxidHistory = function(address, options, callback) {
var self = this;
options = options || {};
@ -436,9 +935,6 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
var results = [];
options.endHeightBuf = new Buffer(4);
options.endHeightBuf.writeUInt32BE(options.end);
if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true;
}
@ -487,7 +983,15 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
txIdTransformStream._transform = function(chunk, enc, callback) {
var txInfo = self._encoding.decodeAddressIndexKey(chunk);
results.push({ txid: txInfo.txid, height: txInfo.height });
if(results.length >= MAX_TX_QUERY_LIMIT_HISTORY) { //Max array limit reached, end response
txIdTransformStream.emit('end');
return;
}
if(!results.some(r => r.txid == txInfo.txid)) //add txid to array only if its not already there
results.push({ txid: txInfo.txid, height: txInfo.height });
callback();
};
@ -499,6 +1003,225 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
};
AddressService.prototype._streamAddressSummary = function(address, options, streamer, callback) {
var self = this;
options = options || {};
options.start = options.start || 0;
options.end = options.end || 0xffffffff;
//options.from = options.from || 0; //Deprecated, use `after` and `before` option
//options.to = options.to || 0xffffffff; //Deprecated, use `after` and `before` option
if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true;
}
if (_.isUndefined(options.mempoolOnly)) {
options.mempoolOnly = false;
}
if (_.isUndefined(options.reverse)) {
options.reverse = false;
}
//declare the queue to process tx data
var tmpTxList = {}; //store processed txid temporarily to ignore duplication
var q = async.queue(function(id, cb) {
//duplication finding
if(id.txid in tmpTxList){
tmpTxList[id.txid][0]++;
if(tmpTxList[id.txid][1] !== null && tmpTxList[id.txid][0] >= tmpTxList[id.txid][1]) //all duplications are found for this txid
delete tmpTxList[id.txid];
return cb();
} else tmpTxList[id.txid] = [1, null];
if (id.height === 0xffffffff) {
return self._mempool.getMempoolTransaction(id.txid, function(err, tx) {
if (err || !tx) {
return cb(err || new Error('Address Service: could not find tx: ' + id.txid));
}
self._transaction.setTxMetaInfo(tx, options, cb);
});
}
self._transaction.getDetailedTransaction(id.txid, options, cb);
}, 1);
//q.pause(); //pause and wait until queue is set (not needed)
function chunkCallback(err, tx){
if(q.killed || (!err && !tx)) //no error or tx data (duplicate calls will have empty tx value)
return;
if(tx){
let txid = tx.txid();
tmpTxList[txid][1] = self._getOccurrenceCount(tx, address);
if(tmpTxList[txid][0] >= tmpTxList[txid][1]) //all duplications are found for this txid
delete tmpTxList[txid];
}
streamer(err, tx);
if((err || options.flag_stop) && !q.killed){
q.kill();
q.killed = true;
return callback();
}
}
const waterfall_array = [];
waterfall_array.push(
//Find start height if `after` option is passed
function parse_after_id(next){
if(_.isUndefined(options.after)) {
return next();
}
self._transaction.getTransaction(options.after, options, function(err, tx) {
if(tx && tx.confirmations && tx.height >= options.start) {
options.start = tx.height;
} else {
delete options.after;
}
next();
});
});
waterfall_array.push(
//Find end height if `before` option is passed
function parse_before_id(next){
if(_.isUndefined(options.before)) {
return next();
}
self._transaction.getTransaction(options.before, options, function(err, tx) {
if(tx && tx.confirmations && tx.height <= options.end) {
options.end = tx.height;
} else {
delete options.before;
}
next();
});
});
// stream the confirmed txids out of the address index
function query_confirmed_txids(next) {
if (options.mempoolOnly) { //Option to query from mempool only (ie, unconfirmed txs only)
return next();
}
var txIdTransformStream = new Transform({ objectMode: true });
txIdTransformStream._flush = function(cb) {
txIdTransformStream.emit('end');
cb();
};
txIdTransformStream.on('error', function(err) {
log.error('Address Service: txstream err: ' + err);
txIdTransformStream.unpipe();
});
txIdTransformStream.on('end', function() {
next();
});
txIdTransformStream._transform = function(chunk, enc, cb) {
if(options.flag_stop)//stop data query
return txIdTransformStream.unpipe();
var txInfo = self._encoding.decodeAddressIndexKey(chunk);
q.push({ txid: txInfo.txid, height: txInfo.height }, chunkCallback);
cb();
};
var txidStream = self._getTxidStream(address, options);
txidStream.pipe(txIdTransformStream);
}
// query the mempool for relevant txs for this address
function query_mempool_txids(next) {
if (!options.queryMempool || !_.isUndefined(options.before)) { //if queryMempool=false or options.before is given a valid value, then do not query mempool
return next();
}
self._mempool.getTxidsByAddress(address, 'both', function(err, mempoolTxids) {
if (mempoolTxids.length <= 0) {
return next();
}
mempoolTxids.map(id => q.push(id, chunkCallback));
next();
});
}
if(options.reverse){ //when queried txs in reverse key order, mempool first then confirmed
waterfall_array.push(query_mempool_txids);
waterfall_array.push(query_confirmed_txids);
} else { //when queried tx in key order, confirmed tx 1st, then mempool
waterfall_array.push(query_confirmed_txids);
waterfall_array.push(query_mempool_txids);
}
waterfall_array.push(
//wait for queue to complete
function end_fall(next) {
if(!q.started || q.idle()) //No tx in query (or) already finished querying
return next();
else
q.drain = () => next();
});
async.waterfall(waterfall_array, callback);
}
AddressService.prototype._removeBlock = function(block, callback) {
var self = this;
@ -566,7 +1289,7 @@ AddressService.prototype._removeInput = function(input, tx, block, index, callba
}
address.network = self._network;
address = address.toString();
address = address.toString(self._network);
assert(block && block.__ts && block.__height, 'Missing block or block values.');
@ -610,7 +1333,7 @@ AddressService.prototype._removeOutput = function(output, tx, block, index, call
}
address.network = self._network;
address = address.toString();
address = address.toString(self._network);
assert(block && block.__ts && block.__height, 'Missing block or block values.');
@ -679,7 +1402,7 @@ AddressService.prototype._processInput = function(tx, input, index, opts) {
}
address.network = this._network;
address = address.toString();
address = address.toString(this._network);
var txid = tx.txid();
var timestamp = this._timestamp.getTimestampSync(opts.block.rhash());
@ -717,7 +1440,7 @@ AddressService.prototype._processOutput = function(tx, output, index, opts) {
}
address.network = this._network;
address = address.toString();
address = address.toString(this._network);
var txid = tx.txid();
var timestamp = this._timestamp.getTimestampSync(opts.block.rhash());

View File

@ -242,7 +242,7 @@ ProcessSerial.prototype._write = function(block, enc, callback) {
self.block.once('concurrentaddblock', function() {
if(!check()) {
var err = new Error('Concurrent block ' + self.block.concurrentTip.__height + ' is less than ' + block.__height);
var err = 'Concurrent block ' + self.block.concurrentTip.__height + ' is less than ' + block.__height;
return self.emit('error', err);
}
self._process(block, callback);

View File

@ -1,6 +1,6 @@
'use strict';
var Block = require('bcoin').block;
var Block = require('fcoin').Block;
// stores -- block header as key, block itself as value (optionally)
function Encoding(servicePrefix) {

View File

@ -9,10 +9,12 @@ var log = index.log;
var utils = require('../../utils');
var assert = require('assert');
var constants = require('../../constants');
var bcoin = require('bcoin');
var bcoin = require('fcoin');
var _ = require('lodash');
var LRU = require('lru-cache');
const MAX_IGNORED_BLOCK = 16; //Maximum ignored block allowed before trigging sync again
var BlockService = function(options) {
BaseService.call(this, options);
@ -36,6 +38,7 @@ var BlockService = function(options) {
this._recentBlockHashes = new LRU(this._recentBlockHashesCount);
this._readAheadBlockCount = options.readAheadBlockCount || 2; // this is the number of blocks to direct the p2p service to read aheead
this._pauseSync = options.pause;
this._reorgToBlock = options.reorgToBlock;
};
inherits(BlockService, BaseService);
@ -90,8 +93,8 @@ BlockService.prototype.getInfo = function(callback) {
errors: '',
network: self.node.network,
relayFee: 0,
version: 'bitcore-1.1.2',
protocolversion: 700001,
version: 'flocore-5.0.0',
protocolversion: 70015,
difficulty: self._header.getCurrentDifficulty()
});
};
@ -161,7 +164,7 @@ BlockService.prototype.getBlockOverview = function(hash, callback) {
prevHash: header.prevHash,
nextHash: header.nextHash,
merkleRoot: header.merkleRoot,
time: block.ts,
time: block.time,
medianTime: null,
nonce: header.nonce,
bits: header.bits,
@ -201,7 +204,7 @@ BlockService.prototype._checkTip = function(callback) {
header = header || self._header.getLastHeader();
if (header.hash === self._tip.hash) {
if (header.hash === self._tip.hash && !self._reorgToBlock) {
log.info('Block Service: saved tip is good to go.');
return callback();
}
@ -230,8 +233,8 @@ BlockService.prototype._resetTip = function(callback) {
self._header.getAllHeaders(function(err, headers) {
if (err || !headers) {
return callback(err || new Error('headers required'));
}
log.error(err || 'headers required'); return callback(err);
}
log.info('Block Service: retrieved all the headers for lookups.');
@ -251,13 +254,18 @@ BlockService.prototype._resetTip = function(callback) {
return callback(err);
}
if (!_block) {
if (!_block) {
log.debug('Block Service: block: ' + header.hash + ' was not found, proceeding to older blocks.');
}
}
block = _block;
header = headers.getIndex(--height);
assert(header, 'Header not found for reset.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (header == false) {
log.error('Header not found for reset.');
}
// assert(header, 'Header not found for reset.');
if (!block) {
log.debug('Block Service: trying block: ' + header.hash);
@ -270,8 +278,8 @@ BlockService.prototype._resetTip = function(callback) {
}, function(err) {
if (err || !block) {
return callback(err ||
new Error('Block Service: none of the blocks from the headers match what is already indexed in the block service.'));
log.error(err ||
'Block Service: none of the blocks from the headers match what is already indexed in the block service.'); return callback(err);
}
self._setTip({ hash: block.rhash(), height: height + 1 }, callback);
@ -369,8 +377,8 @@ BlockService.prototype._loadRecentBlockHashes = function(callback) {
self.getBlock(hash, function(err, block) {
if (err || !block) {
return callback(err || new Error('Block Service: attempted to retrieve block: ' + hash +
' but was not in the index.'));
log.error(err || 'Block Service: attempted to retrieve block: ' + hash +
' but was not in the index.'); return callback(err);
}
var prevHash = bcoin.util.revHex(block.prevBlock);
@ -386,7 +394,11 @@ BlockService.prototype._loadRecentBlockHashes = function(callback) {
return callback(err);
}
assert(self._recentBlockHashes.length === times, 'Block Service: did not load enough recent block hashes from the index.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (self._recentBlockHashes.length != times) {
log.error('Block Service: did not load enough recent block hashes from the index.');
}
//assert(self._recentBlockHashes.length === times, 'Block Service: did not load enough recent block hashes from the index.');
log.info('Block Service: loaded: ' + self._recentBlockHashes.length + ' hashes from the index.');
callback();
@ -405,7 +417,7 @@ BlockService.prototype._getTimeSinceLastBlock = function(callback) {
self._header.getBlockHeader(Math.max(self._tip.height - 1, 0), function(err, header) {
if(err || !header) {
return callback(err || new Error('Block Service: we should have a header in order to get time since last block.'));
log.error(err || 'Block Service: we should have a header in order to get time since last block.'); return callback(err);
}
async.map([ self._tip.hash, header.hash ], function(hash, next) {
@ -627,6 +639,7 @@ BlockService.prototype._startBlockSubscription = function() {
}
this._subscribedBlock = true;
this._ignoredBlockCount = 0; //SZ: reset the ignored count to 0 when subscription starts
log.info('Block Service: starting p2p block subscription.');
this._bus.on('p2p/block', this._queueBlock.bind(this));
@ -652,6 +665,15 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
var self = this;
if (self._reorgToBlock) {
return self._header.getBlockHeader(self._reorgToBlock, function(err, header) {
if (err || !header) {
log.error(err || 'Block Service: header not found to reorg to.'); return callback(err);
}
callback(null, header);
});
}
var blockServiceHash = self._tip.hash;
var blockServiceHeight = self._tip.height;
var iterCount = 0;
@ -701,12 +723,19 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
// any of our recent block hashes in its indexes.
// if some joker mines a block using an orphan block as its prev block, then the effect of this will be
// us detecting a reorg, but not actually reorging anything
assert(header, 'Block Service: we could not locate any of our recent block hashes in the header service ' +
'index. Perhaps our header service sync\'ed to the wrong chain?');
assert(header.height <= self._tip.height, 'Block Service: we found a common ancestor header whose ' +
'height was greater than our current tip. This should be impossible.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (!_.isUndefined(header)) {
if (header == false) {
log.error('Block Service: we could not locate any of our recent block hashes in the header service ' + 'index. Perhaps our header service sync\'ed to the wrong chain?');
}
}
// assert(header, 'Block Service: we could not locate any of our recent block hashes in the header service ' + 'index. Perhaps our header service sync\'ed to the wrong chain?');
if (!_.isUndefined(header.height)) {
if (header.height > self._tip.height) {
log.error('Block Service: we found a common ancestor header whose ' + 'height was greater than our current tip. This should be impossible.');
}
// assert(header.height <= self._tip.height, 'Block Service: we found a common ancestor header whose ' + 'height was greater than our current tip. This should be impossible.');
}
callback(null, header);
});
@ -729,13 +758,13 @@ BlockService.prototype._findBlocksToRemove = function(commonHeader, callback) {
self._getBlock(hash, function(err, block) {
if (err || !block) {
return next(err || new Error('Block Service: block not found in index.'));
return next(err || 'Block Service: block not found in index.');
}
self._timestamp.getTimestamp(block.rhash(), function(err, timestamp) {
if (err || !timestamp) {
return callback(err || new Error('timestamp missing from reorg.'));
log.error(err || 'timestamp missing from reorg.'); return callback(err);
}
block.__height = height;
@ -805,8 +834,10 @@ BlockService.prototype._handleReorg = function(callback) {
blocksToRemove = _blocksToRemove;
assert(blocksToRemove.length >= 1 && blocksToRemove.length <= self._recentBlockHashes.length,
'Block Service: the number of blocks to remove looks to be incorrect.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (blocksToRemove.length < 1 || blocksToRemove.length > self._recentBlockHashes.length) {
log.error('Block Service: the number of blocks to remove looks to be incorrect.'); }
// assert(blocksToRemove.length >= 1 && blocksToRemove.length <= self._recentBlockHashes.length, 'Block Service: the number of blocks to remove looks to be incorrect.');
log.warn('Block Service: chain reorganization detected, current height/hash: ' + self._tip.height + '/' +
self._tip.hash + ' common ancestor hash: ' + commonAncestorHeader.hash + ' at height: ' + commonAncestorHeader.height +
@ -910,6 +941,15 @@ BlockService.prototype._processBlock = function(block, callback) {
return self._saveBlock(block, callback);
}
//SZ: count the ignored blocks. if many blocks ignored, trigger sync process
if(self._ignoredBlockCount < MAX_IGNORED_BLOCK)
self._ignoredBlockCount++;
else {
self._ignoredBlockCount = 0;
self._removeAllSubscriptions();
self._startSync();
}
// reorg -- in this case, we will not handle the reorg right away
// instead, we will skip the block and wait for the eventual call to
// "onHeaders" function. When the header service calls this function,
@ -925,6 +965,7 @@ BlockService.prototype._saveBlock = function(block, callback) {
var self = this;
block.__height = self._tip.height + 1;
self._ignoredBlockCount = 0; //SZ: a block is saved, reset the ignored count
var services = self.node.services;
@ -972,7 +1013,9 @@ BlockService.prototype._saveBlock = function(block, callback) {
BlockService.prototype._handleError = function(err) {
if (!this.node.stopping) {
log.error('Block Service: handle error ' + err);
return this.node.stop();
//FLO Crash Error Resolution by RanchiMall 10th May 2021
//return this.node.stop();
return;
}
};
@ -1067,7 +1110,7 @@ BlockService.prototype._startSync = function() {
this.on('next block', this._sync.bind(this));
this.on('synced', this._onSynced.bind(this));
clearInterval(this._reportInterval);
this._reportingInterval = setInterval(this._logProgress.bind(this), 5000);
this._reportInterval = setInterval(this._logProgress.bind(this), 5000);
return this._sync();
}
@ -1116,7 +1159,7 @@ BlockService.prototype._sync = function() {
self._getBlocksTimer.unref();
// TODO; research how different bitcoin implementation handle block
// TODO; research how different florincoin implementation handle block
// locator objects. If you pass a block locator object that has one
// block hash and that block hash is not on the main chain, then will
// the peer send an inv for block 1 or no inv at all?

View File

@ -1,6 +1,6 @@
'use strict';
var bitcore = require('bitcore-lib');
var BufferUtil = bitcore.util.buffer;
var flocore = require('flocore-lib');
var BufferUtil = flocore.util.buffer;
var async = require('async');
function Reorg(node, block) {
@ -315,7 +315,7 @@ Reorg.prototype.findCommonAncestorAndNewHashes = function(oldTipHash, newTipHash
}
if(!mainPosition && !forkPosition) {
return next(new Error('Unknown common ancestor'));
return next('Unknown common ancestor');
}
next();

View File

@ -3,6 +3,7 @@
var util = require('util');
var fs = require('fs');
var async = require('async');
var _ = require('lodash');
var levelup = require('levelup');
var leveldown = require('leveldown');
var mkdirp = require('mkdirp');
@ -49,18 +50,19 @@ DB.dependencies = [];
DB.prototype._onError = function(err) {
if (!this._stopping) {
log.error('Db Service: error: ' + err);
this.node.stop();
//FLO Crash Error Resolution by RanchiMall 10th May 2021
//this.node.stop();
}
};
DB.prototype._setDataPath = function() {
assert(fs.existsSync(this.node.datadir), 'Node is expected to have a "datadir" property');
if (this.node.network === 'livenet' || this.node.network === 'mainnet') {
this.dataPath = this.node.datadir + '/bitcorenode.db';
this.dataPath = this.node.datadir + '/flocorenode.db';
} else if (this.node.network === 'regtest') {
this.dataPath = this.node.datadir + '/regtest/bitcorenode.db';
this.dataPath = this.node.datadir + '/regtest/flocorenode.db';
} else if (this.node.network === 'testnet') {
this.dataPath = this.node.datadir + '/testnet/bitcorenode.db';
this.dataPath = this.node.datadir + '/testnet/flocorenode.db';
} else {
throw new Error('Unknown network: ' + this.network);
}
@ -94,7 +96,7 @@ DB.prototype.get = function(key, options, callback) {
var cb = callback;
var opts = options;
if (typeof callback !== 'function') {
if (!_.isFunction(callback)) {
cb = options;
opts = {};
}
@ -117,7 +119,9 @@ DB.prototype.get = function(key, options, callback) {
} else {
cb(new Error('Shutdown sequence underway, not able to complete the query'));
// FLOSight Error Correction from RanchiMall 20th May 2021.
//cb(new Error('Shutdown sequence underway, not able to complete the query'));
log.error('Shutdown sequence underway, not able to complete the query');
}
};
@ -128,17 +132,40 @@ DB.prototype.put = function(key, value, callback) {
callback();
}
assert(Buffer.isBuffer(key), 'key NOT a buffer as expected.');
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
if (Buffer.isBuffer(key) == false) {
log.error('key NOT a buffer as expected.');
}
// assert(Buffer.isBuffer(key), 'key NOT a buffer as expected.');
if (value) {
assert(Buffer.isBuffer(value), 'value exists but NOT a buffer as expected.');
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
if (Buffer.isBuffer(value) == false) {
log.error('value exists but NOT a buffer as expected.');
}
//assert(Buffer.isBuffer(value), 'value exists but NOT a buffer as expected.');
}
this._store.put(key, value, callback);
};
DB.prototype.del = function(key, callback) {
if (this._stopping) {
callback();
}
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
if (Buffer.isBuffer(key) == false) {
log.error('key NOT a buffer as expected.');
}
// assert(Buffer.isBuffer(key), 'key NOT a buffer as expected.');
this._store.del(key, callback);
}
DB.prototype.batch = function(ops, callback) {
if (this._stopping) {
@ -147,11 +174,18 @@ DB.prototype.batch = function(ops, callback) {
for(var i = 0; i < ops.length; i++) {
assert(Buffer.isBuffer(ops[i].key), 'key NOT a buffer as expected.');
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
if (Buffer.isBuffer(ops[i].key) == false) {
log.error('key NOT a buffer as expected.');
}
//assert(Buffer.isBuffer(ops[i].key), 'key NOT a buffer as expected.');
if (ops[i].value) {
assert(Buffer.isBuffer(ops[i].value), 'value exists but NOT a buffer as expected.');
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
if (Buffer.isBuffer(ops[i].value) == false) {
log.error('value exists but NOT a buffer as expected.');
}
//assert(Buffer.isBuffer(ops[i].value), 'value exists but NOT a buffer as expected.');
}
}

View File

@ -2,18 +2,18 @@
var BaseService = require('../../service');
var inherits = require('util').inherits;
var BitcoreRPC = require('bitcoind-rpc');
var FlocoreRPC = require('florincoind-rpc');
var FeeService = function(options) {
this._config = options.rpc || {
user: 'bitcoin',
user: 'florincoin',
pass: 'local321',
host: 'localhost',
protocol: 'http',
port: 8332
port: 7312
};
BaseService.call(this, options);
this._client = new BitcoreRPC(this._config);
this._client = new FlocoreRPC(this._config);
};
inherits(FeeService, BaseService);

View File

@ -7,11 +7,14 @@ var index = require('../../');
var log = index.log;
var utils = require('../../utils');
var async = require('async');
var BN = require('bn.js');
var consensus = require('bcoin').consensus;
// var BN = require('bn.js');
var BN = require('bcrypto/lib/bn.js')
var consensus = require('fcoin').consensus;
var assert = require('assert');
var constants = require('../../constants');
var bcoin = require('bcoin');
var bcoin = require('fcoin');
const SYNC_CHECK_INTERVAL = 1000 * 60 * 15; //15 mins
var HeaderService = function(options) {
@ -39,7 +42,7 @@ inherits(HeaderService, BaseService);
HeaderService.dependencies = [ 'p2p', 'db' ];
HeaderService.MAX_CHAINWORK = new BN(1).ushln(256);
HeaderService.STARTING_CHAINWORK = '0000000000000000000000000000000000000000000000000000000100010001';
HeaderService.STARTING_CHAINWORK = '0000000000000000000000000000000000000000000000000000000000100010';
HeaderService.prototype.subscribe = function(name, emitter) {
this.subscriptions[name].push(emitter);
@ -144,7 +147,11 @@ HeaderService.prototype._adjustTipBackToCheckpoint = function() {
HeaderService.prototype._setGenesisBlock = function(callback) {
assert(this._tip.hash === this.GENESIS_HASH, 'Expected tip hash to be genesis hash, but it was not.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (this._tip.hash != this.GENESIS_HASH) {
log.error('Expected tip hash to be genesis hash, but it was not.');
}
// assert(this._tip.hash === this.GENESIS_HASH, 'Expected tip hash to be genesis hash, but it was not.');
var genesisHeader = {
hash: this.GENESIS_HASH,
@ -152,10 +159,10 @@ HeaderService.prototype._setGenesisBlock = function(callback) {
chainwork: HeaderService.STARTING_CHAINWORK,
version: 1,
prevHash: new Array(65).join('0'),
timestamp: 1231006505,
nonce: 2083236893,
bits: 0x1d00ffff,
merkleRoot: '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
timestamp: 1371488396,
nonce: 1000112548,
bits: 0x1e0ffff0,
merkleRoot: '730f0c8ddc5a592d5512566890e2a73e45feaa6748b24b849d1c29a7ab2b2300'
};
this._lastHeader = genesisHeader;
@ -334,7 +341,7 @@ HeaderService.prototype._persistHeader = function(block, callback) {
HeaderService.prototype._formatHeader = function(block) {
var header = block.toHeaders().toJSON();
header.timestamp = header.ts;
header.timestamp = header.time;
header.prevHash = header.prevBlock;
return header;
@ -411,7 +418,10 @@ HeaderService.prototype._getDBOpForLastHeader = function(nextHeader) {
this._lastHeader.nextHash = nextHeader.hash;
var keyHash = this._encoding.encodeHeaderHashKey(this._lastHeader.hash);
assert(this._lastHeader.height >= 0, 'Trying to save a header with incorrect height.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (this._lastHeader.height < 0) { log.error('Trying to save a header with incorrect height.');
}
// assert(this._lastHeader.height >= 0, 'Trying to save a header with incorrect height.');
var keyHeight = this._encoding.encodeHeaderHeightKey(this._lastHeader.height);
var value = this._encoding.encodeHeaderValue(this._lastHeader);
@ -465,9 +475,12 @@ HeaderService.prototype._onHeaders = function(headers) {
for(var i = 0; i < transformedHeaders.length; i++) {
var header = transformedHeaders[i];
assert(self._lastHeader.hash === header.prevHash, 'headers not in order: ' + self._lastHeader.hash +
' -and- ' + header.prevHash + ' Last header at height: ' + self._lastHeader.height);
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (self._lastHeader.hash != header.prevHash) {
log.error('headers not in order: ' + self._lastHeader.hash + ' -and- ' + header.prevHash + ' Last header at height: ' + self._lastHeader.height);
}
// assert(self._lastHeader.hash === header.prevHash, 'headers not in order: ' + self._lastHeader.hash + ' -and- ' + header.prevHash + ' Last header at height: ' + self._lastHeader.height);
var ops = self._onHeader(header);
@ -484,8 +497,9 @@ HeaderService.prototype._onHeaders = function(headers) {
};
HeaderService.prototype._handleError = function(err) {
log.error('Header Service: ' + err);
this.node.stop();
log.error('Error in Header Service: ' + err);
return;
//this.node.stop();
};
HeaderService.prototype._saveHeaders = function(dbOps, callback) {
@ -510,6 +524,7 @@ HeaderService.prototype._saveHeaders = function(dbOps, callback) {
HeaderService.prototype._onHeadersSave = function(callback) {
var self = this;
self._syncUnresponsive = false; //SZ: got response from peer
self._logProgress();
if (!self._syncComplete()) {
@ -517,6 +532,12 @@ HeaderService.prototype._onHeadersSave = function(callback) {
return callback();
}
//SZ: clear the interval check as sync is completed
if(self._syncCheckInterval){
clearInterval(self._syncCheckInterval);
self._syncCheckInterval = null;
}
self._endHeaderSubscription(); // we don't need headers any more
self._startBlockSubscription(); // we need new blocks coming tu us aynchronuously
@ -573,12 +594,15 @@ HeaderService.prototype._startBlockSubscription = function() {
};
HeaderService.prototype._syncComplete = function() {
// Check if we have reached the last block that we can download.
var bestHeight = Math.max(this._bestHeight, this._lastHeader.height);
// we always ask for the max number of headers, which is 2000.
// so any response with < 2000 means we have reached the end of the headers list.
// we could make an extra call if the number of total headers is multiple of 2000.
return this._lastHeaderCount < 2000;
var syncComplete = bestHeight === this._tip.height
if (syncComplete && this._initialSync)
log.info("Header Service: Sync Complete!")
return syncComplete
};
HeaderService.prototype._setBestHeader = function() {
@ -593,7 +617,7 @@ HeaderService.prototype._getHeader = function(height, hash, callback) {
/*jshint -W018 */
if (!hash && !(height >= 0)) {
/*jshint +W018 */
return callback(new Error('invalid arguments'));
return callback('invalid arguments');
}
if (height === self._lastHeader.height || hash === self._lastHeader.hash) {
@ -692,6 +716,23 @@ HeaderService.prototype._startSync = function() {
// common case
if (numNeeded > 0) {
log.info('Header Service: Gathering: ' + numNeeded + ' ' + 'header(s) from the peer-to-peer network.');
//SZ: Adding interval check for sync with peer is responsive or not
//(only if fcoin is started by flocore)
if(self._p2p._bcoin){
self._syncUnresponsive = true;
self._syncCheckInterval = setInterval(() => {
//check the best height
if(self._bestHeight < self._p2p._bcoin._bcoin.pool.chain.height)
self._bestHeight = self._p2p._bcoin._bcoin.pool.chain.height;
//call sync again if unresponsive
if(self._syncUnresponsive)
self._sync();
else //reset unresponsive as true
self._syncUnresponsive = true;
}, SYNC_CHECK_INTERVAL);
}
return self._sync();
}
@ -773,9 +814,11 @@ HeaderService.prototype._findReorgConditionInNewPeer = function(callback) {
// nothing matched...
// at this point, we should wonder if we are connected to the wrong network
assert(true, 'We tried to find a common header between current set of headers ' +
'and the new peer\'s set of headers, but there were none. This should be impossible ' +
' if the new peer is using the same genesis block.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (false) {
log.error('We tried to find a common header between current set of headers ' + 'and the new peer\'s set of headers, but there were none. This should be impossible ' + ' if the new peer is using the same genesis block.');
}
// assert(true, 'We tried to find a common header between current set of headers ' +'and the new peer\'s set of headers, but there were none. This should be impossible ' +' if the new peer is using the same genesis block.');
});
self._getP2PHeaders(self.GENESIS_HASH);
@ -876,7 +919,11 @@ HeaderService.prototype._sync = function() {
HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
assert(blockCount >= 1, 'Header Service: block count to getEndHash must be at least 1.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (blockCount < 1) {
log.error('Header Service: block count to getEndHash must be at least 1.');
}
// assert(blockCount >= 1, 'Header Service: block count to getEndHash must be at least 1.');
var self = this;
@ -887,7 +934,7 @@ HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
}
if (numResultsNeeded <= 0) {
return callback(new Error('Header Service: block service is mis-aligned '));
return callback('Header Service: block service is mis-aligned ');
}
var startingHeight = tip.height + 1;
@ -917,8 +964,11 @@ HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
if (streamErr) {
return streamErr;
}
assert(results.length === numResultsNeeded, 'getEndHash returned incorrect number of results.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (results.length != numResultsNeeded) {
log.error('getEndHash returned incorrect number of results.');
}
// assert(results.length === numResultsNeeded, 'getEndHash returned incorrect number of results.');
var index = numResultsNeeded - 1;
var endHash = index <= 0 || !results[index] ? 0 : results[index];
@ -936,7 +986,11 @@ HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
};
HeaderService.prototype.getLastHeader = function() {
assert(this._lastHeader, 'Last header should be populated.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (this._lastHeader == false) {
log.error('Last header should be populated.'); return;
}
// assert(this._lastHeader, 'Last header should be populated.');
return this._lastHeader;
};
@ -949,7 +1003,7 @@ HeaderService.prototype._adjustHeadersForCheckPointTip = function(callback) {
var start = self._encoding.encodeHeaderHeightKey(self._tip.height);
var end = self._encoding.encodeHeaderHeightKey(0xffffffff);
log.info('Getting last header synced at height: ' + self._tip.height);
log.info('Header Service: Getting last header synced at height: ' + self._tip.height);
var criteria = {
gte: start,
@ -969,6 +1023,7 @@ HeaderService.prototype._adjustHeadersForCheckPointTip = function(callback) {
// any records with a height greater than our current tip height can be scheduled for removal
// because they will be replaced shortly
// and for every height record, we must also remove its hash record
if (header.height > self._tip.height) {
removalOps.push({
type: 'del',
@ -992,8 +1047,14 @@ HeaderService.prototype._adjustHeadersForCheckPointTip = function(callback) {
if (streamErr) {
return streamErr;
}
assert(self._lastHeader, 'The last synced header was not in the database.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (self._lastHeader == false) {
log.error('The last synced header was not in the database.');
}
//assert(self._lastHeader, 'The last synced header was not in the database.');
self._tip.hash = self._lastHeader.hash;
self._tip.height = self._lastHeader.height;
self._db.batch(removalOps, callback);

View File

@ -1,6 +1,6 @@
'use strict';
var tx = require('bcoin').tx;
var tx = require('fcoin').TX;
function Encoding(servicePrefix) {
this.servicePrefix = servicePrefix;

View File

@ -247,7 +247,7 @@ MempoolService.prototype._onTransaction = function(tx) {
self._db.batch(ops, function(err) {
if(err) {
log.error(err);
self.node.stop();
// self.node.stop();
}
for (var i = 0; i < self._subscriptions.transaction.length; i++) {

View File

@ -2,47 +2,51 @@
var index = require('../../');
var log = index.log;
var bcoin = require('bcoin');
var bcoin = require('fcoin');
// var bzmq = require('bzmq');
var Bcoin = function(options) {
this._config = this._getConfig(options);
};
Bcoin.prototype.start = function(callback) {
var self = this;
self._bcoin = bcoin.fullnode(self._config);
this._bcoin = new bcoin.FullNode(this._config);
log.info('Starting Bcoin full node...');
log.info('Starting fcoin FullNode...');
self._bcoin.open().then(function() {
self._bcoin.connect().then(function() {
log.info('Waiting for Bcoin to sync');
self._bcoin.startSync();
// this will instruct the p2p service to start trying to connect to bcoin right away
this._bcoin.open().then(() => {
this._bcoin.connect().then(() => {
this._bcoin.startSync();
callback();
});
});
};
Bcoin.prototype.stop = function() {
this._bcoin.stopSync();
this._bcoin.disconnect();
this._bcoin.close();
Bcoin.prototype.stop = function(callback) {
this._bcoin.close().then(() => {
log.info("fcoin shutdown")
callback()
});
};
// --- privates
Bcoin.prototype._getConfig = function(options) {
var config = {
db: 'leveldb',
checkpoints: true,
network: options.network || 'main',
listen: true,
port: options.port,
logFile: true,
logConsole: true,
logLevel: 'info',
port: options.port,
persistent: true,
workers: true
// indexTx: true,
// indexAddress: true,
checkpoints: true,
memory: false,
workers: true,
listen: true
};
if (options.prefix) {
config.prefix = options.prefix;

View File

@ -1,6 +1,6 @@
'use strict';
var p2p = require('bitcore-p2p');
var p2p = require('flocore-p2p');
var LRU = require('lru-cache');
var util = require('util');
var index = require('../../');
@ -8,8 +8,10 @@ var log = index.log;
var BaseService = require('../../service');
var assert = require('assert');
var Bcoin = require('./bcoin');
var BcoinTx = require('bcoin').tx;
var Networks = require('bitcore-lib').Networks;
var BcoinBlock = require('fcoin').Block;
var BcoinTx = require('fcoin').TX;
var Networks = require('flocore-lib').Networks;
var BitcoreRPC = require('bitcoind-rpc');
var LRU = require('lru-cache');
var P2P = function(options) {
@ -21,6 +23,7 @@ var P2P = function(options) {
BaseService.call(this, options);
this._options = options;
this._initRPC(options);
this._initP2P();
this._initPubSub();
this._bcoin = null;
@ -87,7 +90,7 @@ P2P.prototype.getP2PBlock = function(opts, callback) {
self.once(opts.blockHash, callback);
peer.sendMessage(self.messages.GetBlocks(blockFilter));
peer.sendMessage(self.messages.GetBlocks(blockFilter, { Block: BcoinBlock }));
};
P2P.prototype.getHeaders = function(filter) {
@ -128,26 +131,7 @@ P2P.prototype.getPublishEvents = function() {
P2P.prototype.sendTransaction = function(tx, callback) {
var peer = this._getPeer();
var bcoinTx;
try {
bcoinTx = BcoinTx.fromRaw(tx, 'hex');
} catch(e) {
return callback(e);
}
log.info('P2P Service: sending transaction: ' + bcoinTx.txid());
this._outgoingTxs.set(bcoinTx.txid(), bcoinTx);
var inv = p2p.Inventory.forTransaction(bcoinTx.txid());
var txMessage = this.messages.Inventory([inv]);
peer.sendMessage(txMessage);
this._onPeerTx(peer, { transaction: bcoinTx });
return callback(null, bcoinTx.txid());
return this._client.sendRawTransaction(tx, callback);
};
@ -269,6 +253,23 @@ P2P.prototype._initCache = function() {
this._inv = LRU(1000);
};
P2P.prototype._initRPC = function (options) {
var port = 7313
if (this.node.network === 'testnet')
port = 17313
this._config = options.rpc || {
user: 'flocore',
pass: 'flocorepassw123',
host: 'localhost',
protocol: 'http',
port: port
};
this._client = new BitcoreRPC(this._config);
}
P2P.prototype._initP2P = function() {
this._maxPeers = this._options.maxPeers || 60;
this._minPeers = this._options.minPeers || 0;
@ -277,7 +278,7 @@ P2P.prototype._initP2P = function() {
if (this.node.network === 'regtest') {
Networks.enableRegtest();
}
this.messages = new p2p.Messages({ network: Networks.get(this.node.network), Transaction: BcoinTx });
this.messages = new p2p.Messages({ network: Networks.get(this.node.network), Transaction: BcoinTx, Block: BcoinBlock });
this._peerHeights = [];
this._peers = [];
this._peerIndex = 0;
@ -363,7 +364,8 @@ P2P.prototype._matchNetwork = function(network) {
log.error('Configured network: "' + this.node.network +
'" does not match our peer\'s reported network: "' +
network.name + '".');
return this.node.stop();
// return this.node.stop();
return ;
}
return this.node.network === network.name ? network.name : network.alias;
@ -423,7 +425,12 @@ P2P.prototype._setListeners = function() {
P2P.prototype._setResourceFilter = function(filter) {
assert(filter && filter.startHash, 'A "startHash" field is required to retrieve headers or blocks');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (filter == false || filter.startHash == false) {
log.error('A "startHash" field is required to retrieve headers or blocks');
}
// assert(filter && filter.startHash, 'A "startHash" field is required to retrieve headers or blocks');
if (!filter.endHash) {
filter.endHash = 0;
}
@ -432,29 +439,26 @@ P2P.prototype._setResourceFilter = function(filter) {
};
P2P.prototype._startBcoin = function(callback) {
var self = this;
var network;
var port;
if (['livenet', 'live', 'main', 'mainnet'].indexOf(this.node.network) !== -1) {
network = 'main';
port = this._configPeers[0].port || 8333;
port = this._configPeers[0].port || 7312;
} else if (this.node.network !== 'regtest') {
network = 'testnet';
port = this._configPeers[0].port || 18333;
port = this._configPeers[0].port || 17312;
} else {
network = this.node.network;
port = this._configPeers[0].port || 48444;
port = this._configPeers[0].port || 17412;
}
self._bcoin = new Bcoin({
this._bcoin = new Bcoin({
network: network,
prefix: self.node.datadir,
prefix: this.node.datadir,
port: port
});
self._bcoin.start(callback);
this._bcoin.start(callback);
};

View File

@ -91,7 +91,7 @@ TimestampService.prototype.onBlock = function(block, callback) {
var operations = [];
var ts = block.ts;
var ts = block.time;
var hash = block.rhash();
if (ts <= this._lastBlockTimestamp) {

View File

@ -1,6 +1,6 @@
'use strict';
var Tx = require('bcoin').tx;
var Tx = require('fcoin').TX;
function Encoding(servicePrefix) {
this.servicePrefix = servicePrefix;

View File

@ -7,6 +7,7 @@ var _ = require('lodash');
var async = require('async');
var assert = require('assert');
var LRU = require('lru-cache');
var log = require('../../index').log;
function TransactionService(options) {
BaseService.call(this, options);
@ -16,7 +17,6 @@ function TransactionService(options) {
this._header = this.node.services.header;
this._p2p = this.node.services.p2p;
this._timestamp = this.node.services.timestamp;
this._address = this.node.services.address;
this._network = this.node.network;
if (this._network === 'livenet') {
@ -114,7 +114,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
var self = this;
if (typeof callback !== 'function') {
if (!_.isFunction(callback)) {
callback = options;
}
@ -131,7 +131,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
if (err) {
return callback(err);
}
if (tx) {
if (tx && tx.confirmations >= 6) {
self._cacheTx.set(txid, tx);
}
callback(err, tx);
@ -185,8 +185,11 @@ TransactionService.prototype.setTxMetaInfo = function(tx, options, callback) {
var inputSatoshis = 0;
assert(tx.__inputValues.length === tx.inputs.length,
'Transaction Service: input values length is not the same as the number of inputs.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (tx.__inputValues.length != tx.inputs.length) {
log.error('Transaction Service: input values length is not the same as the number of inputs.');
}
// assert(tx.__inputValues.length === tx.inputs.length, 'Transaction Service: input values length is not the same as the number of inputs.');
tx.__inputValues.forEach(function(val) {
@ -309,13 +312,18 @@ TransactionService.prototype._getInputValues = function(tx, options, callback) {
// if not in mempool or tx index, we just don't have it, yet?
function(txid, tx, next) {
if (!tx) {
return next(new Error('Transaction Service: prev transacion: (' + input.prevout.txid() + ') for tx: ' +
return next(log.error('Transaction Service: prev transacion: (' + input.prevout.txid() + ') for tx: ' +
_tx.txid() + ' at input index: ' + outputIndex + ' is missing from the index or not in the memory pool. It could be' +
' that the parent tx has not yet been relayed to us, but will be relayed in the near future.'));
}
var output = tx.outputs[outputIndex];
assert(output, 'Expected an output, but did not get one for tx: ' + tx.txid() + ' outputIndex: ' + outputIndex);
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (output == false) {
log.error('Expected an output, but did not get one for tx: ' + tx.txid() + ' outputIndex: ' + outputIndex);
}
// assert(output, 'Expected an output, but did not get one for tx: ' + tx.txid() + ' outputIndex: ' + outputIndex);
next(null, output.value);
}
@ -375,7 +383,11 @@ TransactionService.prototype.onBlock = function(block, callback) {
return callback(err);
}
assert(block.txs.length === operations.length, 'It seems we are not indexing the correct number of transactions.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (block.txs.length != operations.length) {
log.error('It seems we are not indexing the correct number of transactions.');
}
// assert(block.txs.length === operations.length, 'It seems we are not indexing the correct number of transactions.');
callback(null, _.flattenDeep(operations));
});
@ -477,19 +489,30 @@ TransactionService.prototype._processTransaction = function(tx, opts, callback)
return callback(err);
}
assert(inputValues && inputValues.length === tx.inputs.length,
'Input values missing from tx.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (inputValues == false || inputValues.length != tx.inputs.length) {
log.error('Input values missing from tx.');
}
// assert(inputValues && inputValues.length === tx.inputs.length, 'Input values missing from tx.');
// inputValues
tx.__inputValues = inputValues;
// timestamp
tx.__timestamp = self._getBlockTimestamp(opts.block.rhash());
assert(tx.__timestamp, 'Timestamp is required when saving a transaction.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (tx.__timestamp == false) {
log.error('Timestamp is required when saving a transaction.');
}
// assert(tx.__timestamp, 'Timestamp is required when saving a transaction.');
// height
tx.__height = opts.block.__height;
assert(tx.__height, 'Block height is required when saving a trasnaction.');
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
if (tx.__height == false) {
log.error('Block height is required when saving a trasnaction.');
}
//assert(tx.__height, 'Block height is required when saving a trasnaction.');
// block hash
tx.__blockhash = opts.block.rhash();

View File

@ -4,13 +4,14 @@ var fs = require('fs');
var http = require('http');
var https = require('https');
var express = require('express');
var express_ws = require('express-ws');
var bodyParser = require('body-parser');
var socketio = require('socket.io');
var inherits = require('util').inherits;
var BaseService = require('../../service');
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var flocore = require('flocore-lib');
var _ = flocore.deps._;
var index = require('../../');
var log = index.log;
@ -105,7 +106,7 @@ WebService.prototype.setupAllRoutes = function() {
if(service.getRoutePrefix && service.setupRoutes) {
this.app.use('/' + this.node.services[key].getRoutePrefix(), subApp);
this.node.services[key].setupRoutes(subApp, express);
this.node.services[key].setupRoutes(subApp, express, express_ws);
} else {
log.debug('No routes defined for: ' + key);
}

View File

@ -175,7 +175,7 @@ utils.getAddress = function(item, network) {
return;
}
address.network = network;
return address.toString();
return address.toString(network);
};
module.exports = utils;

6033
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +1,59 @@
{
"name": "bitcore-node",
"description": "Full node with extended capabilities using Bitcore and Bitcoin Core",
"name": "flocore-node",
"description": "Full node with extended capabilities using Flocore and Florincoin Core",
"engines": {
"node": ">=8.0.0"
},
"author": "BitPay <dev@bitpay.com>",
"version": "5.0.0-beta.40",
"version": "5.0.9-beta-rm",
"main": "./index.js",
"repository": "git://github.com/bitpay/bitcore-node.git",
"homepage": "https://github.com/bitpay/bitcore-node",
"repository": "git://github.com/ranchimall/flocore-node.git",
"homepage": "https://github.com/ranchimall/flocore-node",
"bugs": {
"url": "https://github.com/bitpay/bitcore-node/issues"
"url": "https://github.com/ranchimall/flocore-node/issues"
},
"bin": {
"bitcore-node": "./bin/bitcore-node"
"flocore-node": "./bin/flocore-node"
},
"scripts": {
"test": "NODE_ENV=test mocha -R spec --recursive test"
},
"tags": [
"bitcoin",
"bitcoind",
"florincoin",
"florincoind",
"bcoin",
"bitcoin full node",
"bitcoin index",
"florincoin full node",
"florincoin index",
"block explorer",
"wallet backend"
],
"dependencies": {
"async": "^2.5.0",
"bcoin": "bitpay/bcoin#v1.0.0-beta.14+cash",
"bitcoind-rpc": "^0.6.0",
"bitcore-lib": "5.0.0-beta.1",
"bitcore-p2p": "5.0.0-beta.1",
"bitcoind-rpc": "^0.7.2",
"bn.js": "^4.11.8",
"body-parser": "^1.13.3",
"colors": "^1.1.2",
"commander": "^2.8.1",
"errno": "^0.1.4",
"express": "^4.13.3",
"express-ws": "^5.0.2",
"fcoin": "^1.1.4",
"flocore-lib": "^0.15.2",
"flocore-message": "^1.0.7",
"flocore-p2p": "^5.0.0-beta.8",
"florincoind-rpc": "0.7.1",
"flosight-api": "github:ranchimall/flosight-api",
"flosight-ui": "github:ranchimall/flosight-ui",
"leveldown": "^2.0.0",
"levelup": "^2.0.0",
"liftoff": "^2.2.0",
"lodash": "^4.17.4",
"lru-cache": "^4.0.2",
"memwatch-next": "^0.3.0",
"lodash": "^4.17.12",
"lru-cache": "^4.1.1",
"mkdirp": "0.5.0",
"path-is-absolute": "^1.0.0",
"socket.io": "^1.4.5",
"socket.io-client": "^1.4.5"
"socket.io-client": "^1.4.5",
"xxhash": "^0.2.4"
},
"devDependencies": {
"chai": "^3.5.0",
@ -56,7 +61,7 @@
"istanbul": "^0.4.3",
"jshint": "^2.9.2",
"jshint-stylish": "^2.1.0",
"mocha": "3.2.0",
"mocha": "^6.2.0",
"proxyquire": "^1.3.1",
"rimraf": "^2.4.2",
"sinon": "^1.15.4"

View File

@ -3,10 +3,10 @@
var should = require('chai').should();
describe('Index Exports', function() {
it('will export bitcore-lib', function() {
var bitcore = require('../');
should.exist(bitcore.lib);
should.exist(bitcore.lib.Transaction);
should.exist(bitcore.lib.Block);
it('will export flocore-lib', function() {
var flocore = require('../');
should.exist(flocore.lib);
should.exist(flocore.lib.Transaction);
should.exist(flocore.lib.Block);
});
});

View File

@ -25,7 +25,7 @@ describe('#add', function() {
throw err;
}
fs.writeFile(
testDir + '/s0/s1/bitcore-node.json',
testDir + '/s0/s1/flocore-node.json',
JSON.stringify(startConfig),
function(err) {
if (err) {
@ -90,12 +90,12 @@ describe('#add', function() {
});
});
it('will update bitcore-node.json services', function(done) {
it('will update flocore-node.json services', function(done) {
var callCount = 0;
var oldPackage = {
dependencies: {
'bitcore-lib': '^v0.13.7',
'bitcore-node': '^v0.2.0'
'flocore-lib': '^v0.13.7',
'flocore-node': '^v0.2.0'
}
};
var spawn = sinon.stub().returns({
@ -130,7 +130,7 @@ describe('#add', function() {
services: ['a', 'b', 'c']
}, function(err) {
should.not.exist(err);
var configPath = path.resolve(testDir, 's0/s1/bitcore-node.json');
var configPath = path.resolve(testDir, 's0/s1/flocore-node.json');
var config = JSON.parse(fs.readFileSync(configPath));
config.services.should.deep.equal(['a','b','c']);
done();

View File

@ -33,7 +33,7 @@ describe('#create', function() {
if (err) {
throw err;
}
mkdirp(testDir + '/.bitcoin', function(err) {
mkdirp(testDir + '/.florincoin', function(err) {
if (err) {
throw err;
}
@ -64,14 +64,14 @@ describe('#create', function() {
throw err;
}
var configPath = testDir + '/mynode/bitcore-node.json';
var configPath = testDir + '/mynode/flocore-node.json';
var packagePath = testDir + '/mynode/package.json';
should.equal(fs.existsSync(configPath), true);
should.equal(fs.existsSync(packagePath), true);
var config = JSON.parse(fs.readFileSync(configPath));
config.services.should.deep.equal(['bitcoind', 'db', 'address', 'web']);
config.services.should.deep.equal(['florincoind', 'db', 'address', 'web']);
config.datadir.should.equal('./data');
config.network.should.equal('livenet');
@ -104,7 +104,7 @@ describe('#create', function() {
dirname: 'mynode3',
name: 'My Node 3',
isGlobal: true,
datadir: '../.bitcoin'
datadir: '../.florincoin'
}, function(err) {
if (err) {
throw err;
@ -139,7 +139,7 @@ describe('#create', function() {
dirname: 'mynode4',
name: 'My Node 4',
isGlobal: false,
datadir: '../.bitcoin'
datadir: '../.florincoin'
}, function(err) {
should.exist(err);
err.message.should.equal('There was an error installing dependencies.');

View File

@ -25,7 +25,7 @@ describe('#remove', function() {
throw err;
}
fs.writeFile(
testDir + '/s0/s1/bitcore-node.json',
testDir + '/s0/s1/flocore-node.json',
JSON.stringify(startConfig),
function(err) {
if (err) {
@ -64,7 +64,7 @@ describe('#remove', function() {
});
});
it('will update bitcore-node.json services', function(done) {
it('will update flocore-node.json services', function(done) {
var spawn = sinon.stub().returns({
stdout: {
on: sinon.stub()
@ -92,7 +92,7 @@ describe('#remove', function() {
services: ['b']
}, function(err) {
should.not.exist(err);
var configPath = path.resolve(testDir, 's0/s1/bitcore-node.json');
var configPath = path.resolve(testDir, 's0/s1/flocore-node.json');
var config = JSON.parse(fs.readFileSync(configPath));
config.services.should.deep.equal(['a', 'c']);
done();

View File

@ -1,6 +1,6 @@
'use strict';
var bitcore = require('bitcore-lib');
var flocore = require('flocore-lib');
var should = require('chai').should();
var Encoding = require('../../../lib/services/address/encoding');
@ -38,7 +38,7 @@ describe('Address service encoding', function() {
new Buffer(txid, 'hex'),
new Buffer('00000005', 'hex')]);
var txHex = '0100000001cc3ffe0638792c8b39328bb490caaefe2cf418f2ce0144956e0c22515f29724d010000006a473044022030ce9fa68d1a32abf0cd4adecf90fb998375b64fe887c6987278452b068ae74c022036a7d00d1c8af19e298e04f14294c807ebda51a20389ad751b4ff3c032cf8990012103acfcb348abb526526a9f63214639d79183871311c05b2eebc727adfdd016514fffffffff02f6ae7d04000000001976a9144455183e407ee4d3423858c8a3275918aedcd18e88aca99b9b08010000001976a9140beceae2c29bfde08d2b6d80b33067451c5887be88ac00000000';
var tx = new bitcore.Transaction(txHex);
var tx = new flocore.Transaction(txHex);
var sats = tx.outputs[0].satoshis;
var satsBuf = new Buffer(8);
satsBuf.writeDoubleBE(sats);

View File

@ -8,6 +8,7 @@ var Encoding = require('../../../lib/services/address/encoding');
var Readable = require('stream').Readable;
var EventEmitter = require('events').EventEmitter;
var bcoin = require('bcoin');
var lodash = require('lodash');
describe('Address Service', function() {
@ -54,7 +55,7 @@ describe('Address Service', function() {
describe('#getAddressHistory', function() {
it('should get the address history', function(done) {
it('should get the address history (null case)', function(done) {
sandbox.stub(addressService, '_getAddressTxidHistory').callsArgWith(2, null, null);
sandbox.stub(addressService, '_getAddressTxHistory').callsArgWith(1, null, []);
@ -74,6 +75,222 @@ describe('Address Service', function() {
});
});
it('should get the sorted address history', function(done) {
var old_getAddressTxidHistory = addressService._getAddressTxidHistory;
addressService._getAddressTxidHistory = function(addr, options, cb) {
options.txIdList = [
{
txid: "d",
height: 10,
},
{
txid: "c",
height: 10,
},
{
txid: "a",
height: 101,
},
{
txid: "b",
height: 100,
},
];
return cb();
};
var old_getAddressTxHistory = addressService._getAddressTxHistory;
addressService._getAddressTxHistory = function(options, cb) {
return cb(null, options.txIdList);
};
addressService.getAddressHistory(['a', 'b', 'c'], { from: 12, to: 14 }, function(err, res) {
if (err) {
return done(err);
}
expect(res.totalCount).equal(4);
expect(lodash.map(res.items,'txid')).to.be.deep.equal(['a','b','c','d']);
addressService._getAddressTxidHistory = old_getAddressTxHistory;
addressService._getAddressTxHistory = old_getAddressTxHistory;
done();
});
});
it('should remove duplicated items in history', function(done) {
var old_getAddressTxidHistory = addressService._getAddressTxidHistory;
addressService._getAddressTxidHistory = function(addr, options, cb) {
options.txIdList = [
{
txid: "b",
height: 10,
},
{
txid: "b",
height: 10,
},
{
txid: "d",
height: 101,
},
{
txid: "c",
height: 100,
},
{
txid: "d",
height: 101,
},
];
return cb();
};
var old_getAddressTxHistory = addressService._getAddressTxHistory;
addressService._getAddressTxHistory = function(options, cb) {
return cb(null, options.txIdList);
};
addressService.getAddressHistory(['a', 'b', 'c'], { from: 12, to: 14 }, function(err, res) {
if (err) {
return done(err);
}
expect(res.totalCount).equal(3);
expect(lodash.map(res.items,'txid')).to.be.deep.equal(['d','c','b']);
addressService._getAddressTxidHistory = old_getAddressTxHistory;
addressService._getAddressTxHistory = old_getAddressTxHistory;
done();
});
});
describe('TxIdList cache', function() {
var list, old_getAddressTxidHistory, old_getAddressTxHistory;
beforeEach(function(done){
this.clock = sinon.useFakeTimers();
list = [];
for(let i=1000; i>0; i--) {
list.push({
txid: "txid" + i,
height: 1000 + i,
});
};
old_getAddressTxidHistory = addressService._getAddressTxidHistory;
// Note that this stub DOES NOT respect options.from/to as the real function
addressService._getAddressTxidHistory = function(addr, options, cb) {
options.txIdList = lodash.clone(list);
return cb();
};
old_getAddressTxHistory = addressService._getAddressTxHistory;
addressService._getAddressTxHistory = function(options, cb) {
return cb(null, options.txIdList);
};
addressService.getAddressHistory(['a', 'b', 'c'], { from: 0, to: 10 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
expect(cacheUsed).equal(false);
done();
});
});
afterEach(function(done){
this.clock.restore();
addressService._getAddressTxidHistory = old_getAddressTxHistory;
addressService._getAddressTxHistory = old_getAddressTxHistory;
done();
});
it('should not cache the address txlist history when from =0 ', function(done) {
addressService.getAddressHistory(['a', 'b', 'c'], { from: 0, to: 10 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
expect(cacheUsed).equal(false);
done();
});
});
it('should cache the address txlist history', function(done) {
addressService.getAddressHistory(['a', 'b', 'c'], { from: 1, to: 10 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(cacheUsed).equal(true);
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
done();
});
});
it('should retrive cached list using cachekey', function(done) {
addressService.getAddressHistory([], { from: 1, to: 10, cacheKey: 977282097 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(cacheUsed).equal(true);
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
done();
});
});
it('should expire cache', function(done) {
this.clock.tick(35*1000);
addressService.getAddressHistory(['a', 'b', 'c'], { from: 1, to: 10 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(cacheUsed).equal(false);
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
done();
});
});
it('should cache using the address as key', function(done) {
addressService.getAddressHistory(['a', 'b', 'c', 'd'], { from: 1, to: 10 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(cacheUsed).equal(false);
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
addressService.getAddressHistory(['a', 'b', 'c', 'd'], { from: 1, to: 10 }, function(err, res, cacheUsed) {
if (err) {
return done(err);
}
expect(cacheUsed).equal(true);
expect(res.totalCount).equal(1000);
expect(res.items,'txid').to.be.deep.equal(list);
done();
});
});
});
});
});
describe('#_getAddressTxidHistory', function() {

View File

@ -77,7 +77,7 @@ describe('DB', function() {
it('should set the data path', function() {
dbService._setDataPath();
dbService.dataPath.should.equal('/tmp/regtest/bitcorenode.db');
dbService.dataPath.should.equal('/tmp/regtest/flocorenode.db');
});
});

View File

@ -13,7 +13,7 @@ describe('#Fee Service', function() {
sandbox = sinon.sandbox.create();
feeService = new FeeService({
rpc: {
user: 'bitcoin',
user: 'florincoin',
pass: 'local321',
host: 'localhost',
protocol: 'http',

View File

@ -7,7 +7,7 @@ var assert = chai.assert;
var expect = chai.expect;
var Encoding = require('../../../lib/services/header/encoding');
var utils = require('../../../lib/utils');
var Block = require('bitcore-lib').Block;
var Block = require('flocore-lib').Block;
var BN = require('bn.js');
var Emitter = require('events').EventEmitter;
var bcoin = require('bcoin');