Compare commits

...
388 Commits
Author SHA1 Message Date
Chris Troutner 2ad10180d0 Merge pull request #70 from Permissionless-Software-Foundation/ct-upstream
fix(ipfs-coord): Updating to v7.1.3
2022-03-05 08:35:10 -08:00
Chris Troutner dd42f5da16 fix(upstream): Syncing with upstream. Updating ipfs-coord 2022-03-05 08:32:38 -08:00
Chris Troutner 496a1dd07c Merge pull request #77 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v7.1.3
2022-03-05 08:26:32 -08:00
Chris Troutner a7b8ca9ad5 linting 2022-03-05 08:24:50 -08:00
Chris Troutner 6eb16eb11a fix(ipfs-coord): Updating to v7.1.3 2022-03-05 08:24:36 -08:00
Chris Troutner 553957a173 Merge pull request #69 from Permissionless-Software-Foundation/ct-unstable
fix(bch-js): Updating to 5.3.1
2022-01-31 21:20:51 -08:00
Chris Troutner 99a737c7e7 fix(bch-js): Updating to 5.3.1 2022-01-31 21:17:40 -08:00
Chris Troutner ffb87d09c2 Merge pull request #68 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-01-31 10:39:37 -08:00
Chris Troutner 65ead3568a Merge branch 'master' into ct-unstable 2022-01-31 10:34:52 -08:00
Chris Troutner b4b2aefac6 synced with upstream ipfs-service-provider 2022-01-31 10:33:54 -08:00
Chris Troutner 1844f30dc5 Merge pull request #76 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Bumping to v6.8.12
2022-01-31 10:31:20 -08:00
Chris Troutner b6ab2f02f4 Updating package-lock 2022-01-31 10:29:45 -08:00
Chris Troutner b5c76aa5fe fix(ipfs-coord): Bumping to v6.8.12 2022-01-31 10:28:06 -08:00
Chris Troutner 7648c96a70 Removing console logs 2022-01-29 17:37:22 -08:00
Chris Troutner 79f5adaf6b fix(bch-js): Tweeking initialization at startup 2022-01-29 17:29:26 -08:00
Chris Troutner e2f84d661f Debugging bch-js 2022-01-29 17:13:46 -08:00
Chris Troutner 31091a50a8 fix(startup): Announcing APISERVER when default init of bch-js is overridden 2022-01-29 15:53:45 -08:00
Chris Troutner 512775c68f More debugging 2022-01-29 15:42:50 -08:00
Chris Troutner c53394e547 Merge pull request #67 from Permissionless-Software-Foundation/ct-unstable
Adding debugging to txData()
2022-01-29 15:34:56 -08:00
Chris Troutner 79083502fb Adding debugging to txData() 2022-01-29 14:52:19 -08:00
Chris Troutner 6049c6566f Merge pull request #66 from Permissionless-Software-Foundation/ct-unstable
fix(getTxData): Removing txData property from output
2022-01-29 09:21:25 -08:00
Chris Troutner 99a52ec605 fix(getTxData): Removing txData property from output 2022-01-29 09:19:43 -08:00
Chris Troutner 33e7bc2b52 Merge pull request #65 from Permissionless-Software-Foundation/ct-unstable
feat(txData): Renamed transaction JSON endpoint to txData
2022-01-29 07:39:47 -08:00
Chris Troutner a20f30ec1e feat(txData): Renamed transaction JSON endpoint to txData 2022-01-29 07:38:05 -08:00
Chris Troutner b0b12c590c Merge pull request #64 from Permissionless-Software-Foundation/ct-unstable
feat(txHistory): Renamed transactions JSON endpoint to txHistory
2022-01-29 07:11:58 -08:00
Chris Troutner 286092f2e3 feat(txHistory): Renamed transactions JSON endpoint to txHistory 2022-01-29 07:09:40 -08:00
Chris Troutner 5be93afc38 fix(production): adding .env file to docker folder to prevent orphan warning 2022-01-28 19:43:51 -08:00
Chris Troutner 63cb107a25 Merge pull request #63 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to 6.8.11
2022-01-28 19:32:43 -08:00
Chris Troutner c54fb73c7d fix(bch): Adding additional debugging statements for BCH endpoints 2022-01-28 19:31:04 -08:00
Chris Troutner 8063c0e922 fix(ipfs-coord): Updating to 6.8.11 2022-01-28 19:26:41 -08:00
Chris Troutner b729c7ed80 Merge pull request #62 from Permissionless-Software-Foundation/ct-unstable
feat(transaction): Refactoring to allow up to 20 TXIDs per call
2022-01-28 12:06:12 -08:00
Chris Troutner 5a3d91e3b0 feat(transaction): Refactoring to allow up to 20 TXIDs per call 2022-01-28 12:04:35 -08:00
Chris Troutner d9fa44328a Merge pull request #61 from Permissionless-Software-Foundation/ct-unstable
Heavily refactored transaction history JSON RPC endpoint
2022-01-28 08:15:36 -08:00
Chris Troutner efaffa8e0f fix(getTransactions()): Added unit tests 2022-01-28 08:03:35 -08:00
Chris Troutner 27a9e9f3f3 Working on unit tests 2022-01-28 06:55:50 -08:00
Chris Troutner 41a5071467 fix(JSON transactions): Updated to new algorithm 2022-01-28 06:37:18 -08:00
Chris Troutner c6c3bb5d9c More debugging of pagination 2022-01-27 19:01:57 -08:00
Chris Troutner e4977a4351 Debugging pagination 2022-01-27 18:58:28 -08:00
Chris Troutner fe3b45f6be fixing typo 2022-01-27 17:54:17 -08:00
Chris Troutner d25b240112 Debugging 2022-01-27 17:52:16 -08:00
Chris Troutner 7a89a06ddb fix(getTransactions()): Adding pagination to tx history 2022-01-27 17:47:03 -08:00
Chris Troutner 74fb65df72 more debugging 2022-01-27 15:10:46 -08:00
Chris Troutner 0b38247f5a more debugging 2022-01-27 15:05:08 -08:00
Chris Troutner 473aaae307 debugging 2022-01-27 15:00:54 -08:00
Chris Troutner 284f4e4478 Debugging and reporting errors 2022-01-27 14:58:00 -08:00
Chris Troutner 56f6dc273a Restoring bch-js 2022-01-27 09:06:39 -08:00
Chris Troutner 4bd3387bde feat(transactions): Refactored JSON RPC transactions endpoint 2022-01-27 08:47:06 -08:00
Chris Troutner 7e7e91460a fix(integration): Adding integration test script to package.json 2022-01-24 13:21:29 -08:00
Chris Troutner e5f6f24570 Created mock unit tests for BCH use cases 2022-01-24 13:13:55 -08:00
Chris Troutner 818c85e3d4 Merge branch 'master' into ct-unstable 2022-01-24 12:32:24 -08:00
Chris Troutner 4101615a4a Merge pull request #75 from Permissionless-Software-Foundation/ct-unstable
Maintenance
2022-01-20 08:05:50 -08:00
Chris Troutner 34a4072384 fix(restart): Removing code the auto-restarts app after 2 hours 2022-01-20 07:56:40 -08:00
Chris Troutner 5fc72be10c fix(fullstack-jwt.js): Got unit test coverage back to 100% 2022-01-20 07:53:12 -08:00
Chris Troutner 651c4a1346 Debugging transactions JSON RPC endpoint 2022-01-19 15:58:25 -08:00
Chris Troutner 4b90ad5009 fix(bch-js): Upgrading to v5.2.2 2022-01-19 15:31:25 -08:00
Chris Troutner 05ddf8521a fix(bch-js): Updating to v5.2.1 2022-01-19 11:34:58 -08:00
Chris Troutner 88d1805685 Merge pull request #60 from Permissionless-Software-Foundation/ct-unstable
No-op
2022-01-18 15:38:12 -08:00
Chris Troutner ea104b5586 Rolling back debug console.logs 2022-01-18 15:31:15 -08:00
Chris Troutner 4251e2a02d more debugging 2022-01-18 15:22:26 -08:00
Chris Troutner 5e0eb017ef Debugging 2022-01-18 15:16:45 -08:00
Chris Troutner 86946968fe Merge pull request #59 from Permissionless-Software-Foundation/ct-unstable
fix(bch-js): Updating to bch-js v5
2022-01-18 12:40:22 -08:00
Chris Troutner 9597f1963f fix(bch-js): Updating to bch-js v5 2022-01-18 12:38:33 -08:00
Chris Troutner 67d80056ff Merge pull request #58 from Permissionless-Software-Foundation/ct-unstable
New version. Syncing with upstream ipfs-service-provider
2022-01-18 12:32:55 -08:00
Chris Troutner 199677e4c6 synced with upstream ipfs-service-provider 2022-01-18 12:14:51 -08:00
Chris Troutner 86ea5c6354 fix(version): Bumping to v2.0.0 2022-01-18 12:08:36 -08:00
Chris Troutner 7b112a13d4 fix(cors): Fixing bug leading to CORS error 2022-01-12 15:33:04 -08:00
Chris Troutner fe5c573291 Merge pull request #74 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Skipping IPFS stuff in test environment
2022-01-09 11:54:41 -08:00
Chris Troutner 463d7df582 fix(tests): Skipping IPFS stuff in test environment 2022-01-09 11:51:15 -08:00
Chris Troutner 5a1ec640a4 Merge pull request #73 from Permissionless-Software-Foundation/ct-unstable
Adding swarm.key
2022-01-03 11:39:57 -08:00
Chris Troutner 8bb8dbcd23 Updating READMe 2022-01-03 11:35:26 -08:00
Chris Troutner ba212b0997 fix(ipfs): Adding swarm.key file for joining network 2022-01-03 11:22:15 -08:00
Chris Troutner 803496fbc3 Merge pull request #57 from Permissionless-Software-Foundation/ct-unstable
Syncing upstream ipfs-service-provider
2022-01-02 19:15:52 -08:00
Chris Troutner c49ab4f58b Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-01-02 19:14:28 -08:00
Chris Troutner 4670bd22af Merge pull request #72 from Permissionless-Software-Foundation/ct-unstable
fix(pubsub): Applying fix for pubsub in external node
2022-01-02 19:13:44 -08:00
Chris Troutner b3e7c63e61 fix(pubsub): Applying fix for pubsub in external node 2022-01-02 19:00:50 -08:00
Chris Troutner 421ca359f2 Merge pull request #56 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-01-01 21:06:35 -08:00
Chris Troutner 4e6559ac96 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-01-01 21:04:33 -08:00
Chris Troutner 1fcc92e10d Merge pull request #71 from Permissionless-Software-Foundation/ct-unstable
fix(ipsf-coord): Updating to v6.8.10
2022-01-01 21:01:14 -08:00
Chris Troutner f332aece98 fix(ipsf-coord): Updating to v6.8.10 2022-01-01 20:58:56 -08:00
Chris Troutner 4112b34205 Merge pull request #55 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-01-01 20:47:11 -08:00
Chris Troutner 30d0a62455 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2022-01-01 20:44:41 -08:00
Chris Troutner 89f24e9940 Merge pull request #70 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Switching to private network. Updating ipfs-coord
2022-01-01 20:40:23 -08:00
Chris Troutner 25a75dc369 fix(ipfs-coord): Switching to private network. Updating ipfs-coord to v6.8.9 2022-01-01 20:25:40 -08:00
Chris Troutner f36ce14087 fix(ipfs-coord): Updating v6.8.8 2022-01-01 18:58:47 -08:00
Chris Troutner df45792f47 fix(ipfs-coord): Updating to v6.8.7 2022-01-01 18:43:24 -08:00
Chris Troutner 9e71e33ccd Merge pull request #69 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.8.6
2022-01-01 18:20:30 -08:00
Chris Troutner c7b0b0c1d5 fix(ipfs-coord): Updating to v6.8.6 2022-01-01 18:19:07 -08:00
Chris Troutner e475e5f4c3 Downgrading ipfs-http-client 2022-01-01 16:41:56 -08:00
Chris Troutner 7fff41b702 fix(production): Fixing typo in docker-compose.yml 2022-01-01 06:51:54 -08:00
Chris Troutner a7f7fc4e14 Merge pull request #54 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-01-01 06:48:33 -08:00
Chris Troutner 83ad0d8bfa Merge branch 'master' into ct-unstable 2022-01-01 06:44:04 -08:00
Chris Troutner ac4aaca66e fix(production): Explictly using ipfs v0.11.0 docker container 2022-01-01 06:43:16 -08:00
Chris Troutner 0748106637 Merge pull request #68 from Permissionless-Software-Foundation/ct-unstable
fix(production): using explcit v0.11.0 ipfs docker container
2022-01-01 06:41:36 -08:00
Chris Troutner 27dcc219b9 fix(production): using explcit v0.11.0 ipfs docker container 2022-01-01 06:40:15 -08:00
Chris Troutner 1362e64c42 Merge pull request #53 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-12-31 18:44:59 -08:00
Chris Troutner 7aad5db594 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-12-31 18:42:36 -08:00
Chris Troutner b231686a64 Merge pull request #67 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.8.5
2021-12-31 18:40:55 -08:00
Chris Troutner 60668430f5 fix(ipfs-coord): Updating to v6.8.5 2021-12-31 18:38:17 -08:00
Chris Troutner cf0fb0f572 Merge pull request #52 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-12-31 16:04:19 -08:00
Chris Troutner 68b0117c3d Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-12-31 16:02:57 -08:00
Chris Troutner e73440f342 fix(production): Slight tweek to start-production.sh 2021-12-31 16:02:37 -08:00
Chris Troutner b9680508db Merge pull request #66 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.8.4
2021-12-31 16:01:32 -08:00
Chris Troutner acebfdef09 fix(ipfs-coord): Updating to v6.8.4 2021-12-31 15:59:06 -08:00
Chris Troutner c3ee71a54f Merge pull request #51 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-12-31 15:44:39 -08:00
Chris Troutner 0d9a32488e Merge branch 'master' into ct-unstable 2021-12-31 15:43:00 -08:00
Chris Troutner de7629c93d Syncing with upstream ipfs-service-provider 2021-12-31 15:42:16 -08:00
Chris Troutner 3979694109 Merge pull request #65 from Permissionless-Software-Foundation/ct-unstable
fix(production): Adding instructions for customizing IPFS docker cont…
2021-12-31 15:38:39 -08:00
Chris Troutner ae888d094b fix(production): Adding instructions for customizing IPFS docker container 2021-12-31 15:34:40 -08:00
Chris Troutner 9b8db2adaf Merge pull request #50 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-12-31 12:15:50 -08:00
Chris Troutner c8539372ae Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-12-31 12:14:24 -08:00
Chris Troutner e8a3234dcd Merge pull request #64 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): updating to v6.8.2
2021-12-31 12:13:13 -08:00
Chris Troutner fc717e0dcd fix(ipfs-coord): updating to v6.8.2 2021-12-31 12:11:47 -08:00
Chris Troutner 02512a8183 Automatically restarting wallet service 2021-12-30 07:52:22 -08:00
Chris Troutner 09a58a78ef Merge pull request #49 from Permissionless-Software-Foundation/ct-unstable
Synced with upstream ipfs-servicer-provider
2021-12-29 20:06:42 -08:00
Chris Troutner f4708d9a49 Synced with upstream ipfs-servicer-provider 2021-12-29 19:53:53 -08:00
Chris Troutner 18cec75f41 Merge pull request #63 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.8.1
2021-12-29 19:33:54 -08:00
Chris Troutner 7621842952 fix(ipfs-coord): Updating to v6.8.1 2021-12-29 19:32:39 -08:00
Chris Troutner 01da1b44da minor tweeks to docker files 2021-12-29 18:31:01 -08:00
Chris Troutner b8f262b01b feat(ipfs-service-provider): Syncing with upstream. Production uses go-ipfs 2021-12-29 18:17:35 -08:00
Chris Troutner 0e9a57a1da Merge pull request #62 from Permissionless-Software-Foundation/ct-unstable
Kicking off v2.0.0
2021-12-29 18:04:29 -08:00
Chris Troutner e374522725 fix(version): Bumping to v2.0.0 2021-12-29 18:03:09 -08:00
Chris Troutner e402f33132 Adding more properties to docker-compose 2021-12-29 18:00:17 -08:00
Chris Troutner e85655c0ec Adding data/ directory to gitignore 2021-12-29 17:46:52 -08:00
Chris Troutner 227ffbc4bc Removing data directory 2021-12-29 17:46:28 -08:00
Chris Troutner b41f819783 fix(startup): Exiting if server can't stop 2021-12-29 17:46:05 -08:00
Chris Troutner d6c3635c6a fix(ipfs): Got running with external IPFS node 2021-12-29 17:28:35 -08:00
Chris Troutner 37e98e4248 fix(ipfs): Switching from @chris.troutner/ipfs to ipfs v0.60.0 2021-12-29 16:59:32 -08:00
Chris Troutner d2f4369f8d Merge pull request #48 from Permissionless-Software-Foundation/ct-unstable
syncing upstream ipfs-service-provider
2021-12-24 17:16:17 -08:00
Chris Troutner bd33314c4f Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-12-24 17:14:26 -08:00
Chris Troutner e6941f7f7f Merge pull request #61 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-cood): Updating to v6.7.6
2021-12-24 17:10:49 -08:00
Chris Troutner 4fdf35a55f fix(ipfs-cood): Updating to v6.7.6 2021-12-24 17:07:54 -08:00
Chris Troutner e6441a9c8c Merge pull request #47 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-12-24 15:43:23 -08:00
Chris Troutner 8a3265bff2 Merge branch 'master' into ct-unstable 2021-12-24 15:34:30 -08:00
Chris Troutner d871d8b392 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-12-24 15:33:01 -08:00
Chris Troutner f1fbe34b58 Merge pull request #60 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.7.5
2021-12-24 15:26:04 -08:00
Chris Troutner d232b6404d fix(ipfs-coord): Updating to v6.7.5 2021-12-24 15:24:38 -08:00
Chris Troutner ea724f7ed8 Merge pull request #46 from Permissionless-Software-Foundation/samrock5000-patch-1
🚧 fix typo and add cd into scripts folder
2021-12-15 08:17:02 -08:00
Samuel Nevarez 2b04bae260 🚧 fix typo and add cd into scripts folder 2021-12-14 21:25:00 -07:00
Chris Troutner 84f1e25648 Adding example script for running locally 2021-12-10 15:30:42 -08:00
Chris Troutner ef8c6fbcec fix(errors): Giving more clues when errors happen 2021-12-10 15:20:03 -08:00
Chris Troutner 12d462b89d Merge pull request #45 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-12-06 12:52:16 -08:00
Chris Troutner 53065d8365 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-12-06 12:50:38 -08:00
Chris Troutner 1bf8f756e5 Merge pull request #59 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs): Deleting /blocks dir if it prevents app from starting
2021-12-06 12:48:48 -08:00
Chris Troutner 1e513cc133 fix(ipfs): Deleting /blocks dir if it prevents app from starting 2021-12-06 12:46:22 -08:00
Chris Troutner 7ce53439b1 Updating gitignore 2021-12-02 14:11:27 -08:00
Chris Troutner e90d664761 Merge pull request #44 from Permissionless-Software-Foundation/ct-unstable
Minor updates
2021-12-02 13:52:13 -08:00
Chris Troutner fc11e701e4 fix(broadcast): Handling full node errors 2021-12-02 13:51:07 -08:00
Chris Troutner 3c7ebef8a7 fix(bch-js): Updating to v4.20.28 2021-12-01 14:54:56 -08:00
Chris Troutner 5d70c89f2d Merge pull request #43 from Permissionless-Software-Foundation/ct-unstable
fix(garbage collection): Updating IPFS config for more conservative GC
2021-11-27 15:28:06 -08:00
Chris Troutner 7149c0a824 fix(upstream): Syncing with upstream ipfs-service-provider 2021-11-27 15:25:39 -08:00
Chris Troutner 74c6bc5737 Merge pull request #58 from Permissionless-Software-Foundation/ct-unstable
fix(garbage collection): Updating IPFS config for more conservative GC
2021-11-27 15:14:30 -08:00
Chris Troutner bac6c8b1e9 Disabling debug code 2021-11-27 15:13:23 -08:00
Chris Troutner 9e7d955bc4 fix(garbage collection): Updating IPFS config for more conservative GC 2021-11-27 15:12:08 -08:00
Chris Troutner af7c4464bb Merge pull request #42 from Permissionless-Software-Foundation/dh-pubkey
feat(pubkey): Added pubkey route to ipfs-bch-wallet-service
2021-11-25 06:10:16 -08:00
Chris Troutner cfb128f3c8 Updating deps 2021-11-25 06:04:35 -08:00
Daniel Gonzalez 451a828a05 feat(pubkey): Added pubkey route to ipfs-bch-wallet-service 2021-11-23 19:25:01 -04:00
Chris Troutner 678bc7015c Merge pull request #56 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.7.4
2021-11-13 11:36:57 -08:00
Chris Troutner 013aa97143 fix(ipfs-coord): Updating to v6.7.4 2021-11-13 11:33:28 -08:00
Chris Troutner 45b7e480b7 Merge pull request #55 from Permissionless-Software-Foundation/ct-unstable
fix(bch-js, ipfs-coord): Updating npm packages
2021-10-29 15:40:36 -07:00
Chris Troutner 09772bae29 fix(bch-js, ipfs-coord): Updating npm packages 2021-10-29 15:38:20 -07:00
Chris Troutner c01130fcc7 Updating ipfs-coord and bch-js 2021-10-27 14:33:17 -07:00
Chris Troutner 2d4159b4cf Merge pull request #41 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Increasing memory limit to 1GB
2021-10-12 13:39:37 -07:00
Chris Troutner 6dcd1ce5e7 fix(Docker): Increasing memory limit to 1GB 2021-10-12 13:37:31 -07:00
Chris Troutner 6c913b2c36 Merge pull request #40 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Using exact versions
2021-10-12 13:34:51 -07:00
Chris Troutner c453705a80 fix(dependencies): Using exact versions 2021-10-12 13:22:16 -07:00
Chris Troutner bb9a2a2408 Merge pull request #54 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Using exact versions
2021-10-12 12:46:51 -07:00
Chris Troutner 54709a8c70 fix(dependencies): Using exact versions 2021-10-12 09:56:52 -07:00
Chris Troutner 64135b55a7 fix(tests): Fixing broken unit test 2021-10-11 14:45:09 -07:00
Chris Troutner 1ff4ba440d fixing merge conflicts with upstream 2021-10-11 14:40:22 -07:00
Chris Troutner 72da6203a1 Merge pull request #53 from Permissionless-Software-Foundation/ct-unstable
fix(Dockerfile): Switching to more basic stuff
2021-10-11 14:34:03 -07:00
Chris Troutner e2bc560c7d fix(Dockerfile): Switching to more basic stuff 2021-10-11 13:48:20 -07:00
Chris Troutner e40241bac8 Fixing typo in docker-compose 2021-10-11 09:05:57 -07:00
Chris Troutner 01c8c5c194 Merge pull request #52 from Permissionless-Software-Foundation/ct-unstable
Additional test coverage
2021-10-01 14:11:44 -07:00
Chris Troutner 5eb5ef204e fix(json rpc): Increasing to 100% test coverage 2021-10-01 14:01:08 -07:00
Chris Troutner ee90bc0730 fix(ipfs): Got adapter back to 100% unit test coverage 2021-09-30 15:20:51 -07:00
Chris Troutner 5af068e0d6 fix(ipfs-coord): Got adapter back to 100% test coverage 2021-09-30 15:12:47 -07:00
Chris Troutner 7e228b729e fix(ipfs adapter): Adding unit tests for lock-file error handling 2021-09-30 14:47:17 -07:00
Chris Troutner ec4c61f38e Merge pull request #39 from Permissionless-Software-Foundation/ct-unstable
Syncing upstream: Improvements to Docker container
2021-09-29 07:20:47 -07:00
Chris Troutner 9ed610e3a4 fix(upstream): Synced with upstream ipfs-service-provider 2021-09-29 07:05:52 -07:00
Chris Troutner a9e7fc616e Merge pull request #51 from Permissionless-Software-Foundation/ct-unstable
fix(docker): disabling circuit relays by default
2021-09-28 20:30:45 -07:00
Chris Troutner 9d5ffbe26e fix(docker): disabling circuit relays by default 2021-09-28 20:11:25 -07:00
Chris Troutner 3829e90844 Merge pull request #50 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Matching ports to dev env
2021-09-28 19:55:58 -07:00
Chris Troutner f181d8b095 fix(docker): Matching ports to dev env 2021-09-28 19:52:10 -07:00
Chris Troutner a2270e70af Merge pull request #49 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Dropping RAM to 500MB
2021-09-28 18:18:26 -07:00
Chris Troutner 34604d53b0 fix(Docker): Dropping RAM to 500MB 2021-09-28 18:16:56 -07:00
Chris Troutner 6257b96bc3 fix(Docker): Forcing memory limit of 1GB 2021-09-28 18:14:18 -07:00
Chris Troutner 1d8912f60d Slight update to docker container 2021-09-28 18:04:52 -07:00
Chris Troutner 3c9b63d009 Merge pull request #48 from Permissionless-Software-Foundation/ct-unstable
fix(circuit relay): Auto-discover IP4 addr when CR enabled
2021-09-28 17:53:29 -07:00
Chris Troutner e6f9f64b4a fix(circuit relay): Auto-discover IP4 addr when CR enabled 2021-09-28 17:51:19 -07:00
Chris Troutner a8ad4149e0 fix(shell-scripts): Added shell-script dir with example scripts 2021-09-28 16:58:57 -07:00
Chris Troutner 3924812985 Merge pull request #47 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs): HOP setting is controlled by config.isCircuitRelay
2021-09-28 15:48:44 -07:00
Chris Troutner fef0f3a987 fix(ipfs): HOP setting is controlled by config.isCircuitRelay 2021-09-28 15:44:06 -07:00
Chris Troutner 1c012322fd Merge pull request #46 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Bumping to v6.7.0
2021-09-28 06:56:26 -07:00
Chris Troutner 545e8aa670 fix(ipfs-coord): Bumping to v6.7.0 2021-09-28 06:54:12 -07:00
Chris Troutner 449bd500c2 Merge pull request #38 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating bootstrap peers. v6.6.8
2021-09-27 12:52:00 -07:00
Chris Troutner ea295f2f41 linting 2021-09-27 12:47:10 -07:00
Chris Troutner 9175b8abe8 Fixing merge conflicts 2021-09-27 12:44:59 -07:00
Chris Troutner 9d4a61ea99 Merge pull request #45 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating bootstrap peers. v6.6.8
2021-09-27 12:40:53 -07:00
Chris Troutner cb50fdc70d fix(ipfs-coord): Updating bootstrap peers. v6.6.8 2021-09-27 12:39:10 -07:00
Chris Troutner cf488e1440 Merge pull request #37 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.6.7
2021-09-20 10:41:57 -07:00
Chris Troutner 4fc6def1cd Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-09-20 10:34:59 -07:00
Chris Troutner e0b2fd2525 Merge pull request #44 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.6.7
2021-09-20 10:21:12 -07:00
Chris Troutner 8e08201b16 fix(ipfs-coord): Updating to v6.6.7 2021-09-20 10:19:33 -07:00
Chris Troutner c347a2d99a Merge pull request #36 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-service-provider): Syncing with upstream repo
2021-09-18 11:37:16 -07:00
Chris Troutner 5b7d8d4db4 fix(ipfs-service-provider): Syncing with upstream repo 2021-09-18 11:34:23 -07:00
Chris Troutner dd0692e91f Merge pull request #43 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Bumping to v6.6.6
2021-09-18 11:23:26 -07:00
Chris Troutner 576da66194 fix(ipfs-coord): Bumping to v6.6.6 2021-09-18 11:20:11 -07:00
Chris Troutner f4851d6771 Merge pull request #42 from Permissionless-Software-Foundation/ct-unstable
Minor tweeks
2021-09-17 17:43:33 -07:00
Chris Troutner 96abb0d56e fix(ipfs-coord): Updating to v6.6.5 2021-09-17 17:41:08 -07:00
Chris Troutner fdf3141c91 fix(reset): Restarting app after 4 hours, not 8 2021-09-17 16:23:47 -07:00
Chris Troutner 6692d234da Adding link to video in readme 2021-09-17 16:23:04 -07:00
Chris Troutner b8655e31ca Fixing typo in shell script 2021-09-17 12:22:05 -07:00
Chris Troutner e118fe4d6e Merge pull request #41 from Permissionless-Software-Foundation/ct-unstable
fix(startup script): Added startup script
2021-09-17 11:20:39 -07:00
Chris Troutner 86283195c5 slight tweek to README 2021-09-17 11:18:26 -07:00
Chris Troutner a037646aca fix(startup script): Added startup script 2021-09-17 11:17:10 -07:00
Chris Troutner ae6bdcdd5f Merge pull request #35 from Permissionless-Software-Foundation/ct-unstable
fix(bch-js): Selecting custom server when not using JWT token
2021-09-08 14:02:25 -07:00
Chris Troutner 9fe822024c fix(bch-js): Selecting custom server when not using JWT token 2021-09-08 14:00:00 -07:00
Chris Troutner fc94041d17 Merge pull request #34 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Using Ubuntu base container
2021-09-08 13:05:58 -07:00
Chris Troutner a3f780b1f5 fix(docker): Using Ubuntu base container 2021-09-08 13:02:23 -07:00
Chris Troutner 9487f19233 Merge pull request #33 from Permissionless-Software-Foundation/ct-unstable
fix(JWT): Added env var to enable/disable JWT retrieval at startup
2021-09-08 12:38:05 -07:00
Chris Troutner 2988374769 linting 2021-09-08 12:35:26 -07:00
Chris Troutner 22ab7260f4 fix(startup): Fixing startup issues caused by code mixup with upstream 2021-09-08 12:35:00 -07:00
Chris Troutner 27f6f62f8c fix(gitignore): Adding run-dev.sh to gitignore 2021-09-08 12:03:46 -07:00
Chris Troutner 33ab787a95 Integrating JWT env var in production 2021-09-08 12:02:57 -07:00
Chris Troutner 4f2cde2599 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-09-08 12:00:41 -07:00
Chris Troutner d419084216 Merge pull request #40 from Permissionless-Software-Foundation/ct-unstable
fix(JWT): Added env var to enable/disable JWT retrieval at startup
2021-09-08 11:59:55 -07:00
Chris Troutner 553e0081fa fix(JWT): Added env var to enable/disable JWT retrieval at startup 2021-09-08 11:58:18 -07:00
Chris Troutner 0716922b7c Merge pull request #32 from Permissionless-Software-Foundation/ct-unstable
fix(memory-leak): Resetting app after 8 hours
2021-09-07 21:05:20 -07:00
Chris Troutner 7e227d994b Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-09-07 21:01:46 -07:00
Chris Troutner dd1b702966 Merge pull request #39 from Permissionless-Software-Foundation/ct-unstable
fix(memory-leak): Resetting app after 8 hours
2021-09-07 20:59:56 -07:00
Chris Troutner 0963f89049 fix(memory-leak): Resetting app after 8 hours 2021-09-07 20:58:23 -07:00
Chris Troutner cda3f1c0a7 Merge pull request #31 from Permissionless-Software-Foundation/ct-unstable
fix(JSON RPC): Adding filters and logging to JSON RPC router
2021-09-05 09:40:16 -07:00
Chris Troutner 1247bcb8c0 fix(upstream): Syncing with upstream ipfs-service-provider 2021-09-05 09:35:53 -07:00
Chris Troutner 36476b32ab Noting GitHub Issue 2021-09-05 09:23:38 -07:00
Chris Troutner 630135ac1c Merge pull request #37 from Permissionless-Software-Foundation/ct-unstable
fix(JSON RPC): Adding filters and logging to JSON RPC router
2021-09-05 08:45:51 -07:00
Chris Troutner 0a86c7dc92 fix(JSON RPC): Adding filters and logging to JSON RPC router 2021-09-05 08:31:06 -07:00
Chris Troutner a8a08f8978 Merge pull request #30 from Permissionless-Software-Foundation/ct-unstable
fix(JSON RPC): Prevening processing of duplicate entries
2021-09-04 18:18:23 -07:00
Chris Troutner 8b8d35573d fix(upstream): Syncing with upstream ipfs-service-provider 2021-09-04 18:07:28 -07:00
Chris Troutner 36ed80212d Merge pull request #36 from Permissionless-Software-Foundation/ct-unstable
fix(JSON RPC): Prevening processing of duplicate entries
2021-09-04 18:01:24 -07:00
Chris Troutner 131e6e1460 Updating ipfs-coord to v6.6.4 2021-09-04 17:59:53 -07:00
Chris Troutner 5c799a8197 fix(JSON RPC): Prevening processing of duplicate entries 2021-09-04 17:53:45 -07:00
Chris Troutner 488c5d3c22 fix(app): Exiting app if IPFS lock file is being held 2021-09-04 17:51:27 -07:00
Chris Troutner e93ffc4c77 Bumping version to 1.11.12 2021-09-04 15:25:52 -07:00
Chris Troutner e4c4e324b8 Merge pull request #29 from Permissionless-Software-Foundation/ct-unstable
fix(debug): Removing debug log spam
2021-09-04 09:20:09 -07:00
Chris Troutner e5e012a700 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-09-04 09:12:25 -07:00
Chris Troutner 9bddcf1c8e Merge pull request #35 from Permissionless-Software-Foundation/ct-unstable
fix(debug): Removing debug log spam
2021-09-04 09:09:26 -07:00
Chris Troutner ba2fdbc836 fix(debug): Removing debug log spam 2021-09-04 09:05:30 -07:00
Chris Troutner 3f809d38fb Merge pull request #28 from Permissionless-Software-Foundation/ct-unstable
fix(upstream): Syncing with upstream ipfs-service-provider
2021-09-04 08:46:39 -07:00
Chris Troutner d66d80bb0c fix(upstream): Syncing with upstream ipfs-service-provider 2021-09-04 08:43:41 -07:00
Chris Troutner 4c707cf5b9 Merge pull request #34 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.6.3
2021-09-04 08:39:37 -07:00
Chris Troutner 8670bdb588 fix(ipfs-coord): Updating to v6.6.3 2021-09-04 08:37:12 -07:00
Chris Troutner 4c5bdd089e Debugging relay metrics 2021-09-03 21:01:53 -07:00
Chris Troutner c3eb1b1ad3 Merge pull request #27 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Specifying max size for log files
2021-09-03 12:08:46 -07:00
Chris Troutner 1e1e1558b4 Adding data/ directory to gitignore 2021-09-03 12:07:00 -07:00
Chris Troutner d4abd693de fix(upstream): Syncing with upstream ipfs-service-provider 2021-09-03 12:01:45 -07:00
Chris Troutner d38718dcdf Merge pull request #33 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Specifying max size for log files
2021-09-03 11:29:37 -07:00
Chris Troutner 3a3376c303 fix(docker): Specifying max size for log files 2021-09-03 11:27:27 -07:00
Chris Troutner 05043ac74d fix(ipfs-coord): Upgrading to v6.6.0 2021-09-03 11:05:52 -07:00
Chris Troutner 5f89bfcbd8 Merge pull request #26 from Permissionless-Software-Foundation/ct-unstable
fix(sync): Synced with upstream ipfs-service-provider
2021-09-02 17:15:13 -07:00
Chris Troutner d7d56d9ebf fix(sync): Synced with upstream ipfs-service-provider 2021-09-02 17:12:11 -07:00
Chris Troutner 1592eadd8c fix(sync): Syncing with upstream ipfs-service-provider 2021-09-02 17:09:32 -07:00
Chris Troutner be1a4c750a Merge pull request #32 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updated to v6.5.6
2021-09-02 16:54:32 -07:00
Chris Troutner 4572ce3d6b fix(ipfs-coord): Updated to v6.5.6 2021-09-02 16:52:39 -07:00
Chris Troutner fb7d4e6074 Merge pull request #31 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs): Updating IPFS nad ipfs-coord
2021-09-02 09:06:27 -07:00
Chris Troutner 5467c991de Merge branch 'master' into ct-unstable 2021-09-02 09:04:25 -07:00
Chris Troutner ba93c6cc46 fix(ipfs): Updating IPFS nad ipfs-coord 2021-09-02 09:03:16 -07:00
Chris Troutner 60b37e4f72 Merge pull request #25 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.5.2
2021-08-30 08:02:58 -07:00
Chris Troutner 02a543323c Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-08-30 08:00:24 -07:00
Chris Troutner c28bc22084 Merge pull request #30 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.5.2
2021-08-30 07:56:29 -07:00
Chris Troutner f796dd6076 fix(ipfs-coord): Updating to v6.5.2 2021-08-30 07:51:44 -07:00
Chris Troutner 5d624f5c23 Merge pull request #24 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.5.1
2021-08-29 20:47:02 -07:00
Chris Troutner 3eacfb27a6 Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-08-29 20:45:05 -07:00
Chris Troutner 29b3d32743 Slight modification to Docker container 2021-08-29 20:44:45 -07:00
Chris Troutner a58e237122 Merge pull request #29 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.5.1
2021-08-29 20:39:48 -07:00
Chris Troutner c237b33677 fix(ipfs-coord): Updating to v6.5.1 2021-08-29 20:37:11 -07:00
Chris Troutner b48b618d4c Merge pull request #23 from Permissionless-Software-Foundation/ct-unstable
fix(upstream): Synced with upstream ipfs-service-provider
2021-08-29 16:48:00 -07:00
Chris Troutner 252834d727 Updating package-lock.json 2021-08-29 16:45:17 -07:00
Chris Troutner 04bcd9fd3a fix(upstream): Synced with upstream ipfs-service-provider 2021-08-29 16:34:03 -07:00
Chris Troutner cc5aba7896 Merge pull request #28 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v6.5.0
2021-08-29 16:24:04 -07:00
Chris Troutner 50bc5c2d02 fix(ipfs-coord): Updating to v6.5.0 2021-08-29 16:16:45 -07:00
Chris Troutner 3251b0dc58 fix(production): changing directories for permission issues 2021-08-28 17:45:28 -07:00
Chris Troutner 090f524b9d Merge pull request #27 from Permissionless-Software-Foundation/ct-unstable
fix(docker-compose): Opening up IPFS ports
2021-08-28 17:31:40 -07:00
Chris Troutner 1846b5da64 fix(docker-compose): Opening up IPFS ports 2021-08-28 17:29:21 -07:00
Chris Troutner 643dfd8fc0 Merge pull request #22 from Permissionless-Software-Foundation/ct-unstable
fix(upstream): Synced with upstream ipfs-service-provider
2021-08-28 07:56:40 -07:00
Chris Troutner 944d721296 fix(e2e): Fixed manual consumer test 2021-08-28 07:38:44 -07:00
Chris Troutner 96e4afd6c8 fix(upstream): Synced with upstream ipfs-service-provider 2021-08-27 16:21:17 -07:00
Chris Troutner 002e6657ff Merge pull request #26 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updated to v6.4.0
2021-08-27 15:43:16 -07:00
Chris Troutner fb215b11b7 fix(production): Tweeking production Docker container slightly 2021-08-27 15:41:33 -07:00
Chris Troutner 1618289078 fix(ipfs-coord): Updated to v6.4.0 2021-08-27 15:04:09 -07:00
Chris Troutner 2ebe42d5f4 Merge pull request #25 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Upgrading to v6.3.0
2021-08-26 21:27:13 -07:00
Chris Troutner 326271f703 Updating Dockerfile 2021-08-26 21:24:27 -07:00
Chris Troutner 0480f54287 fix(ipfs-coord): Upgrading to v6.3.0 2021-08-26 21:23:37 -07:00
Chris Troutner f9df8c7fab fix(production): Running Docker as root 2021-08-26 10:53:53 -07:00
Chris Troutner 2ae550c027 Merge pull request #24 from Permissionless-Software-Foundation/ct-unstable
fix(production): Updating Docker container
2021-08-26 10:29:01 -07:00
Chris Troutner eca131fefc minor comments to startup script 2021-08-26 10:27:22 -07:00
Chris Troutner 596645ad6b Bumping to ipfs-coord v6.1.8 2021-08-26 10:17:11 -07:00
Chris Troutner 2a2d940e7c fix(startup): Adding startup and env var settings 2021-08-26 09:21:08 -07:00
Chris Troutner 46b0c595f9 fix(production): Updating Docker container 2021-08-26 08:54:33 -07:00
Chris Troutner eab7a30926 Merge pull request #21 from Permissionless-Software-Foundation/ct-unstable
fix(psf-bch-wallet): Got working with psf-bch-wallet and ipfs-coord v6
2021-08-24 16:05:04 -07:00
Chris Troutner 85a8efb5bf fix(psf-bch-wallet): Got working with psf-bch-wallet and ipfs-coord v6 2021-08-24 16:03:17 -07:00
Chris Troutner e33ee49879 Merge pull request #20 from Permissionless-Software-Foundation/ct-unstable
fix(upstream): Synced with upstream repo ipfs-service-provider
2021-08-24 11:01:09 -07:00
Chris Troutner 9c53204a91 fix(upstream): Synced with upstream repo ipfs-service-provider 2021-08-24 10:59:39 -07:00
Chris Troutner 6faf1ccf86 Merge branch 'master' into ct-unstable 2021-08-24 10:58:21 -07:00
Chris Troutner 8fafe96e01 Merge pull request #23 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Bumping to v6.1.4
2021-08-24 10:53:32 -07:00
Chris Troutner d06c995174 fix(ipfs-coord): Bumping to v6.1.4 2021-08-24 10:51:58 -07:00
Chris Troutner 2d02904ed1 fix(ipfs-coord): Bumped to v6.1.3 2021-08-24 10:44:25 -07:00
Chris Troutner 51d7ddb362 Merge pull request #22 from Permissionless-Software-Foundation/ct-unstable
fix(node-fetch): Adding node-fetch as dependency, which was preventin…
2021-08-24 10:28:51 -07:00
Chris Troutner ee1fbad02a Fixing broken test 2021-08-24 10:26:46 -07:00
Chris Troutner f5ae98cb9c fix(node-fetch): Adding node-fetch as dependency, which was preventing install on some machines 2021-08-24 10:23:19 -07:00
Chris Troutner e416478522 Explicitly adding node-pre-gyp 2021-08-24 07:54:04 -07:00
Chris Troutner ce85dffc97 Adding node-fetch as a dep 2021-08-24 07:31:52 -07:00
Chris Troutner c9f7a43339 fix(Docker): integrating changes into production Docker container 2021-08-24 07:27:10 -07:00
Chris Troutner a885fb7edf Merge pull request #19 from Permissionless-Software-Foundation/ct-unstable
fix(version): Bumping to v1.11.0 for wallet consumer
2021-08-23 17:16:23 -07:00
Chris Troutner 93d1542522 fix(version): Bumping to v1.11.0 for wallet consumer 2021-08-23 17:12:49 -07:00
Chris Troutner 62fadbb394 Merge pull request #18 from Permissionless-Software-Foundation/ct-unstable
feat(upstream): Synced with upstream ipfs-service-provider
2021-08-23 17:08:35 -07:00
Chris Troutner ae37b6533b fix(upstream): Synced with upstream ipfs-service-provider 2021-08-23 17:06:20 -07:00
Chris Troutner c711fd0ce1 Merge pull request #21 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-cood): Bumping to v6.1.2
2021-08-23 16:38:06 -07:00
Chris Troutner 05af23b87c Merge branch 'master' into ct-unstable 2021-08-23 16:16:48 -07:00
Chris Troutner 54b505449b fix(ipfs-cood): Bumping to v6.1.2 2021-08-23 16:13:05 -07:00
Chris Troutner 8e5f5f2dbd debugging 2021-08-23 15:51:10 -07:00
Chris Troutner c06a9ec874 debugging 2021-08-23 15:36:33 -07:00
Chris Troutner 8639a3d363 Removing if statement 2021-08-23 15:32:31 -07:00
Chris Troutner a9ef1ebd66 using new code for responding to JSON RPC commands 2021-08-23 15:30:13 -07:00
Chris Troutner 1053191835 fix(orbit): Repairing router for handling orbitdb private message 2021-08-23 15:25:56 -07:00
Chris Troutner 7d0b536f73 fix(test): Removing test that broke with new version of ipfs-coord 2021-08-23 15:17:12 -07:00
Chris Troutner cf45a1fc7e fix(ipfs-coord): Bumped to v6.1.1 2021-08-23 15:14:25 -07:00
Chris Troutner cc2ada5169 Merge pull request #17 from Permissionless-Software-Foundation/dh-manual-tests
feat(tests): Added manual e2e tests
2021-08-20 07:12:33 -07:00
Chris Troutner cf4029ff00 Merge pull request #20 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs ports): Adding configurable ports use env vars
2021-08-19 08:04:24 -07:00
Chris Troutner 76e4feb1ac fix(ipfs ports): Adding configurable ports use env vars 2021-08-19 08:01:23 -07:00
Chris Troutner 4a5103d760 Adding note to README to fix install bug 2021-08-19 07:56:55 -07:00
Daniel Gonzalez 0b72895102 feat(tests): Added manual e2e tests 2021-08-18 01:10:03 -04:00
Chris Troutner f41cac9fc7 Merge pull request #16 from Permissionless-Software-Foundation/ct-unstable
fix(broadcast): Fixing bug in broadcast JSON RPC
2021-08-15 09:07:09 -07:00
Chris Troutner 8ad1400d3c fix(error reporting): Adding JSON RPC error reporting 2021-08-15 08:32:39 -07:00
Chris Troutner e48a9213c5 fix(broadcast): Fixing bug in broadcast JSON RPC 2021-08-13 16:15:44 -07:00
Chris Troutner 60e6a8b24f Merge pull request #19 from Permissionless-Software-Foundation/ct-unstable
Heavy refactoring and relocation of directories.
2021-08-08 11:19:24 -07:00
Chris Troutner 85af08b1aa Ran npm audit fix. Zero vulns 2021-08-08 11:14:00 -07:00
Chris Troutner 2d4bbd9ab0 Updated to ipfs-coord v5 2021-08-08 11:12:25 -07:00
Chris Troutner 06631a81ad perf(directories): Moving IPFS and OribitDB data to a .ipfsdata directory 2021-08-08 10:48:26 -07:00
Chris Troutner 24684ac25a feat(server): Converter top-level server library into a class 2021-08-08 09:58:24 -07:00
Chris Troutner 758de6b088 Got unit tests passing again 2021-08-08 08:09:48 -07:00
Chris Troutner 0346898501 feat(adapters): Refactored the adapters into a class 2021-08-08 07:38:47 -07:00
Chris Troutner 2e2d092b18 Merge pull request #15 from Permissionless-Software-Foundation/ct-unstable
fix(protocol): Adding protocol field to announceJsonLd
2021-08-05 17:18:31 -07:00
Chris Troutner c8aefae0cc fix(protocol): Adding protocol property to announceJsonLd 2021-08-05 17:16:37 -07:00
Chris Troutner 17e465b3ab Merge branch 'master' of https://github.com/Permissionless-Software-Foundation/ipfs-service-provider into ct-unstable 2021-08-05 17:14:40 -07:00
Chris Troutner 40bb75bf33 Merge pull request #18 from Permissionless-Software-Foundation/ct-unstable
fix(protocol): Adding protocol field to announceJsonLd
2021-08-05 17:11:00 -07:00
Chris Troutner 02201afc59 fix(protocol): Adding protocol field to announceJsonLd 2021-08-05 17:08:56 -07:00
Chris Troutner bae98bba28 Merge pull request #14 from Permissionless-Software-Foundation/ct-unstable
feat(about): Adding npm version to JSON RPC About endpoint output
2021-08-03 13:13:25 -07:00
Chris Troutner 0eb7aeaed1 feat(version): Adding npm version to ipfs-coord announce payload 2021-08-03 13:12:02 -07:00
Chris Troutner dbd5022c4c Merge pull request #17 from Permissionless-Software-Foundation/ct-unstable
feat(about): Adding npm version to JSON RPC About endpoint output
2021-08-03 13:07:57 -07:00
Chris Troutner 72ac73c410 feat(about): Adding npm version to JSON RPC About endpoint output 2021-08-03 13:05:45 -07:00
Chris Troutner 9b52c81b25 Adding startup script to gitignore 2021-08-03 12:53:35 -07:00
Chris Troutner 7cc13b9ba9 Adding todo in comments 2021-07-31 16:07:47 -07:00
Chris Troutner 3ba866d2d6 Merge pull request #13 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2021-07-31 15:57:18 -07:00
Chris Troutner 3d058d9164 fix(ipfs-service-provider): Synced with upstream 2021-07-31 15:55:47 -07:00
Chris Troutner fde8b16fef Merge pull request #16 from Permissionless-Software-Foundation/dh-required
fix(users): Using the users entity in the use cases
2021-07-31 15:41:25 -07:00
Daniel Gonzalez c5a1eb6f81 fix(users): Using the users entity in the use cases 2021-07-31 15:00:38 -04:00
Chris Troutner 74f8b60472 Adding link to API documentation 2021-07-28 13:28:53 -07:00
Chris Troutner 53846762f0 Merge pull request #12 from Permissionless-Software-Foundation/dh-improve-documentation
feat(documentation): Improved ipfs-bch-wallet-service documentation
2021-07-28 13:25:13 -07:00
Daniel Gonzalez 788d5ba4ee feat(documentation): Improved ipfs-bch-wallet-service documentation 2021-07-26 21:00:24 -04:00
Chris Troutner d57085949c Merge pull request #15 from Permissionless-Software-Foundation/ct-unstable
Removing comments
2021-07-25 17:31:48 -07:00
Chris Troutner 9dc40a417a Removing comments 2021-07-25 17:30:15 -07:00
Chris Troutner 81e5592b81 Merge pull request #14 from Permissionless-Software-Foundation/ct-unstable
Converting wlogger and Controller libraries to classes
2021-07-25 16:51:30 -07:00
Chris Troutner 44867f0173 fix(controllers): Made Controllers library a class 2021-07-25 16:49:01 -07:00
Chris Troutner c46f7357c3 fix(wlogger): Refactored into Class for better unit test control 2021-07-25 16:34:56 -07:00
Chris Troutner 47b8dce966 Adding link to YouTube video in README. 2021-07-21 15:10:05 -07:00
Chris Troutner 63b08d1acb Merge pull request #11 from Permissionless-Software-Foundation/ct-unstable
feat(test): Added e2e test simulating a consumer of JSON RPC
2021-07-18 15:51:22 -07:00
Chris Troutner fa05fcf3d4 feat(test): Added e2e test simulating a consumer of JSON RPC 2021-07-18 15:46:32 -07:00
Chris Troutner f9846e95fd Created client scheme for JSON RPC 2021-07-18 08:09:27 -07:00
Chris Troutner def4f9003c Got simulated client to send a JSON RPC command 2021-07-17 19:51:56 -07:00
Chris Troutner 06cdc03287 Got client to connect to service 2021-07-17 19:14:11 -07:00
Chris Troutner c3bfbbb6e1 Merge pull request #10 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Setting name with an env var
2021-07-17 16:22:51 -07:00
Chris Troutner c7ed9eb3fd fix(ipfs-coord): Setting name with an env var 2021-07-17 16:19:03 -07:00
Chris Troutner a023202703 Adding debug log for mongodb connection string 2021-07-17 11:33:17 -07:00
Chris Troutner e31dceb07f Merge pull request #9 from Permissionless-Software-Foundation/ct-unstable
fix(production): Adjusting production settings
2021-07-17 11:25:38 -07:00
Chris Troutner af0e727ba8 fix(production): Fixed merge conflicts 2021-07-17 11:24:00 -07:00
Chris Troutner 6f64fc4652 fix(production): Adjusting production settings 2 2021-07-17 11:16:57 -07:00
Chris Troutner e91dd7f834 feat(production): Adjusting production settings 2021-07-17 20:16:19 +02:00
Chris Troutner e717124fc7 Merge pull request #8 from Permissionless-Software-Foundation/ct-unstable
fix(production): Updated Docker container
2021-07-17 10:55:48 -07:00
Chris Troutner 3c8d2cfdd3 fix(production): Updated Docker container 2021-07-17 10:54:00 -07:00
Chris Troutner 71fbebe672 Merge pull request #7 from Permissionless-Software-Foundation/ct-unstable
feat(JWT): Added automatic JWT handling for FullStack.cash
2021-07-17 10:08:00 -07:00
Chris Troutner cab819081a Got everything passing and working 2021-07-17 10:06:29 -07:00
Chris Troutner 4f0adbb773 Updated to ipfs-coord v4.0.1 2021-07-17 09:12:37 -07:00
Chris Troutner e04cb1f05a Got all tests passing again 2021-07-17 08:15:02 -07:00
Chris Troutner 6f619db666 Updated unit tests 2021-07-16 18:51:38 -07:00
Chris Troutner 126bee86bd feat(JWT): Added automatic JWT handling for FullStack.cash 2021-07-16 17:26:51 -07:00
Chris Troutner 3761d139f1 Merge pull request #6 from Permissionless-Software-Foundation/ct-unstable
fix(endpoints): Tested endpoints, fixed some bugs and docs
2021-07-16 15:27:55 -07:00
Chris Troutner 006727cc9d fix(bch-js): Updating bch-js to v4.20.2 2021-07-16 15:26:21 -07:00
Chris Troutner bcd2a54aa7 fix(endpoints): Tested endpoints, fixed some bugs and docs 2021-07-16 15:19:03 -07:00
66 changed files with 17498 additions and 25263 deletions
+5
View File
@@ -7,6 +7,7 @@
#logs
logs/*.json
*.log
*.log.*
npm-debug.log*
# Runtime data
@@ -64,6 +65,10 @@ database/
system-user-*.json
orbitdb
ipfsdata
.ipfsdata
ipfs-service-provider.sh
start-bch-wallet-service.sh
data/
run-dev.sh
!README.md
+44 -3
View File
@@ -4,6 +4,9 @@
This is a censorship-resistant, IPFS-based microservice that provides access for wallets to access the Bitcoin Cash (BCH) blockchain. It leverages [bch-js](https://github.com/Permissionless-Software-Foundation/bch-js).
- [Decentralized Blockchain Service Providers](https://youtu.be/m_33rRXEats) YouTube video demos this software.
- [JSON RPC and REST API Documentation](https://ipfs-bch-wallet-service.fullstack.cash/)
## About This Repository
This repository is forked from the [ipfs-service-provider](https://github.com/Permissionless-Software-Foundation/ipfs-service-provider) repository. That code has been customized to provide BCH blockchain access for wallets. This server-side node.js app provides both REST API over HTTP and JSON RPC over IPFS endpoints for wallets to access the blockchain through.
@@ -21,18 +24,54 @@ This repository is one step in a longer path. Here are the major milestones of t
## Requirements
- node **^14.17.0**
- npm **^7.13.0**
- node **^14.18.2**
- npm **^8.3.0**
- Docker **^20.10.8**
- Docker Compose **^1.27.4**
## Installation
### Development Environment
**Note:** This software now uses an external go-ipfs IPFS node. The instructions below have not been updated to reflect this.
A development environment will allow you modify the code on-the-fly and contribute to the code base of this repository. [PM2](https://www.npmjs.com/package/pm2) is recommended for running this code base as an IPFS Circuit Relay.
- [Video: Installing ipfs-service-provider](https://youtu.be/Z0NsboIVN44)
- [Step-by-step installation instructions](https://gist.github.com/christroutner/3304a71d4c12a3a3e1664a438f64d9d0)
```bash
git clone https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service
cd ipfs-bch-wallet-service
./install-mongo.sh
npm install
npm start
cd shell-scripts
./ipfs-bch-wallet-service.sh
```
### Production Environment
The [docker](./production/docker) directory contains a Dockerfile for building a production deployment.
```
docker-compose build --no-cache
docker-compose up -d
```
- Bring the containers up once, then take them back down with `docker-compose down`.
- Copy the [swarm.key](./swarm.key) file to `ipfs-service-provider/production/data/go-ipfs/data/swarm.key`.
- Bring the containers back up with `docker-compose up -d`.
### Operation Notes
- There is a memory leak in the version of js-ipfs. The app is currently configured to shut down every 8 hours to flush memory. It relies on a process manager like pm2, Docker, or systemd to restart the app after it shuts down, in order to ensure continuous operation.
- The PSF network operates as a private network. It does not connect or interact with the wider PSF network, relying instead on gateways to bridge the two networks, when they need to share content. This improves the performance and experience for everyone in the PSF network. To join the network, you'll need to add the [swarm.key](./swarm.key) file to the IPFS data folder.
- [Instructions on setting up IPFS private networks.](https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#private-networks)
- For external installations, the swarm.key file will typically go in `~/.ipfs/swarm.key`
- For production Docker containers, the key would go in `ipfs-service-provider/production/data/go-ipfs/data/swarm.key`
## Structure
The file layout of this repository differs from the koa-api-boilerplate. Instead, it follows the file layout of [Clean Architecture](troutsblog.com/blog/clean-architecture).
@@ -74,3 +113,5 @@ Snapshots pinned to IPFS will be listed here.
## License
[MIT](./LICENSE.md)
a
+90 -49
View File
@@ -1,3 +1,12 @@
/*
This Koa server has two interfaces:
- REST API over HTTP
- JSON RPC over IPFS
The architecture of the code follows the Clean Architecture pattern:
https://troutsblog.com/blog/clean-architecture
*/
// npm libraries
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
@@ -12,72 +21,104 @@ const cors = require('kcors')
// Local libraries
const config = require('../config') // this first.
// const IPFSLib = require('../src/lib/ipfs')
const AdminLib = require('../src/adapters/admin')
const adminLib = new AdminLib()
// const JSONRPC = require('../src/rpc')
// const rpc = new JSONRPC()
const errorMiddleware = require('../src/controllers/rest-api/middleware/error')
const { wlogger } = require('../src/adapters/wlogger')
async function startServer () {
// Create a Koa instance.
const app = new Koa()
app.keys = [config.session]
class Server {
constructor () {
this.adminLib = new AdminLib()
}
// Connect to the Mongo Database.
mongoose.Promise = global.Promise
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
await mongoose.connect(config.database, {
useUnifiedTopology: true,
useNewUrlParser: true
})
async startServer () {
try {
// Create a Koa instance.
const app = new Koa()
app.keys = [config.session]
// MIDDLEWARE START
// Connect to the Mongo Database.
mongoose.Promise = global.Promise
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
console.log(
`Connecting to MongoDB with this connection string: ${config.database}`
)
await mongoose.connect(config.database, {
useUnifiedTopology: true,
useNewUrlParser: true
})
app.use(convert(logger()))
app.use(bodyParser())
app.use(session())
app.use(errorMiddleware())
console.log(`Starting environment: ${config.env}`)
console.log(`Debug level: ${config.debugLevel}`)
// Used to generate the docs.
app.use(mount('/', serve(`${process.cwd()}/docs`)))
// MIDDLEWARE START
// Mount the page for displaying logs.
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
app.use(convert(logger()))
app.use(bodyParser())
app.use(session())
app.use(errorMiddleware())
// User Authentication
require('../config/passport')
app.use(passport.initialize())
app.use(passport.session())
// Used to generate the docs.
app.use(mount('/', serve(`${process.cwd()}/docs`)))
// Attach REST API and JSON RPC controllers to the app.
const controllers = require('../src/controllers')
controllers.attachControllers(app)
// Mount the page for displaying logs.
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
// Enable CORS for testing
// THIS IS A SECURITY RISK. COMMENT OUT FOR PRODUCTION
app.use(cors({ origin: '*' }))
// User Authentication
require('../config/passport')
app.use(passport.initialize())
app.use(passport.session())
// MIDDLEWARE END
// Enable CORS for testing
// THIS IS A SECURITY RISK. COMMENT OUT FOR PRODUCTION
// Dev Note: This line must come BEFORE controllers.attachRESTControllers()
app.use(cors({ origin: '*' }))
console.log(`Running server in environment: ${config.env}`)
wlogger.info(`Running server in environment: ${config.env}`)
// Attach REST API and JSON RPC controllers to the app.
const Controllers = require('../src/controllers')
const controllers = new Controllers()
await controllers.attachRESTControllers(app)
await app.listen(config.port)
console.log(`Server started on ${config.port}`)
app.controllers = controllers
// Create the system admin user.
const success = await adminLib.createSystemUser()
if (success) console.log('System admin user created.')
// MIDDLEWARE END
return app
console.log(`Running server in environment: ${config.env}`)
wlogger.info(`Running server in environment: ${config.env}`)
await app.listen(config.port)
console.log(`Server started on ${config.port}`)
// Create the system admin user.
try {
const success = await this.adminLib.createSystemUser()
if (success) console.log('System admin user created.')
} catch (err) {
console.warn(
'Error trying to create system admin. Perhaps one already exists?'
)
}
// Attach the other IPFS controllers.
// Skip if this is a test environment.
if (config.env !== 'test') {
await controllers.attachControllers(app)
}
return app
} catch (err) {
console.error('Could not start server. Error: ', err)
console.log(
'Exiting after 5 seconds. Depending on process manager to restart.'
)
await sleep(5000)
process.exit(1)
}
}
}
// startServer()
// export default app
// module.exports = app
module.exports = {
startServer
function sleep (ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
module.exports = Server
-15
View File
@@ -1,15 +0,0 @@
/*
This file should be customized for your app. The string in this file is
displayed when a user makes the 'about' JSON RPC call.
*/
module.exports = `
This is the about string for the ipfs-service-provider repository:
https://github.com/Permissionless-Software-Foundation/ipfs-service-provider
Brought to you by the Permissionless Software Foundation:
https://PSFoundation.cash
Documentation:
https://ipfs-service-provider.fullstack.cash/
`
+50 -3
View File
@@ -5,6 +5,16 @@
/* eslint no-unneeded-ternary:0 */
// Get the version from the package.json file.
const pkgInfo = require('../../package.json')
const version = pkgInfo.version
const ipfsCoordName = process.env.COORD_NAME
? process.env.COORD_NAME
: 'ipfs-bch-wallet-service'
console.log('GET_JWT_AT_STARTUP: ', process.env.GET_JWT_AT_STARTUP)
module.exports = {
// Configure TCP port.
port: process.env.PORT || 5001,
@@ -23,17 +33,38 @@ module.exports = {
? process.env.EMAILPASS
: 'emailpassword',
// FullStack.cash account information, used for automatic JWT handling.
getJwtAtStartup: process.env.GET_JWT_AT_STARTUP ? true : false,
authServer: process.env.AUTHSERVER
? process.env.AUTHSERVER
: 'https://auth.fullstack.cash',
apiServer: process.env.APISERVER
? process.env.APISERVER
: 'https://api.fullstack.cash/v5/',
fullstackLogin: process.env.FULLSTACKLOGIN
? process.env.FULLSTACKLOGIN
: 'demo@demo.com',
fullstackPassword: process.env.FULLSTACKPASS
? process.env.FULLSTACKPASS
: 'demo',
// IPFS settings.
isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false,
// SSL domain used for websocket connection via browsers.
crDomain: process.env.CR_DOMAIN ? process.env.CR_DOMAIN : '',
// Information passed to other IPFS peers about this node.
apiInfo: 'https://ipfs-service-provider.fullstack.cash/',
apiInfo: 'https://ipfs-bch-wallet-service.fullstack.cash/',
ipfsCoordName: ipfsCoordName,
// JSON-LD and Schema.org schema with info about this app.
announceJsonLd: {
'@context': 'https://schema.org/',
'@type': 'WebAPI',
name: 'ipfs-bch-wallet-service',
name: ipfsCoordName,
version,
protocol: 'bch-wallet',
description:
'IPFS service providing BCH blockchain access needed by a wallet.',
documentation: 'https://ipfs-bch-wallet-service.fullstack.cash/',
@@ -42,5 +73,21 @@ module.exports = {
name: 'Permissionless Software Foundation',
url: 'https://PSFoundation.cash'
}
}
},
// IPFS Ports
ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 5668,
ipfsWsPort: process.env.IPFS_WS_PORT ? process.env.IPFS_WS_PORT : 5669,
// BCH Mnemonic for generating encryption keys and payment address
mnemonic: process.env.MNEMONIC ? process.env.MNEMONIC : '',
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 2,
// Settings for production, using external go-ipfs node.
isProduction: process.env.SVC_ENV === 'production' ? true : false,
ipfsHost: process.env.IPFS_HOST ? process.env.IPFS_HOST : 'localhost',
ipfsApiPort: process.env.IPFS_API_PORT
? parseInt(process.env.IPFS_API_PORT)
: 5001
}
+1 -1
View File
@@ -7,6 +7,6 @@
module.exports = {
session: 'secret-boilerplate-token',
token: 'secret-jwt-token',
database: 'mongodb://localhost:27017/ipfs-service-dev',
database: 'mongodb://localhost:27017/bch-service-dev',
env: 'dev'
}
+3 -1
View File
@@ -10,6 +10,8 @@
module.exports = {
session: 'secret-boilerplate-token',
token: 'secret-jwt-token',
database: 'mongodb://172.17.0.1:5555/ipfs-service-prod',
database: process.env.DBURL
? process.env.DBURL
: 'mongodb://172.17.0.1:5555/bch-service-prod',
env: 'prod'
}
+1 -1
View File
@@ -7,6 +7,6 @@
module.exports = {
session: 'secret-boilerplate-token',
token: 'secret-jwt-token',
database: 'mongodb://localhost:27017/ipfs-service-test',
database: 'mongodb://localhost:27017/bch-service-test',
env: 'test'
}
-1
View File
@@ -1 +0,0 @@
This is where the mongodb docker container stores its db files.
-25
View File
@@ -1,25 +0,0 @@
# Start the testnet server with the command 'docker-compose up -d'
koa-mongodb:
image: mongo
container_name: mongo-koa
ports:
- "5555:27017" # <host port>:<container port>
volumes:
- ./database:/data/db
command: mongod --smallfiles --logpath=/dev/null # -- quiet
restart: always
koa:
build: ./production/
dockerfile: Dockerfile
container_name: koa
links:
- koa-mongodb
ports:
- "5001:5001" # <host port>:<container port>
volumes:
# - ./logs:/home/coinjoin/consolidating-coinjoin/logs
- ./keys:/home/safeuser/keys
restart: always
+2 -1
View File
@@ -1,3 +1,4 @@
const server = require('./bin/server.js')
const Server = require('./bin/server.js')
const server = new Server()
server.startServer()
+14097 -24773
View File
File diff suppressed because it is too large Load Diff
+48 -42
View File
@@ -1,6 +1,6 @@
{
"name": "ipfs-bch-wallet-service",
"version": "1.0.0",
"version": "2.0.0",
"description": "IPFS and REST service providing blockchain access needed by a wallet. ",
"main": "index.js",
"scripts": {
@@ -8,7 +8,8 @@
"test": "npm run test:all",
"test:all": "export SVC_ENV=test && nyc --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/",
"test:unit": "export SVC_ENV=test && mocha --exit --timeout 15000 --recursive test/unit/",
"test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 15000 test/e2e/automated/",
"test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 30000 test/e2e/automated/",
"test:integration": "export SVC_ENV=test && mocha --timeout 30000 --recursive test/integration/",
"test:temp": "export SVC_ENV=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
"lint": "standard --env mocha --fix",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
@@ -23,49 +24,54 @@
},
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
"dependencies": {
"@psf/bch-js": "^4.20.1",
"axios": "^0.21.1",
"bcryptjs": "^2.4.3",
"glob": "^7.1.6",
"ipfs": "^0.54.4",
"ipfs-coord": "^3.2.0",
"jsonrpc-lite": "^2.2.0",
"jsonwebtoken": "^8.5.1",
"kcors": "^2.2.2",
"koa": "^2.13.1",
"koa-bodyparser": "^4.3.0",
"koa-convert": "^2.0.0",
"koa-generic-session": "^2.1.1",
"koa-logger": "^3.2.1",
"koa-mount": "^4.0.0",
"koa-passport": "^4.1.3",
"koa-router": "^10.0.0",
"koa-static": "^5.0.0",
"koa2-ratelimit": "^0.9.0",
"line-reader": "^0.4.0",
"mongoose": "^5.11.15",
"nodemailer": "^6.4.17",
"passport-local": "^1.0.0",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.0"
"@psf/bch-js": "5.3.2",
"axios": "0.25.0",
"bcryptjs": "2.4.3",
"glob": "7.1.6",
"ipfs": "0.60.0",
"ipfs-coord": "7.1.3",
"ipfs-http-client": "55.0.0",
"jsonrpc-lite": "2.2.0",
"jsonwebtoken": "8.5.1",
"jwt-bch-lib": "1.3.0",
"kcors": "2.2.2",
"koa": "2.13.1",
"koa-bodyparser": "4.3.0",
"koa-convert": "2.0.0",
"koa-generic-session": "2.1.1",
"koa-logger": "3.2.1",
"koa-mount": "4.0.0",
"koa-passport": "4.1.3",
"koa-router": "10.0.0",
"koa-static": "5.0.0",
"koa2-ratelimit": "0.9.1",
"line-reader": "0.4.0",
"mongoose": "5.11.15",
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
"nodemailer": "6.4.17",
"passport-local": "1.0.0",
"public-ip": "4.0.4",
"winston": "3.3.3",
"winston-daily-rotate-file": "4.5.0"
},
"devDependencies": {
"apidoc": "^0.26.0",
"chai": "^4.3.0",
"coveralls": "^3.1.0",
"apidoc": "0.26.0",
"chai": "4.3.0",
"coveralls": "3.1.0",
"eslint": "7.19.0",
"eslint-config-prettier": "^7.2.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-standard": "^4.0.0",
"husky": "^4.3.8",
"mocha": "^8.2.1",
"nyc": "^15.1.0",
"semantic-release": "^17.4.4",
"sinon": "^9.2.4",
"standard": "^16.0.3",
"uuid": "^8.3.2"
"eslint-config-prettier": "7.2.0",
"eslint-config-standard": "16.0.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-standard": "4.0.0",
"husky": "4.3.8",
"lodash.clonedeep": "^4.5.0",
"mocha": "8.2.1",
"nyc": "15.1.0",
"semantic-release": "17.4.4",
"sinon": "9.2.4",
"standard": "16.0.3",
"uuid": "8.3.2"
},
"release": {
"publish": [
-58
View File
@@ -1,58 +0,0 @@
# Create a Dockerized API server
#
#IMAGE BUILD COMMANDS
# ct-base-ubuntu = ubuntu 18.04 + nodejs v10 LTS
FROM christroutner/ct-base-ubuntu
MAINTAINER Chris Troutner <chris.troutner@gmail.com>
#Create the user 'safeuser' and add them to the sudo group.
#RUN useradd -ms /bin/bash safeuser
#RUN adduser safeuser sudo
#Set password to 'password' change value below if you want a different password
#RUN echo safeuser:password | chpasswd
#Set the working directory to be the home directory
WORKDIR /home/safeuser
#Setup NPM for non-root global install
#RUN mkdir /home/safeuser/.npm-global
#RUN chown -R safeuser .npm-global
#RUN echo "export PATH=~/.npm-global/bin:$PATH" >> /home/safeuser/.profile
#RUN runuser -l safeuser -c "npm config set prefix '~/.npm-global'"
# Switch to user account.
USER safeuser
# Prep 'sudo' commands.
RUN echo 'abcd8765' | sudo -S pwd
# Clone the rest.bitcoin.com repository
WORKDIR /home/safeuser
RUN git clone https://github.com/christroutner/koa-api-boilerplate
RUN mv koa-api-boilerplate koa
RUN mkdir keys
# Switch to the desired branch. `master` is usually stable,
# and `stage` has the most up-to-date changes.
WORKDIR /home/safeuser/koa
# For development: switch to unstable branch
# RUN git checkout unstable
# Install dependencies
RUN npm install
# Generate the API docs
RUN npm run docs
VOLUME /home/safeuser/keys
# Expose the port the API will be served on.
EXPOSE 5001
# Start the application.
COPY start-production start-production
CMD ["./start-production"]
#CMD ["npm", "start"]
+1
View File
@@ -0,0 +1 @@
COMPOSE_PROJECT_NAME=bch-wallet-service
+79
View File
@@ -0,0 +1,79 @@
# Create a Dockerized API server
#
#IMAGE BUILD COMMANDS
FROM ubuntu:20.04
MAINTAINER Chris Troutner <chris.troutner@gmail.com>
#Update the OS and install any OS packages needed.
RUN apt-get update
RUN apt-get install -y sudo git curl nano gnupg wget
#Install Node and NPM
RUN curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh
RUN apt-get install -y nodejs build-essential
#Create the user 'safeuser' and add them to the sudo group.
RUN useradd -ms /bin/bash safeuser
RUN adduser safeuser sudo
#Set password to 'password' change value below if you want a different password
RUN echo safeuser:password | chpasswd
#Set the working directory to be the home directory
WORKDIR /home/safeuser
#Setup NPM for non-root global install
RUN mkdir /home/safeuser/.npm-global
RUN chown -R safeuser .npm-global
RUN echo "export PATH=~/.npm-global/bin:$PATH" >> /home/safeuser/.profile
RUN runuser -l safeuser -c "npm config set prefix '~/.npm-global'"
# Update to the latest version of npm.
# Working with npm@7.21.1
RUN npm install -g npm
# Update to the latest version of npm.
#RUN npm install -g npm@7.23.0
RUN npm install -g npm
# npm mirror to prevent direct dependency on npm.
RUN npm set registry http://94.130.170.209:4873/
# Switch to user account.
#USER safeuser
# Prep 'sudo' commands.
#RUN echo 'abcd8765' | sudo -S pwd
# Clone the repository
WORKDIR /home/safeuser
RUN git clone https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service
# Switch to the desired branch. `master` is usually stable,
# and `stage` has the most up-to-date changes.
WORKDIR /home/safeuser/ipfs-bch-wallet-service
# For development: switch to unstable branch
RUN git checkout ct-unstable
# Install dependencies
#RUN npm install -g @mapbox/node-pre-gyp
RUN npm install
# Generate the API docs
RUN npm run docs
# Calling out the directorys that should be mounted as external volumes.
RUN mkdir /home/safeuser/.ipfsdata
#RUN mkdir /home/safeuser/orbitdb
#VOLUME /home/safeuser/ipfsdata
#VOLUME /home/safeuser/orbitdb
EXPOSE 5010
# Start the application.
COPY start-production.sh start-production.sh
CMD ["./start-production.sh"]
#CMD ["npm", "start"]
+61
View File
@@ -0,0 +1,61 @@
# Docker Containers
The 'production' environment is assumed to be a set of Docker containers orchestrated with Docker Compose. The files in this directory will stand up three Docker containers:
1 An instance of go-ipfs.
2 An instance of MongoDB.
3 The JavaScript software in this repository.
The software in this repository depends on the first two containers, so if they aren't running correctly, the application won't run correctly either.
## IPFS
IPFS can be a little tricky to set up. By default, the container uses the following ports:
- 4001 for TCP connections, exposed publicly.
- 5001 for control by the application, exposed privately.
- 8080 for an IPFS gateway, consumed by the application, exposed privately.
If you already have an IPFS node running on a the computer, you will need to change the ports to avaid a conflict. To change the ports from the default, you'll need to perform a series of steps, and the order of the steps matter.
1. Edit the `docker-compose.yml` file and change the ports. Then save the file. Here is an example:
```
ports:
- 4101:4101
- 172.17.0.1:5101:5101
- 172.17.0.1:8180:8180
```
2. Bring the Docker containers up, and then back down. This will allow the IPFS container to create the config file that you'll need to edit.
- `docker-compose up -d`
- Wait a few seconds.
- `docker-compose down`
3. Update the generated config file at `../data/go-ipfs/data/config`, to update the ports in the config file, like this:
```
"Addresses": {
"API": "/ip4/0.0.0.0/tcp/5101",
"Announce": [],
"AppendAnnounce": [],
"Gateway": "/ip4/0.0.0.0/tcp/8180",
"NoAnnounce": [],
"Swarm": [
"/ip4/0.0.0.0/tcp/4101",
"/ip6/::/tcp/4101",
"/ip4/0.0.0.0/udp/4101/quic",
"/ip6/::/udp/4101/quic"
]
},
```
4. Update the port changes in the `start-production.sh` shell script. This tells the application which ports to use, in order to control the IPFS node, are are used when signaling other nodes.
5. Quickly rebuild the containers, to add the modified `start-production.sh` shell script to the application Docker container:
- `docker-compose build`
6. Now start the containers, and the port changes to IPFS should be complete.
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Remove all untagged docker images.
docker rmi $(docker images | grep "^<none>" | awk '{print $3}')
+61
View File
@@ -0,0 +1,61 @@
# Start the service with the command 'docker-compose up -d'
version: '3.9'
services:
mongo-bch-service:
image: mongo
container_name: mongo-bch-service
ports:
- '5555:27017' # <host port>:<container port>
volumes:
- ../data/mongodb:/data/db
command: mongod --logpath=/dev/null # -- quiet
restart: always
ipfs-bch-wallet:
image: ipfs/go-ipfs:v0.11.0
container_name: ipfs-bch-wallet
environment:
MY_ENV_VAR: 'placeholder'
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '10'
mem_limit: 2000mb
ports:
- 4001:4001
- 172.17.0.1:5001:5001
- 172.17.0.1:8080:8080
volumes:
- ../data/go-ipfs/data:/data/ipfs
- ../data/go-ipfs/export:/export
# https://docs.docker.com/compose/compose-file/compose-file-v3/#command
# https://github.com/ipfs/go-ipfs/blob/91c52657166bcf86f2476926e4fe56694dc26562/Dockerfile#L115
command:
[
'daemon',
'--migrate=true',
'--agent-version-suffix=docker',
'--enable-pubsub-experiment'
]
restart: always
bch-wallet-service:
build: ./
container_name: bch-wallet-service
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '10'
mem_limit: 1000mb
links:
- mongo-bch-service
- ipfs-bch-wallet
ports:
- '5010:5010' # <host port>:<container port>
volumes:
- ../data/ipfsdata:/home/safeuser/ipfs-bch-wallet-service/.ipfsdata
restart: always
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
# BEGIN: Optional configuration settings
# This mnemonic is used to set up persistent public key for e2ee
# Replace this with your own 12-word mnemonic.
# You can get one at https://wallet.fullstack.cash.
export MNEMONIC="olive two muscle bottom coral ancient wait legend bronze useful process session"
# The human readable name this IPFS node identifies as.
export COORD_NAME=bch-wallet-service-generic
# Allow this node to function as a circuit relay. It must not be behind a firewall.
#export ENABLE_CIRCUIT_RELAY=1
# For browsers to use your circuit realy, you must set up a domain, SSL certificate,
# and you must forward that subdomain to the IPFS_WS_PORT.
#export CR_DOMAIN=subdomain.yourdomain.com
# Debug level. 0 = minimal info. 2 = max info.
export DEBUG_LEVEL=2
# BCH Wallet Service Settings
# Change APISERVER to point to your own installation of bch-api
export APISERVER=https://api.fullstack.cash/v5/
# These settings are used to proxy a subscription to FullStack.cash.
export GET_JWT_AT_STARTUP=1
export AUTHSERVER=https://auth.fullstack.cash
export FULLSTACKLOGIN=demo@demo.com
export FULLSTACKPASS=demo
# END: Optional configuration settings
# Production database connection string.
export DBURL=mongodb://172.17.0.1:5555/ipfs-service-prod
# Configure REST API port
export PORT=5010
# Production settings using external go-ipfs node.
export SVC_ENV=production
export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001
export IPFS_TCP_PORT=4001
#export IPFS_WS_PORT=4002
npm start
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
export KOA_ENV=production
npm start
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
# This script is an example for running a generic ipfs-service-provider instance
# using a local installation of bch-api.
# Ports
export PORT=5002 # REST API port
export IPFS_TCP_PORT=5268
export IPFS_WS_PORT=5269
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-service-provider-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=1
# MongoDB connection string.
#export DBURL=mongodb://localhost:27017/bch-service-dev
# Customize these environment variables for your own installation.
export GET_JWT_AT_STARTUP=0
export APISERVER=http://localhost:3000/v5/
npm start
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# This script is an example for running a generic ipfs-service-provider instance.
# Ports
export PORT=5002 # REST API port
export IPFS_TCP_PORT=5268
export IPFS_WS_PORT=5269
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-service-provider-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=1
# MongoDB connection string.
#export DBURL=mongodb://localhost:27017/bch-service-dev
npm start
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# This script is an example for running a generic ipfs-service-provider instance.
# Ports
export PORT=5001 # REST API port
export IPFS_TCP_PORT=5268
export IPFS_WS_PORT=5269
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-service-provider-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=1
# MongoDB connection string.
#export DBURL=mongodb://localhost:27017/bch-service-dev
npm start
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# This script is an example for running a ipfs-service-provider as a Circuit Relay.
# Circuit Relays are help other nodes on the network communicate. They are
# critical for reliable functioning of the network, and for circumventing
# censorship.
# Ports
export PORT=5001 # REST API port
export IPFS_TCP_PORT=5268
export IPFS_WS_PORT=5269
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-service-provider-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=1
# MongoDB connection string.
#export DBURL=mongodb://localhost:27017/bch-service-dev
# Comment to disable circuit relay functionality. Or set to 1 to enable.
export ENABLE_CIRCUIT_RELAY=1
# For browsers to use your circuit realy, you must set up a domain, SSL certificate,
# and you must forward that subdomain to the IPFS_WS_PORT.
#export CR_DOMAIN=subdomain.yourdomain.com
npm start
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# This script is an example for running a production environment, which is
# defined by running an external go-ipfs node.
# Ports
export PORT=5010 # REST API port
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-bch-service-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=2
# Production settings that use external IPFS node.
# https://github.com/christroutner/docker-ipfs
export SVC_ENV=production
export IPFS_HOST=localhost
#export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001
# Configure IPFS ports
export IPFS_TCP_PORT=4001
#export IPFS_WS_PORT=5269
# MongoDB connection string.
export DBURL=mongodb://localhost:27017/ipfs-service-dev
export ENABLE_CIRCUIT_RELAY=true
npm start
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
# This script is an example for running a production environment, which is
# defined by running an external go-ipfs node.
# Ports
export PORT=5010 # REST API port
# The human-readible name that is used when displaying data about this node.
export COORD_NAME=ipfs-service-provider-generic
# This is used for end-to-end encryption (e2ee).
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=2
# Production settings that use external IPFS node.
# https://github.com/christroutner/docker-ipfs
export SVC_ENV=production
#export IPFS_HOST=localhost
export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001
# Configure IPFS ports
export IPFS_TCP_PORT=4001
#export IPFS_WS_PORT=5269
# MongoDB connection string.
export DBURL=mongodb://localhost:27017/ipfs-service-dev
npm start
+101
View File
@@ -0,0 +1,101 @@
/*
A library of utility functions for working with FullStack.cash JWT tokens.
Feel free to copy this library into your own app, as well as the unit tests
for this file.
*/
const JwtLib = require('jwt-bch-lib')
const BCHJS = require('@psf/bch-js')
class FullStackJWT {
constructor (localConfig = {}) {
// Input Validation
this.authServer = localConfig.authServer
if (!this.authServer || typeof this.authServer !== 'string') {
throw new Error(
'Must pass a url for the AUTH server when instantiating FullStackJWT class.'
)
}
this.apiServer = localConfig.apiServer
if (!this.apiServer || typeof this.apiServer !== 'string') {
throw new Error(
'Must pass a url for the API server when instantiating FullStackJWT class.'
)
}
this.login = localConfig.fullstackLogin
if (!this.login || typeof this.login !== 'string') {
throw new Error(
'Must pass a FullStack.cash login (email) instantiating FullStackJWT class.'
)
}
this.password = localConfig.fullstackPassword
if (!this.password || typeof this.password !== 'string') {
throw new Error(
'Must pass a FullStack.cash account password when instantiating FullStackJWT class.'
)
}
// Encapsulate dependencies
this.jwtLib = new JwtLib({
// Overwrite default values with the values in the config file.
server: this.authServer,
login: this.login,
password: this.password
})
// State
this.apiToken = '' // Default value.
this.bchjs = {}
}
// Get's a JWT token from FullStack.cash.
async getJWT () {
try {
// Log into the auth server.
await this.jwtLib.register()
this.apiToken = this.jwtLib.userData.apiToken
if (!this.apiToken) {
throw new Error('This account does not have a JWT')
}
console.log(`Retrieved JWT token: ${this.apiToken}\n`)
// Ensure the JWT token is valid to use.
const isValid = await this.jwtLib.validateApiToken()
// Get a new token with the same API level, if the existing token is not
// valid (probably expired).
if (!isValid.isValid) {
this.apiToken = await this.jwtLib.getApiToken(
this.jwtLib.userData.apiLevel
)
console.log(
`The JWT token was not valid. Retrieved new JWT token: ${this.apiToken}\n`
)
} else {
console.log('JWT token is valid.\n')
}
return this.apiToken
} catch (err) {
console.error(
`Error trying to log into ${this.server} and retrieve JWT token.`
)
throw err
}
}
// Create an instance of bchjs with the validated JWT token. Returns this
// instance of bch-js.
instanceBchjs () {
this.bchjs = new BCHJS({
restURL: this.apiServer,
apiToken: this.apiToken
})
return this.bchjs
}
}
module.exports = FullStackJWT
+48 -16
View File
@@ -4,29 +4,61 @@
https://troutsblog.com/blog/clean-architecture
*/
// Public NPM libraries
const BCHJS = require('@psf/bch-js')
// Load individual adapter libraries.
const IPFSAdapter = require('./ipfs')
const LocalDB = require('./localdb')
const LogsAPI = require('./logapi')
const Passport = require('./passport')
const Nodemailer = require('./nodemailer')
const { wlogger } = require('./wlogger')
// const { wlogger } = require('./wlogger')
const JSONFiles = require('./json-files')
const FullStackJWT = require('./fullstack-jwt')
// Instantiate adapter libraries.
const ipfs = new IPFSAdapter()
const localdb = new LocalDB()
const logapi = new LogsAPI()
const passport = new Passport()
const nodemailer = new Nodemailer()
const jsonFiles = new JSONFiles()
const config = require('../../config')
module.exports = {
ipfs,
localdb,
logapi,
passport,
nodemailer,
wlogger,
jsonFiles
class Adapters {
constructor (localConfig = {}) {
// Encapsulate dependencies
this.config = config
this.ipfs = new IPFSAdapter()
this.localdb = new LocalDB()
this.logapi = new LogsAPI()
this.passport = new Passport()
this.nodemailer = new Nodemailer()
this.jsonFiles = new JSONFiles()
this.bchjs = new BCHJS({ restURL: this.config.apiServer })
// Get a valid JWT API key and instance bch-js.
this.fullStackJwt = new FullStackJWT(config)
}
async start () {
try {
if (this.config.getJwtAtStartup) {
// Get a JWT token and instantiate bch-js with it. Then pass that instance
// to all the rest of the apps controllers and adapters.
await this.fullStackJwt.getJWT()
// Instantiate bch-js with the JWT token, and overwrite the placeholder for bch-js.
this.bchjs = await this.fullStackJwt.instanceBchjs()
} else {
// console.log(
// `Initializing bchjs with this restURL: ${this.config.apiServer}`
// )
this.bchjs = new BCHJS({ restURL: this.config.apiServer })
}
if (this.config.env !== 'test') {
// Start the IPFS node.
await this.ipfs.start({ bchjs: this.bchjs })
}
} catch (err) {
console.error('Error in adapters/index.js/start()')
throw err
}
}
}
module.exports = Adapters
+19 -2
View File
@@ -10,6 +10,7 @@ class IPFS {
// Encapsulate dependencies
this.ipfsAdapter = new IpfsAdapter()
this.IpfsCoordAdapter = IpfsCoordAdapter
this.process = process
this.ipfsCoordAdapter = {} // placeholder
@@ -19,8 +20,15 @@ class IPFS {
// Provides a global start() function that triggers the start() function in
// the underlying libraries.
async start () {
async start (localConfig = {}) {
try {
const bchjs = localConfig.bchjs
if (!bchjs) {
throw new Error(
'Instance of bch-js must be passed when instantiating IPFS adapter.'
)
}
// Start IPFS
await this.ipfsAdapter.start()
console.log('IPFS is ready.')
@@ -30,7 +38,8 @@ class IPFS {
// Start ipfs-coord
this.ipfsCoordAdapter = new this.IpfsCoordAdapter({
ipfs: this.ipfs
ipfs: this.ipfs,
bchjs
})
await this.ipfsCoordAdapter.start()
console.log('ipfs-coord is ready.')
@@ -38,6 +47,14 @@ class IPFS {
return true
} catch (err) {
console.error('Error in adapters/ipfs/index.js/start()')
// If error is due to a lock file issue. Kill the process, so that
// Docker or pm2 has a chance to restart the service.
if (err.message.includes('Lock already being held')) {
console.log('lock being held. Exiting.')
this.process.exit(1)
}
throw err
}
}
+43 -8
View File
@@ -6,7 +6,8 @@
// Global npm libraries
const IpfsCoord = require('ipfs-coord')
const BCHJS = require('@psf/bch-js')
// const BCHJS = require('@psf/bch-js')
const publicIp = require('public-ip')
// Local libraries
const config = require('../../../config')
@@ -23,13 +24,19 @@ class IpfsCoordAdapter {
'Instance of IPFS must be passed when instantiating ipfs-coord.'
)
}
this.bchjs = localConfig.bchjs
if (!this.bchjs) {
throw new Error(
'Instance of bch-js must be passed when instantiating ipfs-coord.'
)
}
// Encapsulate dependencies
this.IpfsCoord = IpfsCoord
this.ipfsCoord = {}
this.bchjs = new BCHJS()
// this.rpc = new JSONRPC()
this.config = config
this.publicIp = publicIp
// Properties of this class instance.
this.isReady = false
@@ -37,20 +44,48 @@ class IpfsCoordAdapter {
_this = this
}
async start () {
this.ipfsCoord = new this.IpfsCoord({
async start (localConfig = {}) {
const circuitRelayInfo = {}
// If configured as a Circuit Relay, get the public IP addresses for this node.
if (this.config.isCircuitRelay) {
try {
const ip4 = await this.publicIp.v4()
// const ip6 = await publicIp.v6()
circuitRelayInfo.ip4 = ip4
circuitRelayInfo.tcpPort = this.config.ipfsTcpPort
// Domain used by browser-based secure websocket connections.
circuitRelayInfo.crDomain = this.config.crDomain
} catch (err) {
/* exit quietly */
}
}
const ipfsCoordOptions = {
ipfs: this.ipfs,
type: 'node.js',
// type: 'browser',
bchjs: this.bchjs,
privateLog: console.log, // Default to console.log
isCircuitRelay: this.config.isCircuitRelay,
circuitRelayInfo,
apiInfo: this.config.apiInfo,
announceJsonLd: this.config.announceJsonLd
})
announceJsonLd: this.config.announceJsonLd,
mnemonic: this.config.mnemonic,
debugLevel: this.config.debugLevel
}
// Production env uses external go-ipfs node.
if (this.config.isProduction) {
ipfsCoordOptions.nodeType = 'external'
}
this.ipfsCoord = new this.IpfsCoord(ipfsCoordOptions)
// Wait for the ipfs-coord library to signal that it is ready.
await this.ipfsCoord.isReady()
await this.ipfsCoord.start({ type: 'node.js' })
// Signal that this adapter is ready.
this.isReady = true
@@ -63,7 +98,7 @@ class IpfsCoordAdapter {
attachRPCRouter (router) {
try {
_this.ipfsCoord.privateLog = router
_this.ipfsCoord.ipfs.orbitdb.privateLog = router
_this.ipfsCoord.adapters.pubsub.privateLog = router
} catch (err) {
console.error('Error in attachRPCRouter()')
throw err
+76 -15
View File
@@ -2,36 +2,54 @@
Clean Architecture Adapter for IPFS.
This library deals with IPFS so that the apps business logic doesn't need
to have any specific knowledge of the js-ipfs library.
TODO: Add the external IP address to the list of multiaddrs advertised by
this node. See this GitHub Issue for details:
https://github.com/Permissionless-Software-Foundation/ipfs-service-provider/issues/38
*/
// Global npm libraries
const IPFS = require('ipfs')
// const IPFS = require('ipfs')
// const IPFS = require('@chris.troutner/ipfs')
const IPFSembedded = require('ipfs')
const IPFSexternal = require('ipfs-http-client')
const fs = require('fs')
const http = require('http')
// Local libraries
const config = require('../../../config')
const IPFS_DIR = './.ipfsdata/ipfs'
class IpfsAdapter {
constructor (localConfig) {
// Encapsulate dependencies
this.IPFS = IPFS
this.config = config
// Choose the IPFS constructor based on the config settings.
this.IPFS = IPFSembedded // default
if (this.config.isProduction) {
this.IPFS = IPFSexternal
}
// Properties of this class instance.
this.isReady = false
this.config = config
this.fs = fs
}
// Start an IPFS node.
async start () {
try {
// Ipfs Options
const ipfsOptions = {
repo: './ipfsdata',
const ipfsOptionsEmbedded = {
repo: IPFS_DIR,
start: true,
config: {
relay: {
enabled: true, // enable circuit relay dialer and listener
hop: {
enabled: true // enable circuit relay HOP (make this node a relay)
enabled: config.isCircuitRelay // enable circuit relay HOP (make this node a relay)
}
},
pubsub: true, // enable pubsub
@@ -46,25 +64,35 @@ class IpfsAdapter {
`/ip4/0.0.0.0/tcp/${this.config.ipfsTcpPort}`,
`/ip4/0.0.0.0/tcp/${this.config.ipfsWsPort}/ws`
]
},
Datastore: {
StorageMax: '2GB',
StorageGCWatermark: 50,
GCPeriod: '15m'
}
}
}
const ipfsOptionsExternal = {
host: this.config.ipfsHost,
port: this.config.ipfsApiPort,
agent: http.Agent({ keepAlive: true, maxSockets: 2000 })
}
let ipfsOptions = ipfsOptionsEmbedded
if (this.config.isProduction) {
ipfsOptions = ipfsOptionsExternal
}
// Create a new IPFS node.
this.ipfs = await this.IPFS.create(ipfsOptions)
// Set the 'server' profile so the node does not scan private networks.
await this.ipfs.config.profiles.apply('server')
// const nodeConfig = await this.ipfs.config.getAll()
// console.log(
// `IPFS node configuration: ${JSON.stringify(nodeConfig, null, 2)}`
// )
// Stop the IPFS node if we're running tests.
if (this.config.env === 'test') {
await this.ipfs.stop()
}
// Debugging: Display IPFS config settings.
// const configSettings = await this.ipfs.config.getAll()
// console.log(`configSettings: ${JSON.stringify(configSettings, null, 2)}`)
// Signal that this adapter is ready.
this.isReady = true
@@ -72,6 +100,39 @@ class IpfsAdapter {
return this.ipfs
} catch (err) {
console.error('Error in ipfs.js/start()')
// If IPFS crashes because the /blocks directory is full, wipe the directory.
if (err.message.includes('No space left on device')) {
console.log('No space left in /blocks folder. Deleting blocks folder.')
this.rmBlocksDir()
}
throw err
}
}
async stop () {
await this.ipfs.stop()
return true
}
// Remove the '/blocks' directory that is used to store IPFS data.
// Dev Note: It's assumed this node is not pinning any data and that
// everything in this directory is transient. This folder will regularly
// fill up and prevent IPFS from starting.
rmBlocksDir () {
try {
const dir = `${IPFS_DIR}/blocks`
console.log(`Deleting ${dir} directory...`)
this.fs.rmdirSync(dir, { recursive: true })
console.log(`${dir} directory is deleted!`)
return true // Signal successful execution.
} catch (err) {
console.log('Error in rmBlocksDir()')
throw err
}
}
+54 -44
View File
@@ -11,52 +11,62 @@ require('winston-daily-rotate-file')
const config = require('../../config')
// Configure daily-rotation transport.
const transport = new winston.transports.DailyRotateFile({
filename: `${__dirname.toString()}/../../logs/koa-${config.env}-%DATE%.log`,
datePattern: 'YYYY-MM-DD',
zippedArchive: false,
maxSize: '1m', // 1 megabyte
maxFiles: '5d', // 5 days
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
)
})
class Wlogger {
constructor (localConfig = {}) {
this.config = config
transport.on('rotate', notifyRotation)
function notifyRotation (oldFilename, newFilename) {
wlogger.info('Rotating log files')
}
// This controls what goes into the log FILES
const wlogger = winston.createLogger({
level: 'verbose',
format: winston.format.json(),
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
// new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
// new winston.transports.File({ filename: 'logs/combined.log' })
transport
]
})
function outputToConsole () {
wlogger.add(
new winston.transports.Console({
format: winston.format.simple(),
level: 'info'
// Configure daily-rotation transport.
this.transport = new winston.transports.DailyRotateFile({
filename: `${__dirname.toString()}/../../logs/koa-${
this.config.env
}-%DATE%.log`,
datePattern: 'YYYY-MM-DD',
zippedArchive: false,
maxSize: '1m', // 1 megabyte
maxFiles: '5d', // 5 days
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
)
})
)
this.transport.on('rotate', this.notifyRotation)
// This controls what goes into the log FILES
this.wlogger = winston.createLogger({
level: 'verbose',
format: winston.format.json(),
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
// new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
// new winston.transports.File({ filename: 'logs/combined.log' })
this.transport
]
})
}
notifyRotation (oldFilename, newFilename) {
this.wlogger.info('Rotating log files')
}
outputToConsole () {
this.wlogger.add(
new winston.transports.Console({
format: winston.format.simple(),
level: 'info'
})
)
}
}
// This controls the logs to CONSOLE
// if (config.env !== 'test') {
// outputToConsole()
// }
const logger = new Wlogger()
module.exports = { wlogger, notifyRotation, outputToConsole }
// Allow the logger to write to the console.
logger.outputToConsole()
const wlogger = logger.wlogger
module.exports = { wlogger, Wlogger }
+38 -29
View File
@@ -7,46 +7,55 @@
// Public npm libraries.
// Load the Clean Architecture Adapters library
const adapters = require('../adapters')
const Adapters = require('../adapters')
// Load the JSON RPC Controller.
const JSONRPC = require('./json-rpc')
// Load the Clean Architecture Use Case libraries.
const UseCases = require('../use-cases')
const useCases = new UseCases({ adapters })
// const useCases = new UseCases({ adapters })
// Load the REST API Controllers.
const RESTControllers = require('./rest-api')
// Top-level function for this library.
// Start the various Controllers and attach them to the app.
async function attachControllers (app) {
// Attach the REST controllers to the Koa app.
attachRESTControllers(app)
class Controllers {
constructor (localConfig = {}) {
this.adapters = new Adapters()
this.useCases = new UseCases({ adapters: this.adapters })
}
// Start IPFS.
await adapters.ipfs.start()
async attachControllers (app) {
// Wait for any startup processes to complete for the Adapters libraries.
await this.adapters.start()
attachRPCControllers()
this.attachRPCControllers()
}
// Top-level function for this library.
// Start the various Controllers and attach them to the app.
attachRESTControllers (app) {
const restControllers = new RESTControllers({
adapters: this.adapters,
useCases: this.useCases
})
// Attach the REST API Controllers associated with the boilerplate code to the Koa app.
restControllers.attachRESTControllers(app)
}
// Add the JSON RPC router to the ipfs-coord adapter.
attachRPCControllers () {
const jsonRpcController = new JSONRPC({
adapters: this.adapters,
useCases: this.useCases
})
// Attach the input of the JSON RPC router to the output of ipfs-coord.
this.adapters.ipfs.ipfsCoordAdapter.attachRPCRouter(
jsonRpcController.router
)
}
}
function attachRESTControllers (app) {
const rESTControllers = new RESTControllers({
adapters,
useCases
})
// Attach the REST API Controllers associated with the boilerplate code to the Koa app.
rESTControllers.attachRESTControllers(app)
}
// Add the JSON RPC router to the ipfs-coord adapter.
function attachRPCControllers () {
const jsonRpcController = new JSONRPC({ adapters, useCases })
// Attach the input of the JSON RPC router to the output of ipfs-coord.
adapters.ipfs.ipfsCoordAdapter.attachRPCRouter(jsonRpcController.router)
}
module.exports = { attachControllers }
module.exports = Controllers
+8 -2
View File
@@ -1,12 +1,15 @@
/*
This is the JSON RPC router for the users API
CT 3/5/22: This library can probably be deleted. Handling of the /about endpoint
is now directly controlled by the ipfs-coord library.
*/
// Public npm libraries
const jsonrpc = require('jsonrpc-lite')
// Local libraries
const aboutStr = require('../../../../config/about')
const config = require('../../../../config')
class AboutRPC {
constructor (localConfig) {
@@ -33,10 +36,13 @@ class AboutRPC {
// This is a bit different than other router libraries, because there is
// only one response, which is a string about this node.
async aboutRouter (rpcData) {
console.log('debugging: aboutRouter from ipfs-service-provider triggered')
return {
success: true,
status: 200,
message: aboutStr,
// message: aboutStr,
message: JSON.stringify(config.announceJsonLd),
endpoint: 'about'
}
}
+382 -43
View File
@@ -4,7 +4,7 @@
// Public npm libraries
const jsonrpc = require('jsonrpc-lite')
const BCHJS = require('@psf/bch-js')
// const BCHJS = require('@psf/bch-js')
// Local libraries
// const UserLib = require('../../../use-cases/user')
@@ -32,7 +32,7 @@ class BCHRPC {
this.jsonrpc = jsonrpc
this.validators = new Validators(localConfig)
this.rateLimit = new RateLimit()
this.bchjs = new BCHJS()
this.bchjs = this.adapters.bchjs
}
// Top-level router for this library. All other methods in this class are for
@@ -48,9 +48,9 @@ class BCHRPC {
// Route the call based on the value of the method property.
switch (endpoint) {
case 'transactions':
case 'txHistory':
await this.rateLimit.limiter(rpcData.from)
return await this.transactions(rpcData)
return await this.txHistory(rpcData)
case 'balance':
await this.rateLimit.limiter(rpcData.from)
@@ -64,9 +64,13 @@ class BCHRPC {
await this.rateLimit.limiter(rpcData.from)
return await this.broadcast(rpcData)
case 'transaction':
case 'txData':
await this.rateLimit.limiter(rpcData.from)
return await this.transaction(rpcData)
return await this.txData(rpcData)
case 'pubkey':
await this.rateLimit.limiter(rpcData.from)
return await this.pubKey(rpcData)
}
} catch (err) {
console.error('Error in BCHRPC/rpcRouter()')
@@ -82,31 +86,70 @@ class BCHRPC {
}
/**
* @api {JSON} /bch Transactions
* @api {JSON} /bch TX History
* @apiPermission public
* @apiName Transactions
* @apiName txHistory
* @apiGroup JSON BCH
* @apiDescription This endpoint wraps the bchjs.Electrumx.transactions([]) function.
* It returns the transaction history for an address. This list of TXIDs is
* sorted and paginated.
*
* There are three possible inputs:
* - address: (required) the address to query for a transaction history
* - sortOrder: (optional) will sort results in 'DECENDING' (default) or 'ASCENDING' order.
* - page: (optional) will return a 'page' of 100 results. Default is 0
*
* Given the 'address' property this endpoint returns an object with the following properties
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - method: "" - Method used in the petition
* - receiver: "" - Receiver address
* - value: {} - Final result value of the petition
* - success : - Petition status
* - txs : [] - Transactions of the provided address
* - height : - Reference to the blockchain size
* - tx_hash: "" - Hash of the transaction
* - address : "" - Address asociated to the transactions
* - status: - HTTP Status Code
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "transactions", "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"]}}
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "txHistory", "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"], "sortOrder": "DESCENDING", "page": 0}}
*
* @apiSuccessExample {json} Success-Response:
* {
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":{
* "address":"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"
* "success":true,
* "txs":[
* {
* "height":631219,
* "tx_hash":"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f"
* }
* ],
* "status":200
* }
* }
* }
*/
async transactions (rpcData) {
async txHistory (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
// console.log('transactions rpcData: ', rpcData)
const addrs = rpcData.payload.params.addresses
// const addr = rpcData.payload.params.address
// const sortOrder = rpcData.payload.params.sortOrder
const data = await this.bchjs.Electrumx.transactions(addrs)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
const data = await this.useCases.bch.getTransactions(rpcData)
const retObj = data
retObj.status = 200
return retObj
return data
} catch (err) {
// console.error('Error in createUser()')
console.error('Error in JSON RPC BCH transactions()')
// throw err
// Return an error response
@@ -114,7 +157,7 @@ class BCHRPC {
success: false,
status: 422,
message: err.message,
endpoint: 'transactions'
endpoint: 'txHistory'
}
}
}
@@ -126,9 +169,48 @@ class BCHRPC {
* @apiGroup JSON BCH
* @apiDescription This endpoint wraps the bchjs.Electrumx.balance([]) function.
*
* Given the 'addresses' property it returns an object
* with the following properties
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - method: "" - Method used in the petition
* - receiver: "" - Receiver address
* - value: {} - Final result value of the petition
* - success : - Petition status
* - balances : [] - Balance of the provided addresses
* - balance : {} - Object with the balance types of an address
* - confirmed : - Confirmed balance
* - unconfirmed : - Unconfirmed balance
* - address : "" - Address related to the balance
* - status: - HTTP Status Code
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "balance", "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"]}}
*
* @apiSuccessExample {json} Success-Response:
* {
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":{
* "success":true,
* "balances":[
* {
* "balance":{
* "confirmed":1000,
* "unconfirmed":0
* },
* "address":"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"
* }
* ],
* "status":200
* }
* }
* }
*/
async balance (rpcData) {
try {
@@ -144,7 +226,7 @@ class BCHRPC {
return retObj
} catch (err) {
// console.error('Error in createUser()')
console.error('Error in JSON RPC BCH balance()')
// throw err
// Return an error response
@@ -166,15 +248,89 @@ class BCHRPC {
* endpoint returns UTXOs held at an address, hydrated
* with token information.
*
* Given an address this endpoint will return an object
* with the following properties
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - method: "" - Method used in the petition
* - receiver: "" - Receiver address
* - value: [] - Final result value of the petition
* - address: "" - the address these UTXOs are associated with
* - bchUtxos: [] - UTXOs confirmed to be spendable as normal BCH
* - nullUtxo: [] - UTXOs that did not pass SLP validation. Should be ignored and
* not spent, to be safe.
* - slpUtxos: {} - UTXOs confirmed to be colored as valid SLP tokens
* - type1: {}
* - tokens: [] - SLP token Type 1 tokens.
* - mintBatons: [] - SLP token Type 1 mint batons.
* - nft: {}
* - tokens: [] - NFT tokens
* - groupTokens: [] - NFT Group tokens, used to create NFT tokens.
* - groupMintBatons: [] - Minting baton to create more NFT Group tokens.
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "utxos", "address": "bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"}}
*
* @apiSuccessExample {json} Success-Response:
*
* {
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":[
* {
* "address":"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj",
* "bchUtxos":[
* {
* "height":631219,
* "tx_hash":"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f",
* "tx_pos":0,
* "value":1000,
* "txid":"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f",
* "vout":0,
* "isValid":false
* }
* ],
* "nullUtxos":[
*
* ],
* "slpUtxos":{
* "type1":{
* "mintBatons":[
*
* ],
* "tokens":[
*
* ]
* },
* "nft":{
* "groupMintBatons":[
*
* ],
* "groupTokens":[
*
* ],
* "tokens":[
*
* ]
* }
* }
* }
* ]
* }
* }
*
*/
async utxos (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
const addr = rpcData.payload.params.address
// console.log('addr: ', addr)
const data = await this.bchjs.Utxo.get(addr)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
@@ -184,7 +340,8 @@ class BCHRPC {
return retObj
} catch (err) {
// console.error('Error in createUser()')
console.error('Error in JSON RPC BCH utxos()')
console.error('Error in JSON RPC utxos(): ', err)
// throw err
// Return an error response
@@ -205,9 +362,27 @@ class BCHRPC {
* @apiDescription Broadcast a transaction to the BCH network.
* The transaction should be encoded as a hexidecimal string.
*
* This endpoint will return an object with the following properties
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - method: "" - Method used in the petition
* - receiver: "" - Receiver address
* - value: "" - Final result value of the petition
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "broadcast", "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000"}}
*
* @apiSuccessExample {json} Success-Response:
*
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value": "951299775f68a599b95239bfc385423f87a33e11747c299a22ef9dcf3d1557ec"
*
*/
async broadcast (rpcData) {
try {
@@ -218,50 +393,142 @@ class BCHRPC {
const data = await this.bchjs.RawTransactions.sendRawTransaction(hex)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
const retObj = data
retObj.status = 200
const retObj = {
success: true,
status: 200,
endpoint: 'broadcast',
txid: data
}
// retObj.status = 200
return retObj
} catch (err) {
// console.error('Error in createUser()')
console.error('Error in JSON RPC BCH broadcast()')
console.log('error: ', err)
// throw err
// bch-api will sometimes return an error message, not an error object.
let message = ''
if (!err.message && err.error) {
// Full node error
message = err.error
} else {
// Normal error
message = err.message
}
// Return an error response
return {
success: false,
status: 422,
message: err.message,
message,
endpoint: 'broadcast'
}
}
}
/**
* @api {JSON} /bch Transaction
* @api {JSON} /bch Transaction Data
* @apiPermission public
* @apiName Transaction
* @apiName txData
* @apiGroup JSON BCH
* @apiDescription Get data about a specific transaction.
* @apiDescription Get expanded transaction data for an array of transaction
* IDs. Each call is limited to 20 TXIDs or less.
*
* Given a transaction ID, the endpoint will return an object with the
* following properties
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - method: "" - Method used in the petition
* - receiver: "" - Receiver address
* - value: {} - Final result value of the petition
* - txid: "" - Transaction ID
* - hash: "" - Transaction hash
* - version: - Version number
* - size: - Transaction size
* - locktime: -
* - vin: [] - Transaction inputs
* - vout: [] - Transaction outputs
* - hex: "" - hexadecimal script
* - blockhash: "" - Reference to the block register
* - confirmations : "" - Transaction confirmations
* - time: - Execution time
* - blocktime: - Execution time
* - isValidSLPTx: - Determines if the transaction was under SLP
* - status: - HTTP Status Code
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "transaction", "hex": "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"}}
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "txData", "txids": ["01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b"]}}
*
* @apiSuccessExample {json} Success-Response:
* {
* "jsonrpc":"2.0",
* "id":"555",
* "txData": [{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":{
* "txid":"01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b",
* "hash":"01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b",
* "version":1,
* "size":272,
* "locktime":0,
* "vin":[
* {
* "txid":"4deef6de4b973706cd6e8fc8105a41a84be349e4e9717225ee5e7c63538e95e8",
* "vout":1,
* "scriptSig":{
* "asm":"3045022100fce6ef975fa7ec66e0ce0c51d839fd8f56510897252c0b238e7265974bc7c07202200d1d1429154e6775eecdc2829965650bc3ca714a86088d705bd58f8c034f2496[ALL|FORKID] 0467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3",
* "hex":"483045022100fce6ef975fa7ec66e0ce0c51d839fd8f56510897252c0b238e7265974bc7c07202200d1d1429154e6775eecdc2829965650bc3ca714a86088d705bd58f8c034f249641410467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3"
* },
* "sequence":4294967295,
* "address":"bitcoincash:qqrxa0h9jqnc7v4wmj9ysetsp3y7w9l36u8gnnjulq",
* "value":0.00001824
* }
* ],
* "vout":[
* {
* "value":0,
* "n":0,
* "scriptPubKey":{
* "asm":"OP_RETURN -385055325 46226800369048b83cea897639bb39273c8e4b883bd8c2a435bbe7a237cc433a",
* "hex":"6a045d7af3962046226800369048b83cea897639bb39273c8e4b883bd8c2a435bbe7a237cc433a",
* "type":"nulldata"
* }
* },
* {
* "value":0.0000155,
* "n":1,
* "scriptPubKey":{
* "asm":"OP_DUP OP_HASH160 066ebee590278f32aedc8a4865700c49e717f1d7 OP_EQUALVERIFY OP_CHECKSIG",
* "hex":"76a914066ebee590278f32aedc8a4865700c49e717f1d788ac",
* "reqSigs":1,
* "type":"pubkeyhash",
* "addresses":[
* "bitcoincash:qqrxa0h9jqnc7v4wmj9ysetsp3y7w9l36u8gnnjulq"
* ]
* }
* }
* ],
* "hex":"0100000001e8958e53637c5eee257271e9e449e34ba8415a10c88f6ecd0637974bdef6ee4d010000008b483045022100fce6ef975fa7ec66e0ce0c51d839fd8f56510897252c0b238e7265974bc7c07202200d1d1429154e6775eecdc2829965650bc3ca714a86088d705bd58f8c034f249641410467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3ffffffff020000000000000000276a045d7af3962046226800369048b83cea897639bb39273c8e4b883bd8c2a435bbe7a237cc433a0e060000000000001976a914066ebee590278f32aedc8a4865700c49e717f1d788ac00000000",
* "blockhash":"0000000000000000008e8d83cba6d45a9314bc2ef4538d4e0577c6bed8593536",
* "confirmations":98000,
* "time":1568338904,
* "blocktime":1568338904,
* "isValidSLPTx":false,
* "status":200
* }
* }
* }]
*/
async transaction (rpcData) {
async txData (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
const txid = rpcData.payload.params.txid
const data = await this.bchjs.Transaction.get(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
const retObj = data
retObj.status = 200
const retObj = await this.useCases.bch.getTxData(rpcData)
return retObj
} catch (err) {
// console.error('Error in createUser()')
console.error('Error in JSON RPC BCH txData()): ', err)
// throw err
// Return an error response
@@ -269,7 +536,79 @@ class BCHRPC {
success: false,
status: 422,
message: err.message,
endpoint: 'transaction'
endpoint: 'txData'
}
}
}
/**
* @api {JSON} /bch PubKey
* @apiPermission public
* @apiName PubKey
* @apiGroup JSON BCH
* @apiDescription Get the public key from an address.
* Given an address the endpoint will return an object with the
* following properties
*
* - jsonrpc: "" - jsonrpc version
* - id: "" - jsonrpc id
* - result: {} - Result of the petition with the RPC information
* - success: - Request status
* - publickey: - Address public key
*
* @apiExample Example usage:
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "pubkey", "address": "bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk"}}
*
* @apiSuccessExample {json} Success-Response:
* {
* "jsonrpc":"2.0",
* "id":"555",
* "result":{
* "method":"bch",
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
* "value":{
* "success": true,
* "status": 200,
* "endpoint": "pubkey",
* "pubkey": {
* "success": true,
* "publicKey": "033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee"
* }
*
* }
*/
async pubKey (rpcData) {
try {
// console.log('createUser rpcData: ', rpcData)
const address = rpcData.payload.params.address
const data = await this.bchjs.encryption.getPubKey(address)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
const retObj = {
success: true,
status: 200,
endpoint: 'pubkey',
pubkey: data
}
// retObj.status = 200
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH pubKey()')
// throw err
let error = err
if (err.error && typeof err.error === 'string') {
error = new Error(err.error)
}
// Return an error response
return {
success: false,
status: 422,
message: error.message,
endpoint: 'pubkey'
}
}
}
+86 -9
View File
@@ -38,6 +38,11 @@ class JSONRPC {
this.aboutController = new AboutController()
this.bchController = new BCHController(localConfig)
// Cache to store IDs of processed JSON RPC commands. Used to prevent
// duplicate processing.
this.msgCache = []
this.MSG_CACHE_SIZE = 30
_this = this
}
@@ -46,23 +51,54 @@ class JSONRPC {
async router (str, from) {
try {
// console.log('router str: ', str)
// console.log('router from: ', from)
console.log('JSON RPC router recieved data from: ', from)
// Exit quietly if 'from' is not specified.
if (!from || typeof from !== 'string') {
// console.warn(
// 'Warning: Can not send JSON RPC response. Can not determine which peer this message came from.'
// )
return
wlogger.info(
'Warning: Can not send JSON RPC response. Can not determine which peer this message came from.'
)
return false
}
// Attempt to parse the incoming data as a JSON RPC string.
const parsedData = _this.jsonrpc.parse(str)
// console.log('parsedData: ', parsedData)
// wlogger.debug(`parsedData: ${JSON.stringify(parsedData, null, 2)}`)
// Exit quietly if the incoming string is an invalid JSON RPC string.
if (parsedData.type === 'invalid') {
return
wlogger.info('Rejecting invalid JSON RPC command.')
return false
}
// Check for duplicate entries with same 'id' value.
const alreadyProcessed = _this._checkIfAlreadyProcessed(parsedData)
if (alreadyProcessed) {
return false
} else {
// console.log(`parsedData: ${JSON.stringify(parsedData, null, 2)}`)
// This node will regularly ping known circuit relays with an /about
// JSON RPC call. These will be handled by ipfs-coord, but will percolate
// up to this library. Ignore these messages.
if (
parsedData.type.includes('success') &&
parsedData.payload.method === undefined
) {
return false
}
// Log the incoming JSON RPC command.
wlogger.info(
`JSON RPC received from ${from}, ID: ${parsedData.payload.id}, type: ${parsedData.type}, method: ${parsedData.payload.method}`
)
// Additional debugging for BCH.
if (parsedData.payload.method === 'bch') {
wlogger.info(
`rpcData.payload: ${JSON.stringify(parsedData.payload, null, 2)}`
)
}
}
// Added the property "from" to the parsedData object;
@@ -100,8 +136,19 @@ class JSONRPC {
// Encrypt and publish the response to the originators private OrbitDB,
// if ipfs-coord has been initialized and the peers ID is registered.
if (_this.ipfsCoord.ipfs) {
await _this.ipfsCoord.ipfs.orbitdb.sendToDb(from, retStr)
// console.log('responding to JSON RPC command')
const thisNode = _this.ipfsCoord.thisNode
// console.log('thisNode: ', thisNode)
try {
await _this.ipfsCoord.useCases.peer.sendPrivateMessage(
from,
retStr,
thisNode
)
} catch (err) {
console.log('sendPrivateMessage() err: ', err)
}
// Return the response and originator. Useful for testing.
@@ -113,6 +160,36 @@ class JSONRPC {
}
}
// Checks the ID of the JSON RPC call, to see if the message has already been
// processed. Returns true if the ID exists in the cache of processed messages.
// If the ID is new, the function adds it to the cache and return false.
_checkIfAlreadyProcessed (data) {
try {
// console.log('data: ', data)
const id = data.payload.id
// Check if the hash is in the array of already processed message.
const alreadyProcessed = this.msgCache.includes(id)
// Update the msgCache if this is a new message.
if (!alreadyProcessed) {
// Add the hash to the array.
this.msgCache.push(id)
// If the array is at its max size, then remove the oldest element.
if (this.msgCache.length > this.MSG_CACHE_SIZE) {
this.msgCache.shift()
}
}
return alreadyProcessed
} catch (err) {
console.error('Error in _checkIfAlreadyProcessed: ', err)
return true
}
}
// The default JSON RPC response if the incoming command could not be routed.
defaultResponse () {
const errorObj = {
+234 -25
View File
@@ -2,7 +2,7 @@
Controller for the /fulcrum REST API endpoints.
*/
const BCHJS = require('@psf/bch-js')
// const BCHJS = require('@psf/bch-js')
let _this
@@ -22,26 +22,49 @@ class BCHRESTController {
)
}
this.bchjs = new BCHJS()
// this.bchjs = new BCHJS()
this.bchjs = this.adapters.bchjs
_this = this
}
/**
*
* @api {post} /bch/transactions Transactions
* @apiName Transactions
* @apiGroup REST BCH
* @apiDescription This endpoint wraps the bchjs.Electrumx.transactions([]) function.
*
* Given the 'addresses' property returns an array of objects
* with the following properties
*
* - success : - Petition status
* - transactions : [] - Transaction of the provided address
* - transactions: [] - Transaction details
* - height : - Reference to the blockchain size
* - tx_hash: "" - Transaction hash
* - address : "" - Address associated to the transactions
*
* Note: For a single address pass the 'addresses' of string type
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"] }' localhost:5001/bch/transactions
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
*
* success:true,
* data: <data>
* "success":true,
* "transactions":[
* {
* "transactions":[
* {
* "height":631219,
* "tx_hash":"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f"
* }
* ],
* "address":"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"
* }
* ]
* }
*
* @apiError UnprocessableEntity Missing required parameters
@@ -53,6 +76,7 @@ class BCHRESTController {
* "error": "Unprocessable Entity"
* }
*/
async transactions (ctx) {
try {
const addrs = ctx.request.body.addresses
@@ -70,7 +94,19 @@ class BCHRESTController {
* @api {post} /bch/balance Balance
* @apiName Balance
* @apiGroup REST BCH
* @apiDescription This endpoint returns the balance in BCH for an address.
* @apiDescription Returns the balance of an address or an array of addresses.
*
* Given the 'addresses' property returns an array of objects
* with the following properties
*
* - success : - Petition status
* - balances : [] - Balance of the provided addresses
* - balance : {} - Object with the balance types of an address
* - confirmed : - Confirmed balance
* - unconfirmed : - Unconfirmed Balance
* - address : "" - Address related to the balance
*
* Note: For a single address pass the 'addresses' of string type
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"] }' localhost:5001/bch/balance
@@ -78,8 +114,16 @@ class BCHRESTController {
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* success:true,
* data: <data>
* "success":true,
* "balances":[
* {
* "balance":{
* "confirmed":1000,
* "unconfirmed":0
* },
* "address":"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"
* }
* ]
* }
*
* @apiError UnprocessableEntity Missing required parameters
@@ -105,21 +149,74 @@ class BCHRESTController {
}
/**
* @api {post} /bch/utxos Balance
* @apiName Utxos
* @api {post} /bch/utxos UTXOs
* @apiName UTXOs
* @apiGroup REST BCH
* @apiDescription This endpoint returns UTXOs held at an address, hydrated
* with token information.
* with token information.
*
* Given an address, this endpoint will return an object with thre following
* properties:
*
* - address: "" - the address these UTXOs are associated with
* - bchUtxos: [] - UTXOs confirmed to be spendable as normal BCH
* - nullUtxo: [] - UTXOs that did not pass SLP validation. Should be ignored and
* not spent, to be safe.
* - slpUtxos: {} - UTXOs confirmed to be colored as valid SLP tokens
* - type1: {}
* - tokens: [] - SLP token Type 1 tokens.
* - mintBatons: [] - SLP token Type 1 mint batons.
* - nft: {}
* - tokens: [] - NFT tokens
* - groupTokens: [] - NFT Group tokens, used to create NFT tokens.
* - groupMintBatons: [] - Minting baton to create more NFT Group tokens.
*
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "address": "bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj" }' localhost:5001/bch/utxos
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* success:true,
* data: <data>
* }
* [
* {
* "address":"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj",
* "bchUtxos":[
* {
* "height":631219,
* "tx_hash":"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f",
* "tx_pos":0,
* "value":1000,
* "txid":"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f",
* "vout":0,
* "isValid":false
* }
* ],
* "nullUtxos":[
*
* ],
* "slpUtxos":{
* "type1":{
* "mintBatons":[
*
* ],
* "tokens":[
*
* ]
* },
* "nft":{
* "groupMintBatons":[
*
* ],
* "groupTokens":[
*
* ],
* "tokens":[
*
* ]
* }
* }
* }
* ]
*
* @apiError UnprocessableEntity Missing required parameters
*
@@ -150,15 +247,14 @@ class BCHRESTController {
* @apiDescription Broadcast a transaction to the BCH network.
* The transaction should be encoded as a hexidecimal string.
*
* This endpoint will return a transaction id
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000" }' localhost:5001/bch/broadcast
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* success:true,
* data: <data>
* }
* "951299775f68a599b95239bfc385423f87a33e11747c299a22ef9dcf3d1557ec"
*
* @apiError UnprocessableEntity Missing required parameters
*
@@ -174,7 +270,7 @@ class BCHRESTController {
const hex = ctx.request.body.hex
const txid = await _this.bchjs.RawTransactions.sendRawTransaction(hex)
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
ctx.body = txid
} catch (err) {
@@ -187,16 +283,78 @@ class BCHRESTController {
* @apiName Transaction
* @apiGroup REST BCH
* @apiDescription Get data about a specific transaction.
* Given a transaction id this endpoint will return an object
* with the following properties
*
* - txid: "" - Transaction ID
* - hash: "" - Transaction hash
* - version: - Version number
* - size: - Transaction size
* - locktime: -
* - vin: [] - Transaction inputs
* - vout: [] - Transaction outputs
* - hex: "" - hexadecimal script
* - blockhash: "" - Reference to the block register
* - confirmations : "" - Transaction confirmations
* - time: - Execution time
* - blocktime: - Execution time
* - isValidSLPTx: - Determines if the transaction was under SLP
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "txid": "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" }' localhost:5001/bch/transaction
* curl -H "Content-Type: application/json" -X POST -d '{ "txid": "01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b" }' localhost:5001/bch/transaction
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* success:true,
* data: <data>
* }
* {
* "txid":"01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b",
* "hash":"01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b",
* "version":1,
* "size":272,
* "locktime":0,
* "vin":[
* {
* "txid":"4deef6de4b973706cd6e8fc8105a41a84be349e4e9717225ee5e7c63538e95e8",
* "vout":1,
* "scriptSig":{
* "asm":"3045022100fce6ef975fa7ec66e0ce0c51d839fd8f56510897252c0b238e7265974bc7c07202200d1d1429154e6775eecdc2829965650bc3ca714a86088d705bd58f8c034f2496[ALL|FORKID] 0467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3",
* "hex":"483045022100fce6ef975fa7ec66e0ce0c51d839fd8f56510897252c0b238e7265974bc7c07202200d1d1429154e6775eecdc2829965650bc3ca714a86088d705bd58f8c034f249641410467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3"
* },
* "sequence":4294967295,
* "address":"bitcoincash:qqrxa0h9jqnc7v4wmj9ysetsp3y7w9l36u8gnnjulq",
* "value":0.00001824
* }
* ],
* "vout":[
* {
* "value":0,
* "n":0,
* "scriptPubKey":{
* "asm":"OP_RETURN -385055325 46226800369048b83cea897639bb39273c8e4b883bd8c2a435bbe7a237cc433a",
* "hex":"6a045d7af3962046226800369048b83cea897639bb39273c8e4b883bd8c2a435bbe7a237cc433a",
* "type":"nulldata"
* }
* },
* {
* "value":0.0000155,
* "n":1,
* "scriptPubKey":{
* "asm":"OP_DUP OP_HASH160 066ebee590278f32aedc8a4865700c49e717f1d7 OP_EQUALVERIFY OP_CHECKSIG",
* "hex":"76a914066ebee590278f32aedc8a4865700c49e717f1d788ac",
* "reqSigs":1,
* "type":"pubkeyhash",
* "addresses":[
* "bitcoincash:qqrxa0h9jqnc7v4wmj9ysetsp3y7w9l36u8gnnjulq"
* ]
* }
* }
* ],
* "hex":"0100000001e8958e53637c5eee257271e9e449e34ba8415a10c88f6ecd0637974bdef6ee4d010000008b483045022100fce6ef975fa7ec66e0ce0c51d839fd8f56510897252c0b238e7265974bc7c07202200d1d1429154e6775eecdc2829965650bc3ca714a86088d705bd58f8c034f249641410467ff2df20f28bc62ad188525868f41d461f7dab3c1e500314cdb5218e5637bfd0f9c02eb5b3f383f698d28ff13547eaf05dd9216130861dd0216824e9d7337e3ffffffff020000000000000000276a045d7af3962046226800369048b83cea897639bb39273c8e4b883bd8c2a435bbe7a237cc433a0e060000000000001976a914066ebee590278f32aedc8a4865700c49e717f1d788ac00000000",
* "blockhash":"0000000000000000008e8d83cba6d45a9314bc2ef4538d4e0577c6bed8593536",
* "confirmations":97988,
* "time":1568338904,
* "blocktime":1568338904,
* "isValidSLPTx":false
* }
*
* @apiError UnprocessableEntity Missing required parameters
*
@@ -220,6 +378,57 @@ class BCHRESTController {
}
}
/**
* @api {post} /bch/pubkey PubKey
* @apiName PubKey
* @apiGroup REST BCH
* @apiDescription Get the public key from an address
*
* Given the 'address' param returns an object
* with the following properties
*
* - success : - Request status
* - publicKey : '' - Public key of the provided address
*
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5001/bch/pubkey/bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success":true,
* "publicKey": '033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee'
* }
*
* @apiError UnprocessableEntity Missing required parameters
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 422 Unprocessable Entity
* {
* "status": 422,
* "error": "Unprocessable Entity"
* }
*/
async pubKey (ctx) {
try {
const address = ctx.params.address
console.log(`pubKey address: ${address}`)
const pubkey = await _this.bchjs.encryption.getPubKey(address)
// console.log(`pubkey: ${JSON.stringify(pubkey, null, 2)}`)
ctx.body = pubkey
} catch (err) {
console.log(err)
let error = err
if (err.error && typeof err.error === 'string') {
error = new Error(err.error)
}
_this.handleError(ctx, error)
}
}
// DRY error handler
handleError (ctx, err) {
// If an HTTP status is specified by the buisiness logic, use that.
+1
View File
@@ -50,6 +50,7 @@ class BCHRouter {
this.router.post('/utxos', this.bchRESTController.utxos)
this.router.post('/broadcast', this.bchRESTController.broadcast)
this.router.post('/transaction', this.bchRESTController.transaction)
this.router.get('/pubkey/:address', this.bchRESTController.pubKey)
// Attach the Controller routes to the Koa app.
app.use(this.router.routes())
+142
View File
@@ -0,0 +1,142 @@
/*
Use Cases for interacting with the BCH blockchain.
*/
class BCHUseCases {
constructor (localConfig = {}) {
// console.log('User localConfig: ', localConfig)
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of adapters must be passed in when instantiating BCH Use Cases library.'
)
}
// Encapsulate dependencies
this.bchjs = this.adapters.bchjs
}
// Get transaction history for an address, sorted by block height.
async getTransactions (rpcData) {
try {
// console.log(
// `getTransactions rpcData: ${JSON.stringify(rpcData, null, 2)}`
// )
// Get the list of addresses.
const addr = rpcData.payload.params.address
// Default to descending sorting.
let sortOrder = rpcData.payload.params.sortOrder
if (!sortOrder) sortOrder = 'DESCENDING'
// console.log('sortOrder: ', sortOrder)
// Default to page 1
let page = rpcData.payload.params.page
if (!page) page = 0
// console.log('page: ', page)
// Get the transaction history for the list of addresses.
const data = await this.bchjs.Electrumx.transactions([addr])
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
if (!data.success) {
throw new Error('Could not query Fulcrum indexer.')
}
// console.log(`transactions: ${JSON.stringify(transactions, null, 2)}`);
// Sort the transactions.
const txsArr = await this.bchjs.Electrumx.sortAllTxs(
data.transactions[0].transactions,
sortOrder
)
// console.log(`txsArr: ${JSON.stringify(txsArr, null, 2)}`)
// Paginate the results
const pagedResults = this.bchjs.Util.chunk100(txsArr)
// console.log(
// `pagedResults[page]: ${JSON.stringify(pagedResults[page], null, 2)}`
// )
const retObj = {
address: addr,
txs: pagedResults[page],
status: 200,
success: true
}
// console.log(`retObj: ${JSON.stringify(retObj, null, 2)}`)
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH transactions(): ', err)
// throw err
// Return an error response
return {
success: false,
status: 422,
message: err.message,
endpoint: 'txHistory'
}
}
}
// Get transaction data for an array of TXIDs.
async getTxData (rpcData) {
try {
// console.log('transaction rpcData: ', rpcData)
const txids = rpcData.payload.params.txids
// console.log(`txids: ${JSON.stringify(txids, null, 2)}`)
if (!Array.isArray(txids)) {
return {
success: false,
status: 422,
message: 'Input txids must be an array of transaction IDs.',
endpoint: 'txData'
}
}
if (txids.length > 20) {
return {
success: false,
status: 422,
message: 'Array input must be 20 elements or less.',
endpoint: 'txData'
}
}
const txData = []
for (let i = 0; i < txids.length; i++) {
const thisTxid = txids[i]
// console.log(`this.bchjs.restURL: ${this.bchjs.restURL}`)
const data = await this.bchjs.Transaction.get(thisTxid.toString())
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
txData.push(data.txData)
}
const retObj = {
status: 200,
txData
}
return retObj
} catch (err) {
console.error('Error in JSON RPC BCH getTxData(): ', err)
// throw err
// Return an error response
return {
success: false,
status: 422,
message: err.message,
endpoint: 'txData'
}
}
}
}
module.exports = BCHUseCases
+3
View File
@@ -4,7 +4,9 @@
https://troutsblog.com/blog/clean-architecture
*/
// Local libraries
const UserUseCases = require('./user')
const BCHUseCases = require('./bch')
class UseCases {
constructor (localConfig = {}) {
@@ -17,6 +19,7 @@ class UseCases {
// console.log('use-cases/index.js localConfig: ', localConfig)
this.user = new UserUseCases(localConfig)
this.bch = new BCHUseCases(localConfig)
}
}
+4 -11
View File
@@ -3,7 +3,7 @@
functions are called by the /user REST API endpoints.
*/
// const UserModel = require('../adapters/localdb/models/users')
const UserEntity = require('../entities/user')
const { wlogger } = require('../adapters/wlogger')
class UserLib {
@@ -17,6 +17,7 @@ class UserLib {
}
// Encapsulate dependencies
this.UserEntity = new UserEntity()
this.UserModel = this.adapters.localdb.Users
}
@@ -24,17 +25,9 @@ class UserLib {
async createUser (userObj) {
try {
// Input Validation
if (!userObj.email || typeof userObj.email !== 'string') {
throw new Error("Property 'email' must be a string!")
}
if (!userObj.password || typeof userObj.password !== 'string') {
throw new Error("Property 'password' must be a string!")
}
if (!userObj.name || typeof userObj.name !== 'string') {
throw new Error("Property 'name' must be a string!")
}
const user = new this.UserModel(userObj)
const userEntity = this.UserEntity.validate(userObj)
const user = new this.UserModel(userEntity)
// Enforce default value of 'user'
user.type = 'user'
+3
View File
@@ -0,0 +1,3 @@
/key/swarm/psk/1.0.0/
/base16/
bbd935b70105b03ebd0c6a3c2d2730cd22fc0d18c490ccf689b6c8a22e1bed2a
+25 -16
View File
@@ -10,7 +10,7 @@ const axios = require('axios').default
// Local support libraries
const config = require('../../../config')
const app = require('../../../bin/server')
const Server = require('../../../bin/server')
const testUtils = require('../../utils/test-utils')
const AdminLib = require('../../../src/adapters/admin')
const adminLib = new AdminLib()
@@ -22,25 +22,34 @@ const LOCALHOST = `http://localhost:${config.port}`
describe('Auth', () => {
before(async () => {
// This should be the first instruction. It starts the REST API server.
await app.startServer()
try {
const app = new Server()
// Delete all previous users in the database.
await testUtils.deleteAllUsers()
// This should be the first instruction. It starts the REST API server.
await app.startServer()
// Create a new admin user.
await adminLib.createSystemUser()
// Stop the IPFS node for the rest of the e2e tests.
// await app.controllers.adapters.ipfs.stop()
const userObj = {
email: 'test@test.com',
password: 'pass',
name: 'test'
// Delete all previous users in the database.
await testUtils.deleteAllUsers()
// Create a new admin user.
await adminLib.createSystemUser()
const userObj = {
email: 'test@test.com',
password: 'pass',
name: 'test'
}
const testUser = await testUtils.createUser(userObj)
// console.log('TestUser: ', testUser)
context.user = testUser.user
context.token = testUser.token
} catch (err) {
console.log('err in auth beforeAll: ', err)
}
const testUser = await testUtils.createUser(userObj)
// console.log('TestUser: ', testUser)
context.user = testUser.user
context.token = testUser.token
})
describe('POST /auth', () => {
+2 -1
View File
@@ -12,7 +12,8 @@ const LOCALHOST = `http://localhost:${config.port}`
const context = {}
const UserController = require('../../../src/controllers/rest-api/users/controller')
const adapters = require('../../../src/adapters')
const Adapters = require('../../../src/adapters')
const adapters = new Adapters()
const UseCases = require('../../../src/use-cases/')
let uut
let sandbox
+11
View File
@@ -0,0 +1,11 @@
# Consumer Simulation E2E Test
The files in this directory simulates a consumer of web services, using JSON RPC over IPFS. It starts a new IPFS node that connects to the ipfs-bch-wallet-service and exercises each JSON RPC endpoint.
## Instructions
Execute these steps in order to run the test:
1. Run your local copy of ipfs-bch-wallet-service service provider.
2. Update the [test-data.json](./test-data.json) file with the IPFS ID of the ipfs-bch-wallet-service.
3. In another terminal, run the client simulation with `node client.e2e.js`
+33
View File
@@ -0,0 +1,33 @@
/*
An end-to-end (e2e) test simulating a client connecting over IPFS and
that exercises each JSON RPC endpoint.
*/
const TestUtils = require('./lib/test-utils')
const testUtils = new TestUtils()
const testData = require('./test-data.json')
async function startTest () {
try {
console.log('E2E TEST: Starting consumer E2E tests...')
await testUtils.startIpfs()
await testUtils.connectToUut(testData.uutAddr, testData.uutId)
await testUtils.testBalance(testData.uutId)
await testUtils.testTransaction(testData.uutId)
await testUtils.testTransactions(testData.uutId)
await testUtils.testUtxos(testData.uutId)
console.log('E2E TEST: Tests completed successfully!')
process.exit()
} catch (err) {
console.error('Error in startTest(): ', err)
}
}
startTest()
+303
View File
@@ -0,0 +1,303 @@
/*
A class library of test utility functions.
*/
// Public npm libraries
const BCHJS = require('@psf/bch-js')
const IpfsCoord = require('ipfs-coord')
const IPFS = require('ipfs-http-client')
const EventEmitter = require('events')
const { v4: uid } = require('uuid')
const jsonrpc = require('jsonrpc-lite')
const http = require('http')
let _this
class TestUtils {
constructor (localConfig = {}) {
// Encapsulate dependencies.
this.bchjs = new BCHJS()
this.eventEmitter = new EventEmitter()
this.uid = uid
this.jsonrpc = jsonrpc
_this = this
}
// This handler function recieves data from other ipfs-coord peers, like
// the ipfs-bch-wallet-service that we're testing.
// It emits the data as an 'rpcData' event. The tests will listen for this
// event.
rpcHandler (inData) {
try {
// console.log('Data recieved by rpcHandler: ', inData)
const jsonData = JSON.parse(inData)
_this.eventEmitter.emit('rpcData', jsonData)
} catch (err) {
console.error('Error in rpcHandler: ', err)
// Do not throw an error. This is a top-level function.
}
}
// Send the RPC command to the service, wait a period of time for a response.
// Timeout if a response is not recieved.
async sendRPC (ipfsId, cmdStr) {
try {
// Send the RPC command to the server/service.
// await this.ipfsCoord.ipfs.orbitdb.sendToDb(ipfsId, cmdStr)
await this.ipfsCoord.useCases.peer.sendPrivateMessage(
ipfsId,
cmdStr,
this.ipfsCoord.thisNode
)
let retData
// This event is triggered when the response comes back.
this.eventEmitter.on('rpcData', (inData) => {
retData = inData
})
// Used for calculating the timeout.
const start = new Date()
let now = start
let timeDiff = 0
// Wait for the response from the server. Exit once the response is
// recieved, or a timeout occurs.
do {
await this.bchjs.Util.sleep(1000)
now = new Date()
timeDiff = now.getTime() - start.getTime()
// console.log('timeDiff: ', timeDiff)
} while (
// Exit once the RPC data comes back, or if a period of time passes.
!retData || // eslint-disable-line no-unmodified-loop-condition
timeDiff > 10000
)
return retData
} catch (err) {
console.error('Error in sendRPC')
throw err
}
}
async startIpfs () {
try {
const ipfsOptionsExternal = {
host: 'localhost',
port: 5001,
agent: http.Agent({ keepAlive: true, maxSockets: 2000 })
}
// Start the IPFS node.
this.ipfs = await IPFS.create(ipfsOptionsExternal)
await this.ipfs.config.profiles.apply('server')
// Start ipfs-coord.
this.ipfsCoord = new IpfsCoord({
ipfs: this.ipfs,
type: 'node.js',
// type: 'browser',
bchjs: this.bchjs,
privateLog: this.rpcHandler, // Default to console.log
isCircuitRelay: false,
apiInfo: 'none',
announceJsonLd: announceJsonLd,
nodeType: 'external'
})
await this.ipfsCoord.start()
// Wait to let ipfs-coord connect to subnet peers.
await this.bchjs.Util.sleep(30000)
} catch (err) {
console.error('Error in startIpfs().')
throw err
}
}
// Connect to the unit under test (uut)
async connectToUut (addr, ipfsId) {
try {
try {
await this.ipfs.swarm.connect(addr)
console.log(`E2E TEST: Connected to IPFS node ${addr}`)
} catch (err) {
throw new Error('Could not connect to UUT IPFS node.')
}
// console.log(
// 'ipfs-coord peer info: ',
// this.ipfsCoord.ipfs.peers.state.peers[ipfsId]
// )
const peers = this.ipfsCoord.thisNode.peerList
// console.log('peers: ', peers)
// console.log('Target peer in peerList? ', peers.includes(ipfsId))
// if (!this.ipfsCoord.ipfs.peers.state.peers[ipfsId]) {
if (!peers.includes(ipfsId)) {
throw new Error('Could not find UUT in ipfs-coord list of peers.')
}
} catch (err) {
console.log(err)
console.error('Error in connectToUut()')
console.log(
'Is the service running? Did you update the test-data.json file?'
)
process.exit()
}
}
// Get the balance for a BCH address over JSON RPC.
async testBalance (ipfsId) {
try {
// Generate the JSON RPC command
const id = uid()
const cmd = jsonrpc.request(id, 'bch', {
endpoint: 'balance',
addresses: ['bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj']
})
const cmdStr = JSON.stringify(cmd)
// console.log(`Publishing message to ${ipfsId}`)
console.log('E2E TEST: Sending Balance command...')
const result = await this.sendRPC(ipfsId, cmdStr)
// console.log('result: ', result)
if (result.result.value.success && result.result.value.balances) {
console.log('E2E TEST: balance test passed.')
return true
} else {
console.log('E2E TEST: balance test failed.')
this.failTest()
}
} catch (err) {
console.error('Error in testBalance()')
throw err
}
}
// Get the info a on transaction over JSON RPC.
async testTransaction (ipfsId) {
try {
// Generate the JSON RPC command
const id = uid()
const cmd = jsonrpc.request(id, 'bch', {
endpoint: 'transaction',
txid: '01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b'
})
const cmdStr = JSON.stringify(cmd)
// console.log(`Publishing message to ${ipfsId}`)
console.log('E2E TEST: Sending Transaction command...')
const result = await this.sendRPC(ipfsId, cmdStr)
// console.log('result: ', result)
if (result.result.value.status && result.result.value.confirmations) {
console.log('E2E TEST: transaction test passed.')
return true
} else {
console.log('E2E TEST: transaction test failed.')
this.failTest()
}
} catch (err) {
console.error('Error in testTransaction()')
throw err
}
}
// Get the info a on transaction over JSON RPC.
async testTransactions (ipfsId) {
try {
// Generate the JSON RPC command
const id = uid()
const cmd = jsonrpc.request(id, 'bch', {
endpoint: 'transactions',
address: 'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj'
})
const cmdStr = JSON.stringify(cmd)
// console.log(`Publishing message to ${ipfsId}`)
console.log('E2E TEST: Sending Transactions command...')
const result = await this.sendRPC(ipfsId, cmdStr)
// console.log('result: ', result)
if (
result.result.value.status &&
Array.isArray(result.result.value.transactions)
) {
console.log('E2E TEST: transactions test passed.')
return true
} else {
console.log('E2E TEST: transactions test failed.')
this.failTest()
}
} catch (err) {
console.error('Error in testTransactions()')
throw err
}
}
// Get the utxos for a BCH address over JSON RPC.
async testUtxos (ipfsId) {
try {
// Generate the JSON RPC command
const id = uid()
const cmd = jsonrpc.request(id, 'bch', {
endpoint: 'utxos',
address: 'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj'
})
const cmdStr = JSON.stringify(cmd)
// console.log(`Publishing message to ${ipfsId}`)
console.log('E2E TEST: Sending Utxos command...')
const result = await this.sendRPC(ipfsId, cmdStr)
// console.log('result', result.result.value)
const bchUtxos = result.result.value[0].bchUtxos
const slpUtxos = result.result.value[0].slpUtxos
if (result.result.value && bchUtxos && slpUtxos) {
console.log('E2E TEST: utxos test passed.')
return true
} else {
console.log('E2E TEST: utxos test failed.')
this.failTest()
}
} catch (err) {
console.error('Error in testUtxos()')
throw err
}
}
failTest () {
console.log('Exiting test program.')
process.exit()
}
}
const announceJsonLd = {
'@context': 'https://schema.org/',
'@type': 'WebAPI',
name: 'e2e-test-client',
description: 'A test client runing e2e tests on ipfs-bch-wallet-service.',
documentation: 'https://ipfs-bch-wallet-service.fullstack.cash/',
provider: {
'@type': 'Organization',
name: 'Permissionless Software Foundation',
url: 'https://PSFoundation.cash'
}
}
module.exports = TestUtils
+4
View File
@@ -0,0 +1,4 @@
{
"uutAddr": "/ip4/88.99.188.196/tcp/4001/p2p/12D3KooWT2tDg2pHwKz84Htzh2KsfSUZbZXmoAUFnaSwUVrDsag3/p2p-circuit/ipfs/12D3KooWNuZPDb15ENgk2CYF2dByq1oK6CQ5tUpRW9CpwwNynuJY",
"uutId": "12D3KooWNuZPDb15ENgk2CYF2dByq1oK6CQ5tUpRW9CpwwNynuJY"
}
@@ -0,0 +1,130 @@
/*
Integration tests for the BCH Use Cases library
*/
// Global npm libraries
const assert = require('chai').assert
// Local libraries
const BCHUseCases = require('../../../../src/use-cases/bch')
const Adapters = require('../../../../src/adapters')
describe('#BCH', () => {
let uut
before(async () => {
const adapters = new Adapters()
await adapters.start()
uut = new BCHUseCases({ adapters })
})
describe('#getTransactions', () => {
it('should get transactions for an address, with default descending sorting', async () => {
const rpcData = {
payload: {
params: {
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
}
}
}
const result = await uut.getTransactions(rpcData)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.isArray(result.txs)
// Assert descending sort order.
assert.isAbove(result.txs[0].height, result.txs[1].height)
})
it('should get transactions for an address, with explicit descending sorting', async () => {
const rpcData = {
payload: {
params: {
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v',
sortOrder: 'DESCENDING'
}
}
}
const result = await uut.getTransactions(rpcData)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.isArray(result.txs)
// Assert descending sort order.
assert.isAbove(result.txs[0].height, result.txs[1].height)
})
it('should sort in ascending order', async () => {
const rpcData = {
payload: {
params: {
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v',
sortOrder: 'ASCENDING'
}
}
}
const result = await uut.getTransactions(rpcData)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.success, true)
assert.equal(result.status, 200)
assert.isArray(result.txs)
// Assert descending sort order.
assert.isAbove(result.txs[1].height, result.txs[0].height)
})
})
describe('#getTxData', () => {
it('should get data for a single non-SLP tx', async () => {
const txids = [
'11384d7e5a8af93806591debe5bbe2d7826aeea987b874dfbe372dfdcc0ee54f'
]
const rpcData = {
payload: {
params: {
txids
}
}
}
const result = await uut.getTxData(rpcData)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.status, 200)
assert.isArray(result.txData)
assert.equal(result.txData.length, 1)
})
it('should get data on multiple non-SLP txs', async () => {
const txids = [
'11384d7e5a8af93806591debe5bbe2d7826aeea987b874dfbe372dfdcc0ee54f',
'f9b54fd8d27b0237923437ed4df8d45557f52b3ad4d8d03d4104e925c84ab4ca'
]
const rpcData = {
payload: {
params: {
txids
}
}
}
const result = await uut.getTxData(rpcData)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.status, 200)
assert.isArray(result.txData)
assert.equal(result.txData.length, 2)
})
})
})
@@ -0,0 +1,162 @@
/*
Unit tests for the jwt-bch-lib and fullstack-jwt.js adapter library.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const FullStackJWT = require('../../../src/adapters/fullstack-jwt')
describe('#FullStackJWT', () => {
let sandbox
let uut
beforeEach(() => {
sandbox = sinon.createSandbox()
const localConfig = {
authServer: 'someserver',
apiServer: 'someserver',
fullstackLogin: 'somelogin',
fullstackPassword: 'somepassword'
}
uut = new FullStackJWT(localConfig)
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if auth server is not specified', () => {
try {
uut = new FullStackJWT()
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a url for the AUTH server when instantiating FullStackJWT class.'
)
}
})
it('should throw an error if api server is not specified', () => {
try {
const localConfig = {
authServer: 'someserver'
}
uut = new FullStackJWT(localConfig)
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a url for the API server when instantiating FullStackJWT class.'
)
}
})
it('should throw an error if login is not specified', () => {
try {
const localConfig = {
authServer: 'someserver',
apiServer: 'someserver'
}
uut = new FullStackJWT(localConfig)
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a FullStack.cash login (email) instantiating FullStackJWT class.'
)
}
})
it('should throw an error if login is not specified', () => {
try {
const localConfig = {
authServer: 'someserver',
apiServer: 'someserver',
fullstackLogin: 'somelogin'
}
uut = new FullStackJWT(localConfig)
assert.fail('Unexpected code path')
console.log(uut) // For linting.
} catch (err) {
assert.include(
err.message,
'Must pass a FullStack.cash account password when instantiating FullStackJWT class.'
)
}
})
})
describe('#getJWT', () => {
it('should return the JWT token', async () => {
// Mock dependencies to force a code path.
sandbox.stub(uut.jwtLib, 'register').resolves({})
uut.jwtLib.userData.apiToken = 'abc123'
sandbox.stub(uut.jwtLib, 'validateApiToken').resolves({ isValid: true })
const result = await uut.getJWT()
// console.log('result: ', result)
assert.equal(result, 'abc123')
})
it('should catch and throw an error', async () => {
try {
// Force an error
sandbox.stub(uut.jwtLib, 'register').rejects(new Error('test error'))
await uut.getJWT()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(err.message, 'test error')
}
})
it('should throw an error if user does not have a JWT', async () => {
try {
// Mock dependencies to force a code path.
sandbox.stub(uut.jwtLib, 'register').resolves({})
await uut.getJWT()
assert.fail('Unexpected code path')
} catch (err) {
// console.log('err.message: ', err.message)
assert.include(err.message, 'This account does not have a JWT')
}
})
it('should retrieve a new JWT token if the old one invalid', async () => {
// Mock dependencies to force a code path.
sandbox.stub(uut.jwtLib, 'register').resolves({})
uut.jwtLib.userData.apiToken = 'abc123'
uut.jwtLib.userData.apiLevel = 30
sandbox.stub(uut.jwtLib, 'validateApiToken').resolves({ isValid: false })
sandbox.stub(uut.jwtLib, 'getApiToken').resolves('xyz789')
const result = await uut.getJWT()
// console.log('result: ', result)
assert.equal(result, 'xyz789')
})
})
describe('#instanceBchjs', () => {
it('should return an instance of bch-js', () => {
const result = uut.instanceBchjs()
// console.log('result: ', result)
assert.property(result, 'restURL')
})
})
})
+41 -3
View File
@@ -15,7 +15,8 @@ describe('#IPFS', () => {
beforeEach(() => {
const ipfs = IPFSMock.create()
uut = new IPFSCoordAdapter({ ipfs })
const bchjs = {}
uut = new IPFSCoordAdapter({ ipfs, bchjs })
sandbox = sinon.createSandbox()
})
@@ -35,6 +36,20 @@ describe('#IPFS', () => {
)
}
})
it('should throw an error if bchjs instance is not included', () => {
try {
const ipfs = IPFSMock.create()
uut = new IPFSCoordAdapter({ ipfs })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of bch-js must be passed when instantiating ipfs-coord.'
)
}
})
})
describe('#start', () => {
@@ -47,10 +62,24 @@ describe('#IPFS', () => {
assert.equal(result, true)
})
it('should get the public IP address if this node is a Circuit Relay', async () => {
// Mock dependencies.
uut.IpfsCoord = IPFSCoordMock
sandbox.stub(uut.publicIp, 'v4').returns('123')
// Force Circuit Relay
uut.config.isCircuitRelay = true
const result = await uut.start()
// console.log('result: ', result)
assert.equal(result, true)
})
})
describe('#attachRPCRouter', () => {
it('should attached a router output', async () => {
it('should attach a router output', async () => {
// Mock dependencies
uut.ipfsCoord = {
privateLog: {},
@@ -58,6 +87,12 @@ describe('#IPFS', () => {
orbitdb: {
privateLog: {}
}
},
adapters: {
pubsub: {
privateLog: () => {
}
}
}
}
@@ -66,8 +101,11 @@ describe('#IPFS', () => {
uut.attachRPCRouter(router)
})
it('should throw an error if ipfs-coord has not been instantiated', () => {
it('should catch and throw an error', () => {
try {
// Force an error
delete uut.ipfsCoord.adapters
const router = console.log
uut.attachRPCRouter(router)
+38 -3
View File
@@ -4,6 +4,7 @@
const assert = require('chai').assert
const sinon = require('sinon')
const BCHJS = require('@psf/bch-js')
const IPFSLib = require('../../../src/adapters/ipfs')
const IPFSMock = require('../mocks/ipfs-mock')
@@ -12,9 +13,11 @@ const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
describe('#IPFS-adapter-index', () => {
let uut
let sandbox
let bchjs
beforeEach(() => {
uut = new IPFSLib()
bchjs = new BCHJS()
uut = new IPFSLib({ bchjs })
sandbox = sinon.createSandbox()
})
@@ -22,12 +25,26 @@ describe('#IPFS-adapter-index', () => {
afterEach(() => sandbox.restore())
describe('#start', () => {
it('should throw error if bch-js is not passed', async () => {
try {
await uut.start()
assert.fail('Unexpected code path.')
} catch (err) {
// console.log(err)
assert.include(
err.message,
'Instance of bch-js must be passed when instantiating IPFS adapter.'
)
}
})
it('should return a promise that resolves into an instance of IPFS.', async () => {
// Mock dependencies.
uut.ipfsAdapter = new IPFSMock()
uut.IpfsCoordAdapter = IPFSCoordMock
const result = await uut.start()
const result = await uut.start({ bchjs: {} })
assert.equal(result, true)
})
@@ -37,7 +54,7 @@ describe('#IPFS-adapter-index', () => {
// Force an error
sandbox.stub(uut.ipfsAdapter, 'start').rejects(new Error('test error'))
await uut.start()
await uut.start({ bchjs: {} })
assert.fail('Unexpected code path.')
} catch (err) {
@@ -45,5 +62,23 @@ describe('#IPFS-adapter-index', () => {
assert.include(err.message, 'test error')
}
})
it('should handle lock-file errors', async () => {
try {
// Force an error
sandbox
.stub(uut.ipfsAdapter, 'start')
.rejects(new Error('Lock already being held'))
// Prevent process from exiting
sandbox.stub(uut.process, 'exit').returns()
await uut.start({ bchjs })
assert.fail('Unexpected code path.')
} catch (err) {
assert.include(err.message, 'Lock already being held')
}
})
})
})
+34
View File
@@ -47,4 +47,38 @@ describe('#IPFS-adapter', () => {
}
})
})
describe('#stop', () => {
it('should stop the IPFS node', async () => {
// Mock dependencies
uut.ipfs = {
stop: () => {}
}
const result = await uut.stop()
assert.equal(result, true)
})
})
describe('#rmBlocksDir', () => {
it('should delete the /blocks directory', () => {
const result = uut.rmBlocksDir()
assert.equal(result, true)
})
it('should catch and throw an error', () => {
try {
// Force an error
sandbox.stub(uut.fs, 'rmdirSync').throws(new Error('test error'))
uut.rmBlocksDir()
assert.fail('Unexpected code path')
} catch (err) {
assert.equal(err.message, 'test error')
}
})
})
})
+20 -10
View File
@@ -1,30 +1,40 @@
// const assert = require('chai').assert
const {
notifyRotation,
outputToConsole
} = require('../../../src/adapters/wlogger')
const assert = require('chai').assert
const { Wlogger } = require('../../../src/adapters/wlogger')
const sinon = require('sinon')
// let uut
let uut
let sandbox
describe('#wlogger.js', () => {
describe('#wlogger', () => {
beforeEach(() => {
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
afterEach(() => {
sandbox.restore()
uut = new Wlogger()
})
describe('#constructor', () => {
it('should create a new wlogger instance', () => {
uut = new Wlogger()
// console.log('uut: ', uut)
assert.property(uut, 'transport')
})
})
describe('#notifyRotation', () => {
it('should notify of a log rotation', () => {
notifyRotation()
uut.notifyRotation()
})
})
describe('#envronment', () => {
it('should write to console in non-test environment', () => {
outputToConsole()
uut.outputToConsole()
})
})
})
+34 -8
View File
@@ -3,27 +3,33 @@
*/
// Public npm libraries
// const assert = require('chai').assert
const assert = require('chai').assert
const sinon = require('sinon')
const adapters = require('../../../src/adapters')
const { attachControllers } = require('../../../src/controllers')
const Controllers = require('../../../src/controllers')
describe('#Controllers', () => {
// let uut
let uut
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
uut = new Controllers()
})
afterEach(() => sandbox.restore())
describe('#attachControllers', () => {
it('should attach the controllers', async () => {
// mock IPFS
sandbox.stub(adapters.ipfs, 'start').resolves({})
adapters.ipfs.ipfsCoordAdapter = {
// mock dependencies
// sandbox.stub(adapters.fullStackJwt, 'getJWT').resolves({})
// sandbox.stub(adapters.fullStackJwt, 'instanceBchjs').resolves({})
// sandbox.stub(adapters.ipfs, 'start').resolves({})
// adapters.ipfs.ipfsCoordAdapter = {
sandbox.stub(uut.adapters, 'start').resolves({})
uut.adapters.ipfs.ipfsCoordAdapter = {
attachRPCRouter: () => {}
}
@@ -31,7 +37,27 @@ describe('#Controllers', () => {
use: () => {}
}
await attachControllers(app)
await uut.attachControllers(app)
assert.isOk(true, 'Not throwing an error is a success')
})
it('should catch and throw errors', async () => {
try {
// Force an error
sandbox.stub(uut.adapters, 'start').rejects(new Error('test error'))
const app = {
use: () => {}
}
await uut.attachControllers(app)
assert.fail('Unexpected code path')
} catch (err) {
// console.log('err.message: ', err.message)
assert.include(err.message, 'test error')
}
})
})
})
@@ -61,15 +61,15 @@ describe('#BCHRPC', () => {
})
describe('#bchRouter', () => {
it('should route to the transactions method', async () => {
it('should route to the txHistory method', async () => {
// Mock dependencies
sandbox.stub(uut, 'transactions').resolves(true)
sandbox.stub(uut, 'txHistory').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const txCall = jsonrpc.request(id, 'bch', {
endpoint: 'transactions'
endpoint: 'txHistory'
})
const jsonStr = JSON.stringify(txCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
@@ -137,15 +137,34 @@ describe('#BCHRPC', () => {
assert.equal(result, true)
})
it('should route to the transaction method', async () => {
it('should route to the txData method', async () => {
// Mock dependencies
sandbox.stub(uut, 'transaction').resolves(true)
sandbox.stub(uut, 'txData').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'transaction'
endpoint: 'txData'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
rpcData.from = 'Origin request'
const result = await uut.bchRouter(rpcData)
assert.equal(result, true)
})
it('should route to the pubkey method', async () => {
// Mock dependencies
sandbox.stub(uut, 'pubKey').resolves(true)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'pubkey'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
@@ -158,13 +177,13 @@ describe('#BCHRPC', () => {
it('should return 500 status on routing issue', async () => {
// Mock dependencies
sandbox.stub(uut, 'transactions').rejects(new Error('test error'))
sandbox.stub(uut, 'txHistory').rejects(new Error('test error'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const txCall = jsonrpc.request(id, 'bch', {
endpoint: 'transactions'
endpoint: 'txHistory'
})
const jsonStr = JSON.stringify(txCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
@@ -175,29 +194,24 @@ describe('#BCHRPC', () => {
assert.equal(result.success, false)
assert.equal(result.status, 500)
assert.equal(result.message, 'test error')
assert.equal(result.endpoint, 'transactions')
assert.equal(result.endpoint, 'txHistory')
})
})
describe('#transactions', () => {
describe('#txHistory', () => {
it('should return data from bchjs', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.Electrumx, 'transactions')
.resolves({ success: true })
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const txCall = jsonrpc.request(id, 'bch', {
endpoint: 'transactions',
endpoint: 'txHistory',
addresses: 'testAddr'
})
const jsonStr = JSON.stringify(txCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.transactions(rpcData)
// console.log('response: ', response)
const response = await uut.txHistory(rpcData)
console.log('response: ', response)
assert.equal(response.success, true)
assert.equal(response.status, 200)
@@ -206,26 +220,26 @@ describe('#BCHRPC', () => {
it('should return an error for invalid address', async () => {
// Force an error
sandbox
.stub(uut.bchjs.Electrumx, 'transactions')
.stub(uut.useCases.bch, 'getTransactions')
.rejects(new Error('Invalid address'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const txCall = jsonrpc.request(id, 'bch', {
endpoint: 'transactions',
endpoint: 'txHistory',
addresses: 'testAddr'
})
const jsonStr = JSON.stringify(txCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.transactions(rpcData)
const response = await uut.txHistory(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'Invalid address')
assert.equal(response.endpoint, 'transactions')
assert.equal(response.endpoint, 'txHistory')
})
})
@@ -373,22 +387,19 @@ describe('#BCHRPC', () => {
})
})
describe('#transaction', () => {
it('should return data from bchjs', async () => {
// Mock dependencies
sandbox.stub(uut.bchjs.Transaction, 'get').resolves({ success: true })
describe('#txData', () => {
it('should route data to the use-case library', async () => {
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'transaction',
endpoint: 'txData',
txid: 'testData'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.transaction(rpcData)
const response = await uut.txData(rpcData)
// console.log('response: ', response)
assert.equal(response.success, true)
@@ -398,26 +409,108 @@ describe('#BCHRPC', () => {
it('should return an error for invalid input', async () => {
// Force an error
sandbox
.stub(uut.bchjs.Transaction, 'get')
.stub(uut.useCases.bch, 'getTxData')
.rejects(new Error('Invalid data'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'transaction',
endpoint: 'txData',
txid: 'testTxid'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.transaction(rpcData)
const response = await uut.txData(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'Invalid data')
assert.equal(response.endpoint, 'transaction')
assert.equal(response.endpoint, 'txData')
})
})
describe('#pubKey', () => {
it('should return data from bchjs', async () => {
// Mock dependencies
const mock = {
success: true,
publicKey:
'033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee'
}
sandbox.stub(uut.bchjs.encryption, 'getPubKey').resolves(mock)
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'pubkey',
address: 'bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.pubKey(rpcData)
assert.equal(response.success, true)
assert.equal(response.status, 200)
assert.property(response, 'pubkey')
const pubKey = response.pubkey
assert.property(pubKey, 'publicKey')
assert.equal(pubKey.publicKey, mock.publicKey)
})
it('should throw an error if public key is not found', async () => {
// Force an error
sandbox
.stub(uut.bchjs.encryption, 'getPubKey')
.rejects({ success: false, error: 'No transaction history.' })
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'pubkey',
address: 'bitcoincash:qrnx7l2e6yejgswehf54gs30ljzumnhqdqgn8yscr2'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.pubKey(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'No transaction history.')
assert.equal(response.endpoint, 'pubkey')
})
it('should return an error for invalid input', async () => {
// Force an error
sandbox
.stub(uut.bchjs.encryption, 'getPubKey')
.rejects(new Error('Invalid data'))
// Generate the parsed data that the main router would pass to this
// endpoint.
const id = uid()
const rpcCall = jsonrpc.request(id, 'bch', {
endpoint: 'pubkey',
address: 'bitcoincash'
})
const jsonStr = JSON.stringify(rpcCall, null, 2)
const rpcData = jsonrpc.parse(jsonStr)
const response = await uut.pubKey(rpcData)
// console.log('response: ', response)
assert.equal(response.success, false)
assert.equal(response.status, 422)
assert.equal(response.message, 'Invalid data')
assert.equal(response.endpoint, 'pubkey')
})
})
})
@@ -207,5 +207,120 @@ describe('#JSON RPC', () => {
assert.equal(obj.result.method, 'bch')
assert.equal(obj.id, id)
})
it('should exit quietly for duplicate RPC message', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Call router once.
await uut.router(str, 'peerA')
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
assert.equal(result, false)
})
it('should ignore metric queries from ipfs-coord', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Force the RPC type to be 'success', to indicate an RPC that was
// processed internal to ipfs-coord.
sandbox.stub(uut.jsonrpc, 'parse').returns({
payload: {},
type: 'success'
})
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
assert.equal(result, false)
})
it('should report errors when trying to send messages to peers', async () => {
const id = uid()
const json = jsonrpc.request(id, 'unknownMethod', {})
const str = JSON.stringify(json)
// Force issue with sendPrivateMessage()
sandbox
.stub(uut.ipfsCoord.useCases.peer, 'sendPrivateMessage')
.rejects('test error')
// Call the router again with the same input.
const result = await uut.router(str, 'peerA')
// console.log('result: ', result)
assert.property(result, 'from')
assert.property(result, 'retStr')
})
})
describe('#_checkIfAlreadyProcessed', () => {
it('should return false the first time an RPC command is seen', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, false)
})
it('should return true the second time an RPC command is seen', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
// First call.
uut._checkIfAlreadyProcessed(data)
// Second call.
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, true)
})
it('should push out old data from the cache for new data', () => {
const data = {
payload: {
jsonrpc: '2.0',
id: '6c515f3c-cf8a-42ec-870e-e416edd4923f',
method: 'unknownMethod',
params: {}
},
type: 'request'
}
uut.MSG_CACHE_SIZE = 0
const result = uut._checkIfAlreadyProcessed(data)
assert.equal(result, false)
})
it('should return true on error', () => {
const result = uut._checkIfAlreadyProcessed()
assert.equal(result, true)
})
})
})
@@ -233,6 +233,56 @@ describe('#BCH-REST-Router', () => {
})
})
describe('#pubKey', () => {
it('should return data from bchjs', async () => {
// Mock dependencies
const mock = { success: true, publicKey: '033f267fec0f7eb2b27f8c2e3052b3d03b09d36b47de4082ffb638ffb334ef0eee' }
sandbox.stub(uut.bchjs.encryption, 'getPubKey').resolves(mock)
ctx.params = {
address: 'bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk'
}
await uut.pubKey(ctx)
// console.log('ctx.body: ', ctx.body)
assert.equal(ctx.body.success, true)
assert.equal(ctx.body.publicKey, mock.publicKey)
})
it('should throw an error if public key is not found', async () => {
try {
// Force an error
sandbox
.stub(uut.bchjs.encryption, 'getPubKey')
.rejects({ success: false, error: 'No transaction history.' })
ctx.params = {
address: 'bitcoincash:qrnx7l2e6yejgswehf54gs30ljzumnhqdqgn8yscr2'
}
await uut.pubKey(ctx)
} catch (err) {
// console.log('err: ', err)
assert.include(err.message, 'No transaction history')
}
})
it('should catch and throw an error', async () => {
try {
// Force an error
sandbox
.stub(uut.bchjs.encryption, 'getPubKey')
.rejects(new Error('test error'))
ctx.params = {
address: 'bitcoincash:qpnty9t0w93fez04h7yzevujpv8pun204qv6yfuahk'
}
await uut.pubKey(ctx)
} catch (err) {
// console.log('err: ', err)
assert.include(err.message, 'test error')
}
})
})
describe('#handleError', () => {
it('should pass an error message', () => {
try {
+31 -2
View File
@@ -7,7 +7,13 @@ const ipfs = {
ipfs: {}
},
ipfsCoordAdapter: {
ipfsCoord: {}
ipfsCoord: {
useCases: {
peer: {
sendPrivateMessage: () => {}
}
}
}
}
}
@@ -47,4 +53,27 @@ const localdb = {
}
}
module.exports = { ipfs, localdb }
const bchjs = {
Electrumx: {
transactions: () => {},
balance: () => {},
sortAllTxs: () => {}
},
Utxo: {
get: () => {}
},
Transaction: {
get: () => {}
},
RawTransactions: {
sendRawTransaction: () => {}
},
encryption: {
getPubKey: () => {}
},
Util: {
chunk100: () => {}
}
}
module.exports = { ipfs, localdb, bchjs }
+6
View File
@@ -3,6 +3,12 @@
*/
class IPFSCoord {
constructor () {
this.ipfs = {
async start () {}
}
}
async isReady () {
return true
}
@@ -0,0 +1,94 @@
/*
Mock data for use-cases/bch/index.js unit tests
*/
const fulcrumOut01 = {
success: true,
transactions: [
{
transactions: [
{
height: 560430,
tx_hash:
'3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851'
},
{
height: 560534,
tx_hash:
'4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280'
}
],
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
}
]
}
const txData01 = {
txData: {
txid: '11384d7e5a8af93806591debe5bbe2d7826aeea987b874dfbe372dfdcc0ee54f',
hash: '11384d7e5a8af93806591debe5bbe2d7826aeea987b874dfbe372dfdcc0ee54f',
version: 1,
size: 371,
locktime: 0,
vin: [
{
txid: 'c4f3e3d6f146f1d54bd5c22cad6b189637b44a655b057cd0303d85558c033594',
vout: 310,
scriptSig: {
asm: '304402200d40ad599c7e33c7f5245080c0ea35c837c0d142b82eb6824fceaf049c2a355902200590e35951111f6c603c0fb4e513cf0e47734d7bc8b45f105585bea0f2b923de[ALL|FORKID] 0352ede8ab8f2ae49b3921c385e59f700ae1e6f73cbb37f61cd1244e70c99bf496',
hex: '47304402200d40ad599c7e33c7f5245080c0ea35c837c0d142b82eb6824fceaf049c2a355902200590e35951111f6c603c0fb4e513cf0e47734d7bc8b45f105585bea0f2b923de41210352ede8ab8f2ae49b3921c385e59f700ae1e6f73cbb37f61cd1244e70c99bf496'
},
sequence: 4294967295,
address: 'bitcoincash:qzgkqac0tlrfsajg2f7e4e8nyh3glmn4s523tysd6r',
value: 0.08809511
},
{
txid: 'c32265f89b2d5d1d5ffd5212b3245105d7d0ba726306fbeb93cd866ce0fd2d61',
vout: 1,
scriptSig: {
asm: '3045022100be9cc5e982110b0f563460baa19a42f34ab775708ad3461a6cf065db9dffb1b7022031ffb2721828be4aa1f4967a367e8af2848cdfce41c68565d0a2a2a70117ea5d[ALL|FORKID] 02d2eabc002e25fc08622a71d9ef96c17b21176f438d67bc537ac49a2e0e594372',
hex: '483045022100be9cc5e982110b0f563460baa19a42f34ab775708ad3461a6cf065db9dffb1b7022031ffb2721828be4aa1f4967a367e8af2848cdfce41c68565d0a2a2a70117ea5d412102d2eabc002e25fc08622a71d9ef96c17b21176f438d67bc537ac49a2e0e594372'
},
sequence: 4294967295,
address: 'bitcoincash:qr92r3ms2696ghpmk9467px90jrzzdesy5fmqc05p3',
value: 0.00011805
}
],
vout: [
{
value: 0.0814,
n: 0,
scriptPubKey: {
asm: 'OP_HASH160 84459c796307fe2c0316ce7a8bffc511c27bcd55 OP_EQUAL',
hex: 'a91484459c796307fe2c0316ce7a8bffc511c27bcd5587',
reqSigs: 1,
type: 'scripthash',
addresses: ['bitcoincash:pzzyt8revvrlutqrzm884zllc5guy77d2545uyqe8h']
}
},
{
value: 0.00680944,
n: 1,
scriptPubKey: {
asm: 'OP_DUP OP_HASH160 aab2f091ea97e02c58c4e27fb77afb99538ea39e OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914aab2f091ea97e02c58c4e27fb77afb99538ea39e88ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qz4t9uy3a2t7qtzccn38ldm6lwv48r4rnc9mxdtvt9']
}
}
],
hex: '01000000029435038c55853d30d07c055b654ab43796186bad2cc2d54bd5f146f1d6e3f3c4360100006a47304402200d40ad599c7e33c7f5245080c0ea35c837c0d142b82eb6824fceaf049c2a355902200590e35951111f6c603c0fb4e513cf0e47734d7bc8b45f105585bea0f2b923de41210352ede8ab8f2ae49b3921c385e59f700ae1e6f73cbb37f61cd1244e70c99bf496ffffffff612dfde06c86cd93ebfb066372bad0d7055124b31252fd5f1d5d2d9bf86522c3010000006b483045022100be9cc5e982110b0f563460baa19a42f34ab775708ad3461a6cf065db9dffb1b7022031ffb2721828be4aa1f4967a367e8af2848cdfce41c68565d0a2a2a70117ea5d412102d2eabc002e25fc08622a71d9ef96c17b21176f438d67bc537ac49a2e0e594372ffffffff02e0347c000000000017a91484459c796307fe2c0316ce7a8bffc511c27bcd5587f0630a00000000001976a914aab2f091ea97e02c58c4e27fb77afb99538ea39e88ac00000000',
blockhash:
'000000000000000001e8e99be82172d5fe913e21f5a78e4e3bdce2c7dc6315ce',
confirmations: 94517,
time: 1586584650,
blocktime: 1586584650,
isValidSlp: false
}
}
module.exports = {
fulcrumOut01,
txData01
}
+17
View File
@@ -31,12 +31,29 @@ class UserUseCaseMock {
}
}
class BCH {
async getTransactions(rpcData) {
return {
success: true,
status: 200
}
}
async getTxData(rpcData) {
return {
success: true,
status: 200
}
}
}
class UseCasesMock {
constuctor(localConfig = {}) {
// this.user = new UserUseCaseMock(localConfig)
}
user = new UserUseCaseMock()
bch = new BCH()
}
module.exports = UseCasesMock
@@ -0,0 +1,215 @@
/*
Unit tests for the BCH Use Cases
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
const clone = require('lodash.clonedeep')
// Local support libraries
const BCHUseCases = require('../../../../src/use-cases/bch')
const adapters = require('../../mocks/adapters')
const mockDataLib = require('../../mocks/use-cases/bch/bch.use-cases.mocks.js')
describe('#bch-use-case', () => {
let uut
let sandbox
let mockData
beforeEach(() => {
sandbox = sinon.createSandbox()
mockData = clone(mockDataLib)
uut = new BCHUseCases({ adapters })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new BCHUseCases()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of adapters must be passed in when instantiating BCH Use Cases library.'
)
}
})
})
describe('#getTransactions', () => {
it('should get transactions for an address', async () => {
// Mock dependencies
sandbox
.stub(uut.bchjs.Electrumx, 'transactions')
.resolves(mockData.fulcrumOut01)
sandbox
.stub(uut.bchjs.Electrumx, 'sortAllTxs')
.resolves(mockData.fulcrumOut01.transactions[0].transactions)
sandbox
.stub(uut.bchjs.Util, 'chunk100')
.returns([mockData.fulcrumOut01.transactions[0].transactions])
const address = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
const rpcData = {
payload: {
params: {
address
}
}
}
const result = await uut.getTransactions(rpcData)
// console.log('result: ', result)
// Assert expected values and properties.
assert.equal(result.address, address)
assert.equal(result.status, 200)
assert.equal(result.success, true)
assert.isArray(result.txs)
})
it('should return error if Fulcrum communication is not possible', async () => {
// Force an error
sandbox
.stub(uut.bchjs.Electrumx, 'transactions')
.resolves({ success: false })
const address = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
const rpcData = {
payload: {
params: {
address
}
}
}
const result = await uut.getTransactions(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.message, 'Could not query Fulcrum indexer.')
assert.equal(result.endpoint, 'txHistory')
})
it('should return error if there is an error', async () => {
// Force an error
sandbox
.stub(uut.bchjs.Electrumx, 'transactions')
.rejects(new Error('test error'))
const address = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
const rpcData = {
payload: {
params: {
address
}
}
}
const result = await uut.getTransactions(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.message, 'test error')
assert.equal(result.endpoint, 'txHistory')
})
})
describe('#getTxData', () => {
it('should get tx data', async () => {
// Mock dependencies
sandbox.stub(uut.bchjs.Transaction, 'get').resolves(mockData.txData01)
const rpcData = {
payload: {
params: {
txids: [
'11384d7e5a8af93806591debe5bbe2d7826aeea987b874dfbe372dfdcc0ee54f'
]
}
}
}
const result = await uut.getTxData(rpcData)
// console.log('result: ', result)
assert.equal(result.status, 200)
assert.isArray(result.txData)
})
it('should return error if txids is not an array', async () => {
const rpcData = {
payload: {
params: {
txids: 1234
}
}
}
const result = await uut.getTxData(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.endpoint, 'txData')
assert.equal(
result.message,
'Input txids must be an array of transaction IDs.'
)
})
it('should return error if txids array has more than 20 elements', async () => {
const rpcData = {
payload: {
params: {
txids: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25
]
}
}
}
const result = await uut.getTxData(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.endpoint, 'txData')
assert.equal(result.message, 'Array input must be 20 elements or less.')
})
it('should handle errors', async () => {
// Force an error
sandbox
.stub(uut.bchjs.Transaction, 'get')
.rejects(new Error('test error'))
const rpcData = {
payload: {
params: {
txids: [
'11384d7e5a8af93806591debe5bbe2d7826aeea987b874dfbe372dfdcc0ee54f'
]
}
}
}
const result = await uut.getTxData(rpcData)
// console.log('result: ', result)
assert.equal(result.success, false)
assert.equal(result.status, 422)
assert.equal(result.endpoint, 'txData')
assert.equal(result.message, 'test error')
})
})
})
@@ -7,9 +7,6 @@ const assert = require('chai').assert
const sinon = require('sinon')
// Local support libraries
// const testUtils = require('../../utils/test-utils')
// Unit under test (uut)
const UseCases = require('../../../src/use-cases')
const adapters = require('../mocks/adapters')
+1 -4
View File
@@ -9,9 +9,6 @@ const assert = require('chai').assert
const sinon = require('sinon')
// Local support libraries
// const testUtils = require('../../utils/test-utils')
// Unit under test (uut)
const UserLib = require('../../../src/use-cases/user')
const adapters = require('../mocks/adapters')
@@ -57,7 +54,7 @@ describe('#users-use-case', () => {
} catch (err) {
// console.log(err)
// assert.equal(err.status, 422)
assert.include(err.message, 'Cannot read property')
assert.include(err.message, "Property 'email' must be a string!")
}
})