You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
13 KiB

rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
7 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
7 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
rpc: add support for batched requests/responses (#3534) Continues from #3280 in building support for batched requests/responses in the JSON RPC (as per issue #3213). * Add JSON RPC batching for client and server As per #3213, this adds support for [JSON RPC batch requests and responses](https://www.jsonrpc.org/specification#batch). * Add additional checks to ensure client responses are the same as results * Fix case where a notification is sent and no response is expected * Add test to check that JSON RPC notifications in a batch are left out in responses * Update CHANGELOG_PENDING.md * Update PR number now that PR has been created * Make errors start with lowercase letter * Refactor batch functionality to be standalone This refactors the batching functionality to rather act in a standalone way. In light of supporting concurrent goroutines making use of the same client, it would make sense to have batching functionality where one could create a batch of requests per goroutine and send that batch without interfering with a batch from another goroutine. * Add examples for simple and batch HTTP client usage * Check errors from writer and remove nolinter directives * Make error strings start with lowercase letter * Refactor examples to make them testable * Use safer deferred shutdown for example Tendermint test node * Recompose rpcClient interface from pre-existing interface components * Rename WaitGroup for brevity * Replace empty ID string with request ID * Remove extraneous test case * Convert first letter of errors.Wrap() messages to lowercase * Remove extraneous function parameter * Make variable declaration terse * Reorder WaitGroup.Done call to help prevent race conditions in the face of failure * Swap mutex to value representation and remove initialization * Restore empty JSONRPC string ID in response to prevent nil * Make JSONRPCBufferedRequest private * Revert PR hard link in CHANGELOG_PENDING * Add client ID for JSONRPCClient This adds code to automatically generate a randomized client ID for the JSONRPCClient, and adds a check of the IDs in the responses (if one was set in the requests). * Extract response ID validation into separate function * Remove extraneous comments * Reorder fields to indicate clearly which are protected by the mutex * Refactor for loop to remove indexing * Restructure and combine loop * Flatten conditional block for better readability * Make multi-variable declaration slightly more readable * Change for loop style * Compress error check statements * Make function description more generic to show that we support different protocols * Preallocate memory for request and result objects
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package rpcclient
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. "reflect"
  11. "strings"
  12. "sync"
  13. "github.com/pkg/errors"
  14. amino "github.com/tendermint/go-amino"
  15. cmn "github.com/tendermint/tendermint/libs/common"
  16. types "github.com/tendermint/tendermint/rpc/lib/types"
  17. )
  18. const (
  19. protoHTTP = "http"
  20. protoHTTPS = "https"
  21. protoWSS = "wss"
  22. protoWS = "ws"
  23. protoTCP = "tcp"
  24. )
  25. // HTTPClient is a common interface for JSONRPCClient and URIClient.
  26. type HTTPClient interface {
  27. Call(method string, params map[string]interface{}, result interface{}) (interface{}, error)
  28. Codec() *amino.Codec
  29. SetCodec(*amino.Codec)
  30. }
  31. // protocol - client's protocol (for example, "http", "https", "wss", "ws", "tcp")
  32. // trimmedS - rest of the address (for example, "192.0.2.1:25", "[2001:db8::1]:80") with "/" replaced with "."
  33. func toClientAddrAndParse(remoteAddr string) (network string, trimmedS string, err error) {
  34. protocol, address, err := parseRemoteAddr(remoteAddr)
  35. if err != nil {
  36. return "", "", err
  37. }
  38. // protocol to use for http operations, to support both http and https
  39. var clientProtocol string
  40. // default to http for unknown protocols (ex. tcp)
  41. switch protocol {
  42. case protoHTTP, protoHTTPS, protoWS, protoWSS:
  43. clientProtocol = protocol
  44. default:
  45. clientProtocol = protoHTTP
  46. }
  47. // replace / with . for http requests (kvstore domain)
  48. trimmedAddress := strings.Replace(address, "/", ".", -1)
  49. return clientProtocol, trimmedAddress, nil
  50. }
  51. func toClientAddress(remoteAddr string) (string, error) {
  52. clientProtocol, trimmedAddress, err := toClientAddrAndParse(remoteAddr)
  53. if err != nil {
  54. return "", err
  55. }
  56. return clientProtocol + "://" + trimmedAddress, nil
  57. }
  58. // network - name of the network (for example, "tcp", "unix")
  59. // s - rest of the address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
  60. // TODO: Deprecate support for IP:PORT or /path/to/socket
  61. func parseRemoteAddr(remoteAddr string) (network string, s string, err error) {
  62. parts := strings.SplitN(remoteAddr, "://", 2)
  63. var protocol, address string
  64. switch {
  65. case len(parts) == 1:
  66. // default to tcp if nothing specified
  67. protocol, address = protoTCP, remoteAddr
  68. case len(parts) == 2:
  69. protocol, address = parts[0], parts[1]
  70. default:
  71. return "", "", fmt.Errorf("invalid addr: %s", remoteAddr)
  72. }
  73. // accept http(s) as an alias for tcp
  74. switch protocol {
  75. case protoHTTP, protoHTTPS:
  76. protocol = protoTCP
  77. }
  78. return protocol, address, nil
  79. }
  80. func makeErrorDialer(err error) func(string, string) (net.Conn, error) {
  81. return func(_ string, _ string) (net.Conn, error) {
  82. return nil, err
  83. }
  84. }
  85. func makeHTTPDialer(remoteAddr string) func(string, string) (net.Conn, error) {
  86. protocol, address, err := parseRemoteAddr(remoteAddr)
  87. if err != nil {
  88. return makeErrorDialer(err)
  89. }
  90. return func(proto, addr string) (net.Conn, error) {
  91. return net.Dial(protocol, address)
  92. }
  93. }
  94. // DefaultHTTPClient is used to create an http client with some default parameters.
  95. // We overwrite the http.Client.Dial so we can do http over tcp or unix.
  96. // remoteAddr should be fully featured (eg. with tcp:// or unix://)
  97. func DefaultHTTPClient(remoteAddr string) *http.Client {
  98. return &http.Client{
  99. Transport: &http.Transport{
  100. // Set to true to prevent GZIP-bomb DoS attacks
  101. DisableCompression: true,
  102. Dial: makeHTTPDialer(remoteAddr),
  103. },
  104. }
  105. }
  106. //------------------------------------------------------------------------------------
  107. // jsonRPCBufferedRequest encapsulates a single buffered request, as well as its
  108. // anticipated response structure.
  109. type jsonRPCBufferedRequest struct {
  110. request types.RPCRequest
  111. result interface{} // The result will be deserialized into this object.
  112. }
  113. // JSONRPCRequestBatch allows us to buffer multiple request/response structures
  114. // into a single batch request. Note that this batch acts like a FIFO queue, and
  115. // is thread-safe.
  116. type JSONRPCRequestBatch struct {
  117. client *JSONRPCClient
  118. mtx sync.Mutex
  119. requests []*jsonRPCBufferedRequest
  120. }
  121. // JSONRPCClient takes params as a slice
  122. type JSONRPCClient struct {
  123. address string
  124. client *http.Client
  125. id types.JSONRPCStringID
  126. cdc *amino.Codec
  127. }
  128. // JSONRPCCaller implementers can facilitate calling the JSON RPC endpoint.
  129. type JSONRPCCaller interface {
  130. Call(method string, params map[string]interface{}, result interface{}) (interface{}, error)
  131. }
  132. // Both JSONRPCClient and JSONRPCRequestBatch can facilitate calls to the JSON
  133. // RPC endpoint.
  134. var _ JSONRPCCaller = (*JSONRPCClient)(nil)
  135. var _ JSONRPCCaller = (*JSONRPCRequestBatch)(nil)
  136. // NewJSONRPCClient returns a JSONRPCClient pointed at the given address.
  137. func NewJSONRPCClient(remote string) *JSONRPCClient {
  138. return NewJSONRPCClientWithHTTPClient(remote, DefaultHTTPClient(remote))
  139. }
  140. // NewJSONRPCClientWithHTTPClient returns a JSONRPCClient pointed at the given address using a custom http client
  141. // The function panics if the provided client is nil or remote is invalid.
  142. func NewJSONRPCClientWithHTTPClient(remote string, client *http.Client) *JSONRPCClient {
  143. if client == nil {
  144. panic("nil http.Client provided")
  145. }
  146. clientAddress, err := toClientAddress(remote)
  147. if err != nil {
  148. panic(fmt.Sprintf("invalid remote %s: %s", remote, err))
  149. }
  150. return &JSONRPCClient{
  151. address: clientAddress,
  152. client: client,
  153. id: types.JSONRPCStringID("jsonrpc-client-" + cmn.RandStr(8)),
  154. cdc: amino.NewCodec(),
  155. }
  156. }
  157. // Call will send the request for the given method through to the RPC endpoint
  158. // immediately, without buffering of requests.
  159. func (c *JSONRPCClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
  160. request, err := types.MapToRequest(c.cdc, c.id, method, params)
  161. if err != nil {
  162. return nil, err
  163. }
  164. requestBytes, err := json.Marshal(request)
  165. if err != nil {
  166. return nil, err
  167. }
  168. requestBuf := bytes.NewBuffer(requestBytes)
  169. httpResponse, err := c.client.Post(c.address, "text/json", requestBuf)
  170. if err != nil {
  171. return nil, err
  172. }
  173. defer httpResponse.Body.Close() // nolint: errcheck
  174. responseBytes, err := ioutil.ReadAll(httpResponse.Body)
  175. if err != nil {
  176. return nil, err
  177. }
  178. return unmarshalResponseBytes(c.cdc, responseBytes, c.id, result)
  179. }
  180. // NewRequestBatch starts a batch of requests for this client.
  181. func (c *JSONRPCClient) NewRequestBatch() *JSONRPCRequestBatch {
  182. return &JSONRPCRequestBatch{
  183. requests: make([]*jsonRPCBufferedRequest, 0),
  184. client: c,
  185. }
  186. }
  187. func (c *JSONRPCClient) sendBatch(requests []*jsonRPCBufferedRequest) ([]interface{}, error) {
  188. reqs := make([]types.RPCRequest, 0, len(requests))
  189. results := make([]interface{}, 0, len(requests))
  190. for _, req := range requests {
  191. reqs = append(reqs, req.request)
  192. results = append(results, req.result)
  193. }
  194. // serialize the array of requests into a single JSON object
  195. requestBytes, err := json.Marshal(reqs)
  196. if err != nil {
  197. return nil, err
  198. }
  199. httpResponse, err := c.client.Post(c.address, "text/json", bytes.NewBuffer(requestBytes))
  200. if err != nil {
  201. return nil, err
  202. }
  203. defer httpResponse.Body.Close() // nolint: errcheck
  204. responseBytes, err := ioutil.ReadAll(httpResponse.Body)
  205. if err != nil {
  206. return nil, err
  207. }
  208. return unmarshalResponseBytesArray(c.cdc, responseBytes, c.id, results)
  209. }
  210. func (c *JSONRPCClient) Codec() *amino.Codec {
  211. return c.cdc
  212. }
  213. func (c *JSONRPCClient) SetCodec(cdc *amino.Codec) {
  214. c.cdc = cdc
  215. }
  216. //-------------------------------------------------------------
  217. // Count returns the number of enqueued requests waiting to be sent.
  218. func (b *JSONRPCRequestBatch) Count() int {
  219. b.mtx.Lock()
  220. defer b.mtx.Unlock()
  221. return len(b.requests)
  222. }
  223. func (b *JSONRPCRequestBatch) enqueue(req *jsonRPCBufferedRequest) {
  224. b.mtx.Lock()
  225. defer b.mtx.Unlock()
  226. b.requests = append(b.requests, req)
  227. }
  228. // Clear empties out the request batch.
  229. func (b *JSONRPCRequestBatch) Clear() int {
  230. b.mtx.Lock()
  231. defer b.mtx.Unlock()
  232. return b.clear()
  233. }
  234. func (b *JSONRPCRequestBatch) clear() int {
  235. count := len(b.requests)
  236. b.requests = make([]*jsonRPCBufferedRequest, 0)
  237. return count
  238. }
  239. // Send will attempt to send the current batch of enqueued requests, and then
  240. // will clear out the requests once done. On success, this returns the
  241. // deserialized list of results from each of the enqueued requests.
  242. func (b *JSONRPCRequestBatch) Send() ([]interface{}, error) {
  243. b.mtx.Lock()
  244. defer func() {
  245. b.clear()
  246. b.mtx.Unlock()
  247. }()
  248. return b.client.sendBatch(b.requests)
  249. }
  250. // Call enqueues a request to call the given RPC method with the specified
  251. // parameters, in the same way that the `JSONRPCClient.Call` function would.
  252. func (b *JSONRPCRequestBatch) Call(
  253. method string,
  254. params map[string]interface{},
  255. result interface{},
  256. ) (interface{}, error) {
  257. request, err := types.MapToRequest(b.client.cdc, b.client.id, method, params)
  258. if err != nil {
  259. return nil, err
  260. }
  261. b.enqueue(&jsonRPCBufferedRequest{request: request, result: result})
  262. return result, nil
  263. }
  264. //-------------------------------------------------------------
  265. // URI takes params as a map
  266. type URIClient struct {
  267. address string
  268. client *http.Client
  269. cdc *amino.Codec
  270. }
  271. // The function panics if the provided remote is invalid.
  272. func NewURIClient(remote string) *URIClient {
  273. clientAddress, err := toClientAddress(remote)
  274. if err != nil {
  275. panic(fmt.Sprintf("invalid remote %s: %s", remote, err))
  276. }
  277. return &URIClient{
  278. address: clientAddress,
  279. client: DefaultHTTPClient(remote),
  280. cdc: amino.NewCodec(),
  281. }
  282. }
  283. func (c *URIClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
  284. values, err := argsToURLValues(c.cdc, params)
  285. if err != nil {
  286. return nil, err
  287. }
  288. // log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
  289. resp, err := c.client.PostForm(c.address+"/"+method, values)
  290. if err != nil {
  291. return nil, err
  292. }
  293. defer resp.Body.Close() // nolint: errcheck
  294. responseBytes, err := ioutil.ReadAll(resp.Body)
  295. if err != nil {
  296. return nil, err
  297. }
  298. return unmarshalResponseBytes(c.cdc, responseBytes, "", result)
  299. }
  300. func (c *URIClient) Codec() *amino.Codec {
  301. return c.cdc
  302. }
  303. func (c *URIClient) SetCodec(cdc *amino.Codec) {
  304. c.cdc = cdc
  305. }
  306. //------------------------------------------------
  307. func unmarshalResponseBytes(
  308. cdc *amino.Codec,
  309. responseBytes []byte,
  310. expectedID types.JSONRPCStringID,
  311. result interface{},
  312. ) (interface{}, error) {
  313. // Read response. If rpc/core/types is imported, the result will unmarshal
  314. // into the correct type.
  315. // log.Notice("response", "response", string(responseBytes))
  316. var err error
  317. response := &types.RPCResponse{}
  318. err = json.Unmarshal(responseBytes, response)
  319. if err != nil {
  320. return nil, errors.Wrap(err, "error unmarshalling rpc response")
  321. }
  322. if response.Error != nil {
  323. return nil, errors.Wrap(response.Error, "response error")
  324. }
  325. // From the JSON-RPC 2.0 spec:
  326. // id: It MUST be the same as the value of the id member in the Request Object.
  327. if err := validateResponseID(response, expectedID); err != nil {
  328. return nil, err
  329. }
  330. // Unmarshal the RawMessage into the result.
  331. err = cdc.UnmarshalJSON(response.Result, result)
  332. if err != nil {
  333. return nil, errors.Wrap(err, "error unmarshalling rpc response result")
  334. }
  335. return result, nil
  336. }
  337. func unmarshalResponseBytesArray(
  338. cdc *amino.Codec,
  339. responseBytes []byte,
  340. expectedID types.JSONRPCStringID,
  341. results []interface{},
  342. ) ([]interface{}, error) {
  343. var (
  344. err error
  345. responses []types.RPCResponse
  346. )
  347. err = json.Unmarshal(responseBytes, &responses)
  348. if err != nil {
  349. return nil, errors.Wrap(err, "error unmarshalling rpc response")
  350. }
  351. // No response error checking here as there may be a mixture of successful
  352. // and unsuccessful responses.
  353. if len(results) != len(responses) {
  354. return nil, errors.Errorf(
  355. "expected %d result objects into which to inject responses, but got %d",
  356. len(responses),
  357. len(results),
  358. )
  359. }
  360. for i, response := range responses {
  361. response := response
  362. // From the JSON-RPC 2.0 spec:
  363. // id: It MUST be the same as the value of the id member in the Request Object.
  364. if err := validateResponseID(&response, expectedID); err != nil {
  365. return nil, errors.Wrapf(err, "failed to validate response ID in response %d", i)
  366. }
  367. if err := cdc.UnmarshalJSON(responses[i].Result, results[i]); err != nil {
  368. return nil, errors.Wrap(err, "error unmarshalling rpc response result")
  369. }
  370. }
  371. return results, nil
  372. }
  373. func validateResponseID(res *types.RPCResponse, expectedID types.JSONRPCStringID) error {
  374. // we only validate a response ID if the expected ID is non-empty
  375. if len(expectedID) == 0 {
  376. return nil
  377. }
  378. if res.ID == nil {
  379. return errors.Errorf("missing ID in response")
  380. }
  381. id, ok := res.ID.(types.JSONRPCStringID)
  382. if !ok {
  383. return errors.Errorf("expected ID string in response but got: %v", id)
  384. }
  385. if expectedID != id {
  386. return errors.Errorf("response ID (%s) does not match request ID (%s)", id, expectedID)
  387. }
  388. return nil
  389. }
  390. func argsToURLValues(cdc *amino.Codec, args map[string]interface{}) (url.Values, error) {
  391. values := make(url.Values)
  392. if len(args) == 0 {
  393. return values, nil
  394. }
  395. err := argsToJSON(cdc, args)
  396. if err != nil {
  397. return nil, err
  398. }
  399. for key, val := range args {
  400. values.Set(key, val.(string))
  401. }
  402. return values, nil
  403. }
  404. func argsToJSON(cdc *amino.Codec, args map[string]interface{}) error {
  405. for k, v := range args {
  406. rt := reflect.TypeOf(v)
  407. isByteSlice := rt.Kind() == reflect.Slice && rt.Elem().Kind() == reflect.Uint8
  408. if isByteSlice {
  409. bytes := reflect.ValueOf(v).Bytes()
  410. args[k] = fmt.Sprintf("0x%X", bytes)
  411. continue
  412. }
  413. data, err := cdc.MarshalJSON(v)
  414. if err != nil {
  415. return err
  416. }
  417. args[k] = string(data)
  418. }
  419. return nil
  420. }