-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pay upstream ETH provider for RPC requests (#25)
* Setup a separate upstream RPC provider for mutation requests * Setup a payment channel with the upstream Nitro node * Override ethersjs provider to send payment with each request * Use latest block tag for latestBlock query * Only pay for selective RPC requests * Upgrade cerc-io packages * Check for Nitro node address before setting up the payment channel
- Loading branch information
1 parent
9f7d105
commit 8e587cd
Showing
7 changed files
with
172 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// | ||
// Copyright 2023 Vulcanize, Inc. | ||
// | ||
|
||
import debug from 'debug'; | ||
import { providers } from 'ethers'; | ||
|
||
import { PaymentsManager } from '@cerc-io/util'; | ||
import { deepCopy } from '@ethersproject/properties'; | ||
import { fetchJson } from '@ethersproject/web'; | ||
|
||
const log = debug('vulcanize:payment-utils'); | ||
|
||
// TODO: Configure | ||
const paidRPCMethods = [ | ||
'eth_getBlockByHash', | ||
'eth_getStorageAt' | ||
]; | ||
|
||
export async function setupProviderWithPayments (provider: providers.JsonRpcProvider, paymentsManager: PaymentsManager, paymentAmount: string): Promise<void> { | ||
// https://github.com/ethers-io/ethers.js/blob/v5.7.2/packages/providers/src.ts/json-rpc-provider.ts#L502 | ||
provider.send = async (method: string, params: Array<any>): Promise<any> => { | ||
log(`Making RPC call: ${method}`); | ||
|
||
const request = { | ||
method: method, | ||
params: params, | ||
id: (provider._nextId++), | ||
jsonrpc: '2.0' | ||
}; | ||
|
||
provider.emit('debug', { | ||
action: 'request', | ||
request: deepCopy(request), | ||
provider: provider | ||
}); | ||
|
||
// We can expand this in the future to any call, but for now these | ||
// are the biggest wins and do not require any serializing parameters. | ||
const cache = (['eth_chainId', 'eth_blockNumber'].indexOf(method) >= 0); | ||
// @ts-expect-error copied code | ||
if (cache && provider._cache[method]) { | ||
return provider._cache[method]; | ||
} | ||
|
||
// Send a payment to upstream Nitro node and add details to the request URL | ||
let updatedURL = `${provider.connection.url}?method=${method}`; | ||
if (paidRPCMethods.includes(method)) { | ||
const voucher = await paymentsManager.sendUpstreamPayment(paymentAmount); | ||
updatedURL = `${updatedURL}&channelId=${voucher.channelId}&amount=${voucher.amount}&signature=${voucher.signature}`; | ||
} | ||
|
||
const result = fetchJson({ ...provider.connection, url: updatedURL }, JSON.stringify(request), getResult).then((result) => { | ||
provider.emit('debug', { | ||
action: 'response', | ||
request: request, | ||
response: result, | ||
provider: provider | ||
}); | ||
|
||
return result; | ||
}, (error) => { | ||
provider.emit('debug', { | ||
action: 'response', | ||
error: error, | ||
request: request, | ||
provider: provider | ||
}); | ||
|
||
throw error; | ||
}); | ||
|
||
// Cache the fetch, but clear it on the next event loop | ||
if (cache) { | ||
provider._cache[method] = result; | ||
setTimeout(() => { | ||
// @ts-expect-error copied code | ||
provider._cache[method] = null; | ||
}, 0); | ||
} | ||
|
||
return result; | ||
}; | ||
} | ||
|
||
// https://github.com/ethers-io/ethers.js/blob/v5.7.2/packages/providers/src.ts/json-rpc-provider.ts#L139 | ||
function getResult (payload: { error?: { code?: number, data?: any, message?: string }, result?: any }): any { | ||
if (payload.error) { | ||
// @TODO: not any | ||
const error: any = new Error(payload.error.message); | ||
error.code = payload.error.code; | ||
error.data = payload.error.data; | ||
throw error; | ||
} | ||
|
||
return payload.result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters