Skip to content
This repository was archived by the owner on Dec 10, 2020. It is now read-only.

Conversation

yurenju
Copy link
Contributor

@yurenju yurenju commented Jun 13, 2018

No description provided.

@coveralls
Copy link

coveralls commented Jun 13, 2018

Pull Request Test Coverage Report for Build 41

  • 133 of 141 (94.33%) changed or added relevant lines in 8 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.4%) to 90.558%

Changes Missing Coverage Covered Lines Changed/Added Lines %
tests/rpc/rpc.js 18 20 90.0%
tests/rpc/eth/getBlockByNumber.js 53 59 89.83%
Totals Coverage Status
Change from base Build 40: 0.4%
Covered Lines: 182
Relevant Lines: 192

💛 - Coveralls

Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @yurenju, thanks so much for this PR, this could have come straight from a textbook, really like this clean structure you have already set up and the completeness with the tests and everything.

Have made some comments directly in the code.

P.S.: Croatia was great, we already visited Rovinj, still have all these beautiful sights swirling around in my head. 🏖 ⛪️ 🐚

@@ -0,0 +1,21 @@
const modules = require('./modules')

class RPCServer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably RPCManager?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to rename this one, nice catch!

lib/index.js Outdated

if (config.rpc) {
const rpc = new RPCServer(cm.getBlockchain())
rpc.listen(config.rpcport)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a info log msg either here or in the server constructor (not sure which one is more clean?) that the server has been started, also mentioning the port?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to follow convention from other modules to have an argument config into this module and save _config and _logger into RPCServer and RPCManager

cb(err, block.toJSON(true))
})
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you already mentioned Ganache in the issue description: I just looked into the ganache-core code a bit and I am generally wondering if we are replicating a lot of of the code here (or will do in the future) if one is looking at e.g. this.

I tried to extract the structure from there a bit but have not yet a clear view on the similarities and differences, they seem to have there own blockchain implementation and statemanager. Do you have already formed an opinion on this?

Might be worth to analyze this a bit deeper before we start implementing all the RPC methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which part do you want to replicate from ganache-core?

took a look I feel we should expand argument like function(block_number, include_full_transactions, callback) instead of (params, cb) to make it more clear.

I'm not familiar with ganache-core codebase, so I don't have any opinion for that yet, but I agree we should analyze ganache-core deeper to get a better idea to implement rpc.

tests/rpc.js Outdated
t.equal(blockchain.getBlock.firstCall.args[0], 1)
t.end()
})
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So great that you already added some framing for test execution, really like this sinon library, didn't know that before.

I think our general reference for RPC execution should be Geth behavior, this is also really practical to test running the JS client and Geth with RPC and different port side by side and then have a look at the results.

I've done this with JS 8545 and Geth 8546 and get divergent behavior e.g. for:

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1", true],"id":1}' http://127.0.0.1:8545
{...JSON Result...}
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1", true],"id":1}' http://127.0.0.1:8546
invalid content type, only application/json is supported

So Geth requires a content header -H "Content-Type: application/json" which I think we should then require as well.

Also things like leading zeros (0x01) differ:

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x01", true],"id":1}' -H "Content-Type: application/json" http://127.0.0.1:8545|jq
{...JSON Result...}
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x01", true],"id":1}' -H "Content-Type: application/json" http://127.0.0.1:8546|jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   197  100   117  100    80  73079  49968 --:--:-- --:--:-- --:--:--  114k
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "invalid argument 0: hex number with leading zero digits"
  }
}

Can you test some basic edge cases (e.g. not-existing/downloaded block) and see how things behave and then adopt the code base to make sure that the output is the same?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @yurenju, I would probably merge #29 before this PR and then ask you to rebase on top, if you see any problems here let me know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@holgerd77 sure go ahead! I may update my pr in two days when I get more free time :D, will rebase after #29 is landed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and thanks for testing with js client and geth side by side, I will add some basic edge cases!

Copy link
Contributor Author

