-
Notifications
You must be signed in to change notification settings - Fork 300
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
Conversation
I see that you haven't updated any CHANGELOG files. Would it make sense to do so? |
0255ba3
to
44572aa
Compare
Currently, the common interface between all 4(3 APIs + json-rpc) adapters that return bitcoin info is: I didn't add many validations on q, so it can potentially support other parameters as well. We can improve the uniform interface/naming for blockchain info/stats, either now or in the future and choose a convention either a) created by us b) identical to the getblockchainfo params naming c) one of external APIs, like cryptoapis |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @ebarakos!
I tried to leave some comments and ideas, but we should probably also sync offline on this.
In general:
- Please use the existing
endpoint
input param instead of a new oneq
(take a look at existing adapters usingendpoint
on input) - Don't add custom logic to our general
json-rpc
adapter, but you can make a newbitcoin-json-rpc
adapter, that wraps/uses the underlyingjson-rpc
but follows our standard API. - In the future we should rename our
endpoint
input param asdataPoint
and codify all data point types that we support in TS + docs
blockchair/adapter.js
Outdated
const execute = (input, callback) => { | ||
const validator = new Validator(input, customParams) | ||
if (validator.error) return callback(validator.error.statusCode, validator.errored) | ||
|
||
const jobRunID = validator.validated.id | ||
let blockchain = validator.validated.data.blockchain | ||
let q = validator.validated.data.q || 'difficulty' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We currently use an endpoint
input param to differentiate between different data points we want to fetch from the external data provider.
I would suggest we don't introduce new behavior to the adapter API at this point but continue using what we have now.
Take a look at how we handle endpoint queries in different providers, and please try to mimic the interface and behavior here.
In the future, we are looking to streamline the adapter API. The first thing we should do is list the data points we support and codify them. Here you are adding support for a new data point, let's call it BlockNumber
. All of our adapters that know how to answer requests for that specific data point should follow the same API (input/output).
In this context, it may make sense to wrap the json-rpc
adapter into bitcoin-json-rpc
adapter that will then expose this specific data point (and others).
cryptoapis/adapter.js
Outdated
network: false, | ||
} | ||
|
||
const difficulty = (jobRunID, input, callback) => { | ||
const validator = new Validator(input, difficultyParams) | ||
const latestBlock = (jobRunID, input, callback) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how you renamed this as latestBlock
, as this actually is the latestBlock
endpoint from the cryptoapis
data provider. We also call our input param endpoint
, but IMHO this is the wrong name for this input param.
What our input param should be called is a dataPoint
, which we then map to 1 (or more) underlying API endpoints from which we fetch data.
Here the cryptoapis
adapter supports two data points (we call them endpoint
) and for both of those (difficulty|height) we fetch data from the same underlying HTTP endpoint (latestBlock).
Thank you @krebernisak for your helpful review. I will revert q to endpoint, along with the other changes, and we can tackle this in the future, across the whole codebase, as you mentioned. |
Created |
0042ba6
to
8ddf9f3
Compare
url: false, | ||
method: false, | ||
params: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
url
, method
and params
will be handled by JSONRPC adapter. You can just forward the input to the json adapter an it will handle it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just left them here, so this composite adapter can inherit the actual functionality of the json-rpc one.
I reverted it now to a simpler version, that just accepts the endpoint param, for querying for blockchain stats, according to the scope of the ticket.
if (endpoint != undefined || blockchain != undefined) { | ||
if (endpoint in convertEndpoint) endpoint = convertEndpoint[endpoint] | ||
if (!endpoint) endpoint = 'difficulty' | ||
request.data.method = 'getblockchaininfo' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want method only to be 'getblockchaininfo' only if we don't have endpoint or blockchain params? Default values could come from makeConfig
better.
Also, let's try to not modify directly the request
object.
cryptoid/src/adapter.ts
Outdated
const blockchain = validator.validated.data.blockchain.toLowerCase() | ||
|
||
const key = util.getRandomRequiredEnv('API_KEY') | ||
const q = endpointToQ[endpoint] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is q
? Could it have a more explanatory name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q is a param of the cryptoid endpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would give the var an explicit name, even if it will be a param of the request, but we'll know what is it.
const someExplicitName = endpointToXXX[endpoint]
const params = { key, q: someExplicitName }
cryptoid/src/index.ts
Outdated
import { makeExecute } from './adapter' | ||
import { makeConfig } from './config' | ||
|
||
const NAME = 'EXAMPLE' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you forgot to change the NAME
…d of diffuculty endpoint and added height support
8ddf9f3
to
edcff2a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ebarakos for the changes! Looking great, just some final notes
cryptoid/src/adapter.ts
Outdated
const blockchain = validator.validated.data.blockchain.toLowerCase() | ||
|
||
const key = util.getRandomRequiredEnv('API_KEY') | ||
const q = endpointToQ[endpoint] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would give the var an explicit name, even if it will be a param of the request, but we'll know what is it.
const someExplicitName = endpointToXXX[endpoint]
const params = { key, q: someExplicitName }
Take a look at the failing tests of |
cryptoid/src/adapter.ts
Outdated
const blockchain = validator.validated.data.blockchain.toLowerCase() | ||
|
||
const key = util.getRandomRequiredEnv('API_KEY') | ||
const apiParam = endpointToApiParam[endpoint] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for being picky here, as I understand q
param is the function you want to call from cryptoId, so something like cryptoIdFunction
or apiFunction
would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q
is the query parameter of the cryptoid endpoint. Not sure if it should be called function. In essence though, it has identical name as the JSON RPC methods.
I was thinking of something to let us know that the endpoint is mapped to the actual api's parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to apiFunctionName
after discussion.
6b06009
to
a62df92
Compare
cryptoapis/src/endpoint/stats.ts
Outdated
|
||
export const Name = 'difficulty' | ||
export const Name = 'stats' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we name this as "stats" when we are actually calling Crypoapis /bc/.../info
endpoint?
We should be calling it what it is, let's say blockchain-info
or bc-info
.
For Blockchair the endpoint is "stats", and we should call it "stats", but it's different for this adapter. When we get a query for BTC height, for Crypoapis adapter we need to call their bc-info
endpoint and read the payload.blocks
path from the response..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of adhering to a certain name for this category of calls. Like we have balance
and price
, which also do not correspond to the actual endpoint naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well just because we have some code implemented currently does not make it the correct way to do it :)
I suggest you rename this for now, and we'll make sure to improve/refactor other adapter implementations in the future.
"balance", "price", "difficulty" & "height" are all data points for which one can query our system. There is no "stats" data point currently. Here you are mapping the user request for "height" data point to a cryptoapis "bc-info" endpoint request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed it to bc_info
for now.
I think we have to find a uniform convention for these adapters that are returning blockchain info, while keeping difficulty
(and now height
) in backwards compatibility(probably by just delegating to stats
/bc_info
types when seeing these types of endpoint
).
cryptoapis/src/endpoint/stats.ts
Outdated
blockchain: ['blockchain', 'coin'], | ||
endpoint: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not reuse the name "endpoint" in our internal API. It just does not fit, just as it does not fit in the external API, but we are currently stuck with it there because of backward compatibility.
Internally, we should structure this differently.
So let's take this adapter and endpoint as an example, the "stats" endpoint.
The stats endpoint impl should have no knowledge of a concept like "height", this is a concept of our external API, it has nothing to do with "stats" endpoint. We should map a CL "height" request to a Cryptoapis "stats" request, but the impl for Cryptoapis "stats" request should have no knowledge of the outside CL "height" request.
The input to "stats" endpoint should look something like this:
const inputParams = {
blockchain: true,
network: false,
path: false
}
It makes a "stats" requests, and returns the data point at "path". If the "path" is empty, it returns the whole response body.
The component that is calling this should map from the CL API request to the "stats" API request. So your adapter in the top lvl execute function gets the input:
{
"blockchain": "btc",
"endpoint": height
}
We should map that to the underlying API endpoint fn call like this:
{
"blockchain": "bitcoin",
"network": "mainnet",
"path": "payload.blocks"
}
@ebarakos @RodrigoAD @justinkaseman @emmick4 please acknowledge & discuss!
As this is a high priority for today, you can ignore this for this specific PR, but keep it in mind on the next one. I am also going to open an issue for it, to improve our older implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be good to go!
A lot of valuable discussions in this PR 🙌 Thanks, @ebarakos 👍
Thanks for the thorough review @krebernisak and @RodrigoAD! |
No description provided.