Compare commits

..
27 Commits
Author SHA1 Message Date
Chris Troutner 63e8078681 Merge pull request #52 from Permissionless-Software-Foundation/ct-unstable
feat(rate limits): Bumping anonymous rate limits to 20 RPM
2020-11-08 08:18:36 -08:00
Chris Troutner 821f908fdb feat(rate limits): Bumping anonymous rate limits to 20 RPM 2020-11-08 08:07:16 -08:00
Chris Troutner 9d5a0d9520 Merge pull request #51 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2020-11-08 07:20:46 -08:00
Chris Troutner f146504ed0 Merge branch 'master' into ct-unstable 2020-11-08 07:17:40 -08:00
Chris Troutner 03a4eb1b72 Debugging deployment from CI 2020-11-08 07:17:30 -08:00
Chris Troutner 6286b4967b Merge pull request #50 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2020-11-08 07:10:36 -08:00
Chris Troutner 6bf86b29f8 Merge branch 'master' into ct-unstable 2020-11-08 07:09:18 -08:00
Chris Troutner 0b180e02a4 Debugging deployment from CI 2020-11-08 07:09:08 -08:00
Chris Troutner a2267c9590 Merge pull request #49 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2020-11-07 22:01:41 -08:00
Chris Troutner ed83f5eb3f Merge branch 'master' into ct-unstable 2020-11-07 21:59:36 -08:00
Chris Troutner 91e5423dd2 Debugging deployment from CI 2020-11-07 21:59:20 -08:00
Chris Troutner de4cb8762a Merge pull request #48 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2020-11-07 21:52:34 -08:00
Chris Troutner 284e9a9ee7 Merge branch 'master' into ct-unstable 2020-11-07 21:50:47 -08:00
Chris Troutner ec2fb8e24f testing ci 2020-11-07 21:50:34 -08:00
Chris Troutner 07fc05fa12 Merge pull request #47 from Permissionless-Software-Foundation/ct-unstable
testing ci
2020-11-07 21:37:12 -08:00
Chris Troutner 2bfad5d261 testing ci 2020-11-07 21:34:04 -08:00
Chris Troutner efe4cad08b Merge pull request #46 from Permissionless-Software-Foundation/ct-unstable
testing ci
2020-11-07 21:27:30 -08:00
Chris Troutner b704707ded Merge branch 'master' into ct-unstable 2020-11-07 21:26:00 -08:00
Chris Troutner 6c8a156f37 testing ci 2020-11-07 21:24:45 -08:00
Chris Troutner 19d9153629 Merge pull request #45 from Permissionless-Software-Foundation/ct-unstable
Switching CI from Travis to Jenkins
2020-11-07 21:10:20 -08:00
Chris Troutner 840e92e54c testing ci 2020-11-07 21:00:05 -08:00
Chris Troutner 8e4592826f Testing CI 2020-11-07 20:47:38 -08:00
Chris Troutner c4085fb929 Updating deploy script for Jenkins 2020-11-07 20:40:06 -08:00
Chris Troutner 00e1840ca2 Updating gitignore 2020-11-07 19:42:58 -08:00
Chris Troutner 7e9a9bc635 update to gitignore 2020-11-07 18:34:38 -08:00
Chris Troutner 41163096e3 Merge pull request #44 from Permissionless-Software-Foundation/ct-unstable
fix(raw transactions): Updating for change in output of abc full node
2020-10-31 10:14:19 -07:00
Chris Troutner 1b3e1cc293 fix(raw transactions): Updating for change in output of abc full node 2020-10-31 10:11:44 -07:00
5 changed files with 65 additions and 36 deletions
+4
View File
@@ -21,6 +21,10 @@ start-local-mainnet.sh.save
start-local-testnet.sh.save start-local-testnet.sh.save
temp.sh temp.sh
test-fullstack-test.sh test-fullstack-test.sh
start-sweet-main.sh
test-sweet-main.sh
test-fullstack-abc.sh
test-fullstack-bchn.sh
coverage coverage
start-my-infra start-my-infra
+18 -9
View File
@@ -1,17 +1,26 @@
#!/bin/bash
# Triggers a webhook to update the staging server at staging.fullstack.cash. # Triggers a webhook to update the staging server at staging.fullstack.cash.
#!/bin/bash
#echo $DEPLOY_SECRET #echo $DEPLOY_SECRET
echo "Deploy to production...." # This if statement will only deploy on Jenkins when its testing the master branch.
echo "-->$GIT_BRANCH<--"
if [[ $GIT_BRANCH =~ "master" ]]
then
export DATA="{\"ref\":\"$DEPLOY_SECRET\"}" echo "Deploying to production...."
#echo $DATA export DATA="{\"ref\":\"$DEPLOY_SECRET\"}"
curl -X POST http://fullstack.cash:9000/hooks/bch-api-mainnet -H "Content-Type: application/json" -d $DATA #echo $DATA
curl -X POST http://fullstack.cash:9000/hooks/bch-api-testnet -H "Content-Type: application/json" -d $DATA
curl -X POST http://$FREE_SERVER:9000/hooks/bch-api-testnet -H "Content-Type: application/json" -d $DATA
curl -X POST http://$FREE_SERVER:9000/hooks/bch-api-mainnet -H "Content-Type: application/json" -d $DATA
echo "...Finished deploying to production." curl -X POST http://fullstack.cash:9000/hooks/bch-api-mainnet -H "Content-Type: application/json" -d $DATA
curl -X POST http://fullstack.cash:9000/hooks/bch-api-testnet -H "Content-Type: application/json" -d $DATA
curl -X POST http://$FREE_SERVER:9000/hooks/bch-api-testnet -H "Content-Type: application/json" -d $DATA
curl -X POST http://$FREE_SERVER:9000/hooks/bch-api-mainnet -H "Content-Type: application/json" -d $DATA
echo "...Finished deploying to production."
else
echo "Not master, so not deploying."
fi
+23 -8
View File
@@ -1,3 +1,15 @@
/*
Sets the rate limits for the anonymous and paid tiers. Current rate limits:
- 1000 points in 60 seconds
- 10 points per call for paid tier (100 RPM)
- 50 points per call for anonymous tier (20 RPM)
Background:
The rate limits below were originially coded with the idea of charging on a
per-resource basis. However, that was confusing to end users trying to purchase
a subscription. So everything was simplied to two tiers: paid and anonymous
*/
'use strict' 'use strict'
const wlogger = require('../util/winston-logging') const wlogger = require('../util/winston-logging')
@@ -98,8 +110,8 @@ class RateLimits {
wlogger.debug('No JWT token found!') wlogger.debug('No JWT token found!')
} }
// Used for displaying error message. Default value is 30. // Default value is 50 points per request = 20 RPM
let rateLimit = 30 let rateLimit = 50
// Code here for the rate limiter is adapted from this example: // Code here for the rate limiter is adapted from this example:
// https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#authorized-and-not-authorized-users // https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#authorized-and-not-authorized-users
@@ -118,9 +130,12 @@ class RateLimits {
// Retrieve the origin. // Retrieve the origin.
let origin = req.get('origin') let origin = req.get('origin')
// Handle calls coming from the intranet.
if (origin === undefined && key.indexOf('10.0.0.5') > -1) { if (origin === undefined && key.indexOf('10.0.0.5') > -1) {
origin = 'slp-api' origin = 'slp-api'
} }
wlogger.info(`origin: ${origin}`) wlogger.info(`origin: ${origin}`)
// If the request originates from one of the approved wallet apps, then // If the request originates from one of the approved wallet apps, then
@@ -135,7 +150,7 @@ class RateLimits {
res.locals.pointsToConsume = pointsToConsume // Feedback for tests. res.locals.pointsToConsume = pointsToConsume // Feedback for tests.
} }
// Apply paid-access rate limits based on key/IP // For internal calls, increase rate limits to as fast as possible.
if ( if (
key.toString().indexOf('172.17.') > -1 || key.toString().indexOf('172.17.') > -1 ||
key.toString().indexOf('::ffff:127.0.0.1') > -1 key.toString().indexOf('::ffff:127.0.0.1') > -1
@@ -178,7 +193,7 @@ class RateLimits {
// Calculates the points consumed, based on the jwt information and the route // Calculates the points consumed, based on the jwt information and the route
// requested. // requested.
calcPoints (jwtInfo) { calcPoints (jwtInfo) {
let retVal = 300 // By default, use anonymous tier. let retVal = 50 // By default, use anonymous tier.
try { try {
// console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`) // console.log(`jwtInfo: ${JSON.stringify(jwtInfo, null, 2)}`)
@@ -197,12 +212,12 @@ class RateLimits {
if (level40Routes.includes(resource)) { if (level40Routes.includes(resource)) {
if (apiLevel >= 40) retVal = 10 if (apiLevel >= 40) retVal = 10
// else if (apiLevel >= 10) retVal = 10 // else if (apiLevel >= 10) retVal = 10
else retVal = 100 else retVal = 50
// Normal indexer routes // Normal indexer routes
} else if (level30Routes.includes(resource)) { } else if (level30Routes.includes(resource)) {
if (apiLevel >= 30) retVal = 10 if (apiLevel >= 30) retVal = 10
else retVal = 100 else retVal = 50
// Full node tier // Full node tier
} else if (apiLevel >= 20) { } else if (apiLevel >= 20) {
@@ -210,7 +225,7 @@ class RateLimits {
// Free tier, full node only. // Free tier, full node only.
} else { } else {
retVal = 100 retVal = 50
} }
} }
@@ -218,7 +233,7 @@ class RateLimits {
} catch (err) { } catch (err) {
wlogger.error('Error in route-ratelimit.js/calcPoints()') wlogger.error('Error in route-ratelimit.js/calcPoints()')
// throw err // throw err
retVal = 300 retVal = 50
} }
return retVal return retVal
+17 -17
View File
@@ -105,14 +105,14 @@ describe('#route-ratelimits & jwt-auth', () => {
}) })
describe('#calcPoints', () => { describe('#calcPoints', () => {
it('should return 300 points for anonymous user', () => { it('should return 50 points for anonymous user', () => {
const result = rateLimits.calcPoints() const result = rateLimits.calcPoints()
// console.log(`result: ${result}`) // console.log(`result: ${result}`)
assert.equal(result, 300) assert.equal(result, 50)
}) })
it('should return 100 points for free tier requesting full node access', () => { it('should return 50 points for free tier requesting full node access', () => {
const jwtInfo = { const jwtInfo = {
apiLevel: 10, apiLevel: 10,
resource: 'blockchain', resource: 'blockchain',
@@ -120,10 +120,10 @@ describe('#route-ratelimits & jwt-auth', () => {
} }
const result = rateLimits.calcPoints(jwtInfo) const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 100) assert.equal(result, 50)
}) })
it('should return 100 points for free tier requesting indexer access', () => { it('should return 50 points for free tier requesting indexer access', () => {
const jwtInfo = { const jwtInfo = {
apiLevel: 10, apiLevel: 10,
resource: 'blockbook', resource: 'blockbook',
@@ -131,10 +131,10 @@ describe('#route-ratelimits & jwt-auth', () => {
} }
const result = rateLimits.calcPoints(jwtInfo) const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 100) assert.equal(result, 50)
}) })
it('should return 100 points for free tier requesting SLPDB access', () => { it('should return 50 points for free tier requesting SLPDB access', () => {
const jwtInfo = { const jwtInfo = {
apiLevel: 10, apiLevel: 10,
resource: 'slp', resource: 'slp',
@@ -142,7 +142,7 @@ describe('#route-ratelimits & jwt-auth', () => {
} }
const result = rateLimits.calcPoints(jwtInfo) const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 100) assert.equal(result, 50)
}) })
it('should return 10 points for full node tier requesting full node access', () => { it('should return 10 points for full node tier requesting full node access', () => {
@@ -156,7 +156,7 @@ describe('#route-ratelimits & jwt-auth', () => {
assert.equal(result, 10) assert.equal(result, 10)
}) })
it('should return 100 points for full-node tier requesting indexer access', () => { it('should return 50 points for full-node tier requesting indexer access', () => {
const jwtInfo = { const jwtInfo = {
apiLevel: 20, apiLevel: 20,
resource: 'blockbook', resource: 'blockbook',
@@ -164,10 +164,10 @@ describe('#route-ratelimits & jwt-auth', () => {
} }
const result = rateLimits.calcPoints(jwtInfo) const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 100) assert.equal(result, 50)
}) })
it('should return 100 points for full node tier requesting SLPDB access', () => { it('should return 50 points for full node tier requesting SLPDB access', () => {
const jwtInfo = { const jwtInfo = {
apiLevel: 20, apiLevel: 20,
resource: 'slp', resource: 'slp',
@@ -175,7 +175,7 @@ describe('#route-ratelimits & jwt-auth', () => {
} }
const result = rateLimits.calcPoints(jwtInfo) const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 100) assert.equal(result, 50)
}) })
it('should return 10 point for indexer tier requesting full node access', () => { it('should return 10 point for indexer tier requesting full node access', () => {
@@ -200,7 +200,7 @@ describe('#route-ratelimits & jwt-auth', () => {
assert.equal(result, 10) assert.equal(result, 10)
}) })
it('should return 100 points for indexer tier requesting SLPDB access', () => { it('should return 50 points for indexer tier requesting SLPDB access', () => {
const jwtInfo = { const jwtInfo = {
apiLevel: 30, apiLevel: 30,
resource: 'slp', resource: 'slp',
@@ -208,7 +208,7 @@ describe('#route-ratelimits & jwt-auth', () => {
} }
const result = rateLimits.calcPoints(jwtInfo) const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 100) assert.equal(result, 50)
}) })
it('should return 10 point for SLP tier requesting full node access', () => { it('should return 10 point for SLP tier requesting full node access', () => {
@@ -319,7 +319,7 @@ describe('#route-ratelimits & jwt-auth', () => {
) )
}) })
it('should trigger rate-limit for free tier after 10 RPM', async () => { it('should trigger rate-limit for free tier after 20 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking. // Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits() rateLimits = new RateLimits()
@@ -338,7 +338,7 @@ describe('#route-ratelimits & jwt-auth', () => {
// Mock the call to the jwt library. // Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo) sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 12; i++) { for (let i = 0; i < 22; i++) {
next.reset() // reset the stubbed next() function. next.reset() // reset the stubbed next() function.
await rateLimits.rateLimitByResource(req, res, next) await rateLimits.rateLimitByResource(req, res, next)
@@ -442,7 +442,7 @@ describe('#route-ratelimits & jwt-auth', () => {
// Issues with token secret should treat incoming requests as anonymous // Issues with token secret should treat incoming requests as anonymous
// calls with 30 points or 3 RPM. // calls with 30 points or 3 RPM.
assert.equal(res.locals.pointsToConsume, 300) assert.equal(res.locals.pointsToConsume, 50)
}) })
}) })
}) })
+3 -2
View File
@@ -975,6 +975,7 @@ describe('#Raw-Transactions', () => {
// Restore the saved URL. // Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2 process.env.RPC_BASEURL = savedUrl2
}) })
it('should submit hex encoded transaction', async () => { it('should submit hex encoded transaction', async () => {
// This is a difficult test to run as transaction hex is invalid after a // This is a difficult test to run as transaction hex is invalid after a
// block confirmation. So the unit tests simulates what the output 'should' // block confirmation. So the unit tests simulates what the output 'should'
@@ -1004,7 +1005,7 @@ describe('#Raw-Transactions', () => {
// Integration test // Integration test
} else { } else {
assert.hasAllKeys(result, ['error']) assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Missing inputs') assert.include(result.error, 'bad-txns-inputs-missingorspent')
} }
}) })
}) })
@@ -1159,7 +1160,7 @@ describe('#Raw-Transactions', () => {
// Integration test // Integration test
} else { } else {
assert.hasAllKeys(result, ['error']) assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Missing inputs') assert.include(result.error, 'bad-txns-inputs-missingorspent')
} }
}) })
}) })