@yurenju yurenju Jun 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel the way I handled rpc is too simple since we need to fit JSON-RPC spec, e.g., batch query of JSON-RPC. there are few Node.js packages for JSON-RPC and seems jayson is a well-maintain solution.

so jayson module will be introduced on next commit.

https://github.com/tedeh/jayson

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I didn't even know until now that JSON-RPC is a dedicated standard, lol. Yes, that makes definitely sense then, library seems to be a good choice on first look.

@yurenju
Copy link
Contributor Author

yurenju commented Jun 24, 2018

Just heads up I didn't finish my commit this weekend but already added some edge test case for invalid parameters, only accept content-type as application/json, etc.

I pushed my WIP commit to the previous PR to show the progress. hopefully I can finish this commit this week.

@holgerd77
Copy link
Member

Ah, already running this with jayson, cool! 😄 Thanks for re-thinking this so constantly, this will be really really valuable if we have a solid structure here.

I now merged #29, can you rebase your PR on top?

@yurenju
Copy link
Contributor Author

yurenju commented Jun 25, 2018

just rebased it. the last commit introduces some changes:

  • test cases for:
    • http status code should be 415 if Content-Type is not application/json
    • returns error if method does not exist
    • returns error if parameter is invalid, include hex and boolean checker
  • jayson: JSON-RPC module implementation with batch request and correct status code
  • middleware for validation

let me know if you found anything can be improved :D

@holgerd77
Copy link
Member

@yurenju Thanks again, looking into it right now (think I will learn a lot reviewing your work...).

Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Yuren, really wanted to criticize something but didn't found anything, thanks again for the fantastic work!

Also tested this locally, will merge now.

.option('rpcaddr', {
describe: 'HTTP-RPC server listening interface',
default: 'localhost'
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice that you also added the rpcaddr now.

const manager = new RPCManager(cm.getBlockchain(), config)
const server = jayson.server(manager.getMethods())
config.logger.info(`HTTP endpoint opened: http://${rpcaddr}:${rpcport}`)
server.http().listen(rpcport)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was a bit sceptical about the naming but wasn't aware that consts in an if clause remain local not trickling in the global space (tested this), so this should be ok.


this.getBlockByNumber = middleware(this.getBlockByNumber.bind(this), 2,
[validators.hex, validators.bool])
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really super-nice middleware structure.

*/
middleware (method, requiredParamsCount, validators) {
return function (params, cb) {
if (params.length < requiredParamsCount) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if this should be a !== comparison and a bit more general error msg, but we can leave this for now. Another possibility would also to make an extra check for >, this is maybe even more user-friendly for the caller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this because want to align with go-ethereum behaviors, but you are right we can handle this better than geth :D

id: 1
}

request(server)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice setup with this supertest library - didn't know that yet - really sleak.

@holgerd77 holgerd77 merged commit d42166e into ethereumjs:master Jun 28, 2018
@holgerd77
Copy link
Member

For testing this locally:

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1b4", true],"id":1}' -H "Content-Type: application/json" http://127.0.0.1:8545|jq

(jq is for (optional) formatting and has to be installed manually before)

Result:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "header": {
      "parentHash": "0xe99e022112df268087ea7eafaf4790497fd21dbeeb6bd7a1721df161a6657a54",
      "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
      "coinbase": "0xbb7b8287f3f0a933474a79eae42cbca977791171",
      "stateRoot": "0xddc8b0234c2e0cad087c8b389aa7ef01f7d79b2570bccb77ce48648aa61c904d",
      "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
      "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
      "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
      "difficulty": "0x04ea3f27bc",
      "number": "0x01b4",
      "gasLimit": "0x1388",
      "gasUsed": "0x",
      "timestamp": "0x55ba467c",
      "extraData": "0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32",
      "mixHash": "0x4fffe9ae21f1c9e15207b1f472d5bbdd68c9595d461666602f2be20daf5e7843",
      "nonce": "0x689056015818adbe"
    },
    "transactions": [],
    "uncleHeaders": []
  }
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants