Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add block height in relevant adapters #215

Merged
merged 23 commits into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1f161ae
Added height(latest block number) as endpoint parameter on cryptoapis
ebarakos Jan 6, 2021
82403e8
Added height endpoint for blockchair
ebarakos Jan 7, 2021
bcc9b3d
Added block height on endpoint on cryptoid
ebarakos Jan 7, 2021
d318c39
Add similar (to other blockchain stats querying adapters) input param…
ebarakos Jan 7, 2021
516decf
Renamed endpoint to q. Added READMEs. Cleaned json-rpc.
ebarakos Jan 8, 2021
e368308
reverted q to endpoint
ebarakos Jan 8, 2021
ee7f445
removed process.env.API_KEY
ebarakos Jan 11, 2021
bff0669
reverted json-rpc, kept the directly changed implementation for refer…
ebarakos Jan 11, 2021
b48da1b
created composite adapter, no functionality added
ebarakos Jan 11, 2021
44625e5
Working version of composite bitcoin adapter
ebarakos Jan 11, 2021
c96cc1d
Removed old adapter, fixed dependencies and issues
ebarakos Jan 12, 2021
387db70
migrated cryptoid to TS
ebarakos Jan 12, 2021
af23c5e
Changed blockchair according to the new changes. Created stats instea…
ebarakos Jan 13, 2021
3d957cc
Changed cryptoapis difficulty to stats and added height, after TS mig…
ebarakos Jan 13, 2021
eeb81c8
fixed README
ebarakos Jan 13, 2021
edcff2a
reverted to simpler version of bitcoin-json-rpc + review changes
ebarakos Jan 15, 2021
6e70ec8
reviews changed + reverted tests
ebarakos Jan 15, 2021
a62df92
changed var name
ebarakos Jan 15, 2021
1ec7ed2
Review changes
ebarakos Jan 15, 2021
4ee780a
reverted yarn.lock to 'develop' version
ebarakos Jan 15, 2021
fbe88b2
review changes + updated README
ebarakos Jan 15, 2021
eaf3831
updated cryptoid README
ebarakos Jan 15, 2021
f2046a3
Update cryptoapis/README.md
krebernisak Jan 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/strategy/adapters.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@
"defi-pulse",
"dns-record-check",
"outlier-detection",
"crypto-volatility-index"
"crypto-volatility-index",
"bitcoin-json-rpc"
]
},
"synth-index": {
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- `paxos` to get Paxos asset supply attestations
- `outlier-detection`: composite adapter to check for outlier values between multiple sets of data providers
- `dydx-stark` to sign the input price data with your private STARK key, and send it to the destination endpoint.
- `bitcoin-json-rpc`: composite adapter for querying bitcoin blockchain stats(difficulty, height) according to the existing convention
- Added support for metadata in requests. This gives adapters access to the FM on-chain round state.
- Moves re-usable test behaviors & testing utils to a new package - `@chainlink/adapter-test-helpers`
- Added support for using query string parameters as input to adapters.
Expand Down
7 changes: 2 additions & 5 deletions blockchair/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ The adapter takes the following environment variables:

## Input Params

- `endpoint`: The endpoint to use, one of (difficulty|balance). Defaults to `difficulty`

### Difficulty endpoint

- `blockchain` or `coin`: The blockchain to get difficulty from
- `blockchain` or `coin`: The blockchain to get stats from
- `endpoint`: The parameter to query for. Default: "difficulty"

### Output

Expand Down
8 changes: 5 additions & 3 deletions blockchair/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Requester, Validator, AdapterError } from '@chainlink/external-adapter'
import { ExecuteWithConfig, ExecuteFactory, Config } from '@chainlink/types'
import { makeConfig, DEFAULT_ENDPOINT } from './config'
import { difficulty, balance } from './endpoint'
import { stats, balance } from './endpoint'

const inputParams = {
endpoint: false,
Expand All @@ -18,8 +18,10 @@ const execute: ExecuteWithConfig<Config> = async (request, config) => {
const endpoint = validator.validated.data.endpoint || DEFAULT_ENDPOINT

switch (endpoint) {
case difficulty.Name: {
return difficulty.execute(request, config)
// might be moved to validator or config
case 'difficulty':
case 'height': {
return stats.execute(request, config)
}
case balance.Name: {
return balance.makeExecute(config)(request)
Expand Down
2 changes: 1 addition & 1 deletion blockchair/src/endpoint/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * as balance from './balance'
export * as difficulty from './difficulty'
export * as stats from './stats'

export const COIN_KEYS = ['btc', 'dash', 'doge', 'ltc', 'bch'] as const
export type CoinType = typeof COIN_KEYS[number]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { Requester, Validator } from '@chainlink/external-adapter'
import { ExecuteWithConfig, Config } from '@chainlink/types'
import { COINS } from '.'
import { DEFAULT_ENDPOINT } from '../config'

export const Name = 'difficulty'
export const Name = 'stats'

const inputParams = {
blockchain: ['blockchain', 'coin'],
endpoint: false,
}

const convertEndpoint: { [key: string]: string } = {
height: 'blocks',
}

export const execute: ExecuteWithConfig<Config> = async (input, config) => {
const validator = new Validator(input, inputParams)
if (validator.error) throw validator.error
const jobRunID = validator.validated.id
let endpoint = validator.validated.data.endpoint || DEFAULT_ENDPOINT
if (endpoint in convertEndpoint) endpoint = convertEndpoint[endpoint]
krebernisak marked this conversation as resolved.
Show resolved Hide resolved

const blockchain = Requester.toVendorName(
validator.validated.data.blockchain.toLowerCase(),
Expand All @@ -22,6 +30,6 @@ export const execute: ExecuteWithConfig<Config> = async (input, config) => {
const reqConfig = { ...config.api, url }

const response = await Requester.request(reqConfig)
response.data.result = Requester.validateResultNumber(response.data, ['data', 'difficulty'])
response.data.result = Requester.validateResultNumber(response.data, ['data', endpoint])
return Requester.success(jobRunID, response)
}
90 changes: 90 additions & 0 deletions blockchair/test/stats.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { assert } from 'chai'
import { Requester, AdapterError } from '@chainlink/external-adapter'
import { assertSuccess, assertError } from '@chainlink/adapter-test-helpers'
import { AdapterRequest } from '@chainlink/types'
import { makeExecute } from '../src/adapter'

describe('stats endpoint', () => {
const jobID = '1'
const execute = makeExecute()

context('successful calls @integration', () => {
const requests = [
{
name: 'id not supplied',
testData: { data: { blockchain: 'BTC' } },
},
{
name: 'blockchain',
testData: { id: jobID, data: { blockchain: 'BTC' } },
},
{
name: 'coin',
testData: { id: jobID, data: { coin: 'BTC' } },
},
{
name: 'blockchain difficulty with endpoint',
testData: { id: jobID, data: { blockchain: 'BTC', endpoint: 'difficulty' } },
},
{
name: 'coing difficulty with endpoint',
testData: { id: jobID, data: { coin: 'BTC', endpoint: 'difficulty' } },
},
{
name: 'blockchain height',
testData: { id: jobID, data: { blockchain: 'BTC', endpoint: 'height' } },
},
{
name: 'coin height',
testData: { id: jobID, data: { coin: 'BTC', endpoint: 'height' } },
},
]

requests.forEach((req) => {
it(`${req.name}`, async () => {
const data = await execute(req.testData as AdapterRequest)
assertSuccess({ expected: 200, actual: data.statusCode }, data, jobID)
assert.isAbove(data.result, 0)
assert.isAbove(data.data.result, 0)
})
})
})

context('validation error', () => {
const requests = [
{ name: 'empty body', testData: {} },
{ name: 'empty data', testData: { data: {} } },
]

requests.forEach((req) => {
it(`${req.name}`, async () => {
try {
await execute(req.testData as AdapterRequest)
} catch (error) {
const errorResp = Requester.errored(jobID, new AdapterError(error))
assertError({ expected: 400, actual: errorResp.statusCode }, errorResp, jobID)
}
})
})
})

context('error calls @integration', () => {
const requests = [
{
name: 'unknown blockchain',
testData: { id: jobID, data: { blockchain: 'not_real' } },
},
]

requests.forEach((req) => {
it(`${req.name}`, async () => {
try {
await execute(req.testData as AdapterRequest)
} catch (error) {
const errorResp = Requester.errored(jobID, new AdapterError(error))
assertError({ expected: 500, actual: errorResp.statusCode }, errorResp, jobID)
}
})
})
})
})
14 changes: 14 additions & 0 deletions coinapi/test/adapter_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ describe('execute', () => {
name: 'coin/market lowercase',
testData: { id: jobID, data: { coin: 'eth', market: 'usd' } },
},
{
name: 'BTC testnet difficulty',
testData: {
id: jobID,
data: { blockchain: 'BTC', network: 'testnet', endpoint: 'difficulty' },
},
},
{
name: 'BTC mainnet height',
testData: {
id: jobID,
data: { blockchain: 'BTC', endpoint: 'height' },
},
},
]

requests.forEach((req) => {
Expand Down
3 changes: 3 additions & 0 deletions composite/bitcoin-json-rpc/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
...require('../../.eslintrc.ts.js'),
}
86 changes: 86 additions & 0 deletions composite/bitcoin-json-rpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Bitcoin JSON-RPC Blockchain info adapter for Chainlink

- Takes optional connection to RPC endpoint (set via `RPC_URL` environment variable)

## Input Params

Returns blockchain info stats, by calling `"method": "getblockchainfo"`. It relies on `json-rpc` adapter.

- `endpoint`: The parameter to query for. Default: "difficulty"
krebernisak marked this conversation as resolved.
Show resolved Hide resolved

## Output

```json
{
"jobRunID": "1",
"data": {
"chain": "main",
"blocks": 412022,
"headers": 665582,
"bestblockhash": "0000000000000000056482e60e14364c82903764eb88aef8fb0b1b60647334be",
"difficulty": 194254820283.444,
"mediantime": 1463406562,
"verificationprogress": 0.2162006436056612,
"initialblockdownload": true,
"chainwork": "0000000000000000000000000000000000000000001973393fcfc0215ecc9726",
"size_on_disk": 4758448869,
"pruned": true,
"pruneheight": 406538,
"automatic_pruning": true,
"prune_target_size": 5242880000,
"softforks": {
"bip34": {
"type": "buried",
"active": true,
"height": 227931
},
"bip66": {
"type": "buried",
"active": true,
"height": 363725
},
"bip65": {
"type": "buried",
"active": true,
"height": 388381
},
"csv": {
"type": "buried",
"active": false,
"height": 419328
},
"segwit": {
"type": "buried",
"active": false,
"height": 481824
}
},
"warnings": "",
"result": 665582
},
"result": 665582,
"statusCode": 200
}
```

## Install

Install dependencies

```bash
yarn
```

Set the `RPC_URL` environment variable to your client URL.

## Testing

Testing is dependent on the type of node you're connecting to. You can set a local environment variable `RPC_URL` to point to an RPC connection. Otherwise, the adapter will default to `"http://localhost:8545"`.

RPC Address and Port Defaults:

- BTC: (bitcoind) http://localhost:8332 (btcd) http://localhost:8334

```bash
yarn test
```
36 changes: 36 additions & 0 deletions composite/bitcoin-json-rpc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@chainlink/bitcoin-json-rpc-adapter",
"version": "0.0.1",
"description": "",
"author": "Evangelos Barakos (evangelos@smartcontract.com)",
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"prepublishOnly": "yarn build && yarn test:unit",
"setup": "yarn build",
"build": "tsc -b",
"lint": "eslint --ignore-path ../../.eslintignore . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint --ignore-path ../../.eslintignore . --ext .js,.jsx,.ts,.tsx --fix",
"test": "mocha --exit -r ts-node/register 'test/**/*.test.ts'",
"test:unit": "mocha --exit --grep @integration --invert -r ts-node/register 'test/**/*.test.ts'",
"test:integration": "mocha --exit --grep @integration -r ts-node/register 'test/**/*.test.ts'", "server": "node -e 'require(\"./index.js\").server()'",
"server:dist": "node -e 'require(\"./dist/index.js\").server()'",
"start": "yarn server:dist"
},
"devDependencies": {
"@types/chai": "^4.2.11",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.13",
"@typescript-eslint/eslint-plugin": "^3.9.0",
"@typescript-eslint/parser": "^3.9.0",
"ts-node": "^8.10.2",
"typescript": "^3.9.7"
},
"dependencies": {
"@chainlink/json-rpc-adapter": "^0.0.1"
}
}
38 changes: 38 additions & 0 deletions composite/bitcoin-json-rpc/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import JSONRPC from '@chainlink/json-rpc-adapter'
import { Config, ExecuteWithConfig, ExecuteFactory, AdapterRequest } from '@chainlink/types'
import { Validator, Requester } from '@chainlink/external-adapter'
import { DEFAULT_ENDPOINT, makeConfig } from './config'

const inputParams = {
endpoint: false,
}

const convertEndpoint: { [key: string]: string } = {
height: 'headers',
krebernisak marked this conversation as resolved.
Show resolved Hide resolved
}

// Export function to integrate with Chainlink node
const execute: ExecuteWithConfig<Config> = async (request: AdapterRequest) => {
const validator = new Validator(request, inputParams)
if (validator.error) throw validator.error

const jobRunID = validator.validated.id
let endpoint = validator.validated.data.endpoint || DEFAULT_ENDPOINT

const response = await JSONRPC.execute({
...request,
data: { ...request.data, method: 'getblockchaininfo' },
})

if (endpoint in convertEndpoint) endpoint = convertEndpoint[endpoint]
krebernisak marked this conversation as resolved.
Show resolved Hide resolved
const result = Requester.validateResultNumber(response.data, ['result', endpoint])
return Requester.success(jobRunID, {
data: { ...response.data.result, result },
result,
status: 200,
})
}

export const makeExecute: ExecuteFactory<Config> = (config) => {
return async (request) => execute(request, config || makeConfig())
}
7 changes: 7 additions & 0 deletions composite/bitcoin-json-rpc/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Requester } from '@chainlink/external-adapter'
import { Config } from '@chainlink/types'

export const DEFAULT_ENDPOINT = 'difficulty'

// TODO: needs to setup config for underlying JSON-RPC adapter
export const makeConfig = (prefix?: string): Config => Requester.getDefaultConfig(prefix)
6 changes: 6 additions & 0 deletions composite/bitcoin-json-rpc/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { makeConfig } from './config'
import { makeExecute } from './adapter'
import { expose, util } from '@chainlink/ea-bootstrap'

const NAME = 'BITCOIN-JSON-RPC'
export = { NAME, makeExecute, makeConfig, ...expose(util.wrapExecute(makeExecute())) }
Loading