From 3aef84d32bcbe2f0907b5a6eecde8087d9c35cda Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Wed, 25 Oct 2023 12:32:44 -0700 Subject: [PATCH] improve compute unit method matching and punish admin queries --- web3_proxy/src/compute_units.rs | 301 +++++++++++++++++--------------- 1 file changed, 156 insertions(+), 145 deletions(-) diff --git a/web3_proxy/src/compute_units.rs b/web3_proxy/src/compute_units.rs index 9d34881b..fa35f727 100644 --- a/web3_proxy/src/compute_units.rs +++ b/web3_proxy/src/compute_units.rs @@ -47,154 +47,165 @@ where impl ComputeUnit { /// costs can vary widely depending on method and chain pub fn new(method: &str, chain_id: u64, response_bytes: u64) -> Self { - // TODO: this works, but this is fragile. think of a better way to check the method is a subscription - if method.ends_with(')') { - return Self::variable_price(chain_id, method, response_bytes); - } + let cu = match (chain_id, method) { + (1101, "zkevm_batchNumber") => 0, + (1101, "zkevm_batchNumberByBlockNumber") => 0, + (1101, "zkevm_consolidatedBlockNumber") => 0, + (1101, "zkevm_getBatchByNumber") => 0, + (1101, "zkevm_getBroadcastURI") => 0, + (1101, "zkevm_isBlockConsolidated") => 0, + (1101, "zkevm_isBlockVirtualized") => 0, + (1101, "zkevm_verifiedBatchNumber") => 0, + (1101, "zkevm_virtualBatchNumber") => 0, + (137, "bor_getAuthor") => 10, + (137, "bor_getCurrentProposer") => 10, + (137, "bor_getCurrentValidators") => 10, + (137, "bor_getRootHash") => 10, + (137, "bor_getSignersAtHash") => 10, + (_, "debug_traceBlockByHash") => { + return Self::variable_price(chain_id, method, response_bytes) + 497 + } + (_, "debug_traceBlockByNumber") => { + return Self::variable_price(chain_id, method, response_bytes) + 497 + } + (_, "debug_traceCall") => { + return Self::variable_price(chain_id, method, response_bytes) + 309 + } + (_, "debug_traceTransaction") => { + return Self::variable_price(chain_id, method, response_bytes) + 309 + } + (_, "erigon_forks") => 24, + (_, "erigon_getHeaderByHash") => 24, + (_, "erigon_getHeaderByNumber") => 24, + (_, "erigon_getLogsByHash") => 24, + (_, "erigon_issuance") => 24, + (_, "eth_accounts") => 10, + (_, "eth_blockNumber") => 10, + (_, "eth_call") => 26, + (_, "eth_chainId") => 0, + (_, "eth_createAccessList") => 10, + (_, "eth_estimateGas") => 87, + (_, "eth_estimateUserOperationGas") => 500, + (_, "eth_feeHistory") => 10, + (_, "eth_gasPrice") => 19, + (_, "eth_getBalance") => 19, + (_, "eth_getBlockByHash") => 21, + (_, "eth_getBlockByNumber") => 16, + (_, "eth_getBlockReceipts") => 500, + (_, "eth_getBlockTransactionCountByHash") => 20, + (_, "eth_getBlockTransactionCountByNumber") => 20, + (_, "eth_getCode") => 19, + (_, "eth_getFilterChanges") => 20, + (_, "eth_getFilterLogs") => 75, + (_, "eth_getLogs") => 75, + (_, "eth_getProof") => 21, + (_, "eth_getStorageAt") => 17, + (_, "eth_getTransactionByBlockHashAndIndex") => 15, + (_, "eth_getTransactionByBlockNumberAndIndex") => 15, + (_, "eth_getTransactionByHash") => 17, + (_, "eth_getTransactionCount") => 26, + (_, "eth_getTransactionReceipt") => 15, + (_, "eth_getUncleByBlockHashAndIndex") => 15, + (_, "eth_getUncleByBlockNumberAndIndex") => 15, + (_, "eth_getUncleCountByBlockHash") => 15, + (_, "eth_getUncleCountByBlockNumber") => 15, + (_, "eth_getUserOperationByHash") => 17, + (_, "eth_getUserOperationReceipt") => 15, + (_, "eth_maxPriorityFeePerGas") => 10, + (_, "eth_newBlockFilter") => { + // TODO: 20 + return Self::unimplemented(); + } + (_, "eth_newFilter") => { + // TODO: 20 + return Self::unimplemented(); + } + (_, "eth_newPendingTransactionFilter") => { + // TODO: 20 + return Self::unimplemented(); + } + (_, "eth_pollSubscriptions") => { + return Self::unimplemented(); + } + (_, "eth_protocolVersion") => 0, + (_, "eth_sendRawTransaction") => 250, + (_, "eth_sendUserOperation") => 1000, + (_, "eth_subscribe") => 10, + (_, "eth_supportedEntryPoints") => 5, + (_, "eth_syncing") => 0, + (_, "eth_uninstallFilter") => 10, + (_, "eth_unsubscribe") => 10, + (_, "net_listening") => 0, + (_, "net_version") => 0, + (_, "test") => 0, + (_, "trace_block") => 24, + (_, "trace_call") => 75, + (_, "trace_callMany") => 75 * 3, + (_, "trace_filter") => 75, + (_, "trace_get") => 17, + (_, "trace_rawTransaction") => 75, + (_, "trace_replayBlockTransactions") => 2983, + (_, "trace_replayTransaction") => 2983, + (_, "trace_transaction") => 26, + (_, "txpool_content") => { + return Self::variable_price(chain_id, method, response_bytes) + 1000; + } + (_, "invalid_method") => 100, + (_, "web3_clientVersion") => 15, + (_, "web3_bundlerVersion") => 15, + (_, "web3_sha3") => 15, + (_, "ots_getInternalOperations") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_hasCode") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_getTransactionError") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_traceTransaction") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_getBlockDetails") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_getBlockDetailsByHash") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_getBlockTransactions") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_searchTransactionsBefore") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_searchTransactionsAfter") => { + return Self::variable_price(chain_id, method, response_bytes) + 100 + } + (_, "ots_getTransactionBySenderAndNonce") => 1000, + (_, "ots_getContractCreator") => 1000, + (_, method) => { + // TODO: this works, but this is fragile. think of a better way to check the method is a subscription + if method.ends_with(')') { + return Self::variable_price(chain_id, method, response_bytes); + } - let cu = if method.starts_with("admin_") || method.starts_with("alchemy_") { - // maybe charge extra since they are doing things they aren't supposed to - return Self::unimplemented(); - } else { - match (chain_id, method) { - (1101, "zkevm_batchNumber") => 0, - (1101, "zkevm_batchNumberByBlockNumber") => 0, - (1101, "zkevm_consolidatedBlockNumber") => 0, - (1101, "zkevm_getBatchByNumber") => 0, - (1101, "zkevm_getBroadcastURI") => 0, - (1101, "zkevm_isBlockConsolidated") => 0, - (1101, "zkevm_isBlockVirtualized") => 0, - (1101, "zkevm_verifiedBatchNumber") => 0, - (1101, "zkevm_virtualBatchNumber") => 0, - (137, "bor_getAuthor") => 10, - (137, "bor_getCurrentProposer") => 10, - (137, "bor_getCurrentValidators") => 10, - (137, "bor_getRootHash") => 10, - (137, "bor_getSignersAtHash") => 10, - (_, "debug_traceBlockByHash") => { - return Self::variable_price(chain_id, method, response_bytes) + 497 + if method.starts_with("admin_") + || method.starts_with("miner_") + || method == "personal_unlockAccount" + { + // charge extra since they are doing things they aren't supposed to + return Self::unimplemented() * 10; } - (_, "debug_traceBlockByNumber") => { - return Self::variable_price(chain_id, method, response_bytes) + 497 - } - (_, "debug_traceCall") => { - return Self::variable_price(chain_id, method, response_bytes) + 309 - } - (_, "debug_traceTransaction") => { - return Self::variable_price(chain_id, method, response_bytes) + 309 - } - (_, "erigon_forks") => 24, - (_, "erigon_getHeaderByHash") => 24, - (_, "erigon_getHeaderByNumber") => 24, - (_, "erigon_getLogsByHash") => 24, - (_, "erigon_issuance") => 24, - (_, "eth_accounts") => 10, - (_, "eth_blockNumber") => 10, - (_, "eth_call") => 26, - (_, "eth_chainId") => 0, - (_, "eth_createAccessList") => 10, - (_, "eth_estimateGas") => 87, - (_, "eth_estimateUserOperationGas") => 500, - (_, "eth_feeHistory") => 10, - (_, "eth_gasPrice") => 19, - (_, "eth_getBalance") => 19, - (_, "eth_getBlockByHash") => 21, - (_, "eth_getBlockByNumber") => 16, - (_, "eth_getBlockReceipts") => 500, - (_, "eth_getBlockTransactionCountByHash") => 20, - (_, "eth_getBlockTransactionCountByNumber") => 20, - (_, "eth_getCode") => 19, - (_, "eth_getFilterChanges") => 20, - (_, "eth_getFilterLogs") => 75, - (_, "eth_getLogs") => 75, - (_, "eth_getProof") => 21, - (_, "eth_getStorageAt") => 17, - (_, "eth_getTransactionByBlockHashAndIndex") => 15, - (_, "eth_getTransactionByBlockNumberAndIndex") => 15, - (_, "eth_getTransactionByHash") => 17, - (_, "eth_getTransactionCount") => 26, - (_, "eth_getTransactionReceipt") => 15, - (_, "eth_getUncleByBlockHashAndIndex") => 15, - (_, "eth_getUncleByBlockNumberAndIndex") => 15, - (_, "eth_getUncleCountByBlockHash") => 15, - (_, "eth_getUncleCountByBlockNumber") => 15, - (_, "eth_getUserOperationByHash") => 17, - (_, "eth_getUserOperationReceipt") => 15, - (_, "eth_maxPriorityFeePerGas") => 10, - (_, "eth_newBlockFilter") => { - // TODO: 20 + + if method.starts_with("alchemy_") + || method.starts_with("personal_") + || method.starts_with("shh_") + || method.starts_with("db_") + { + // maybe charge extra since they are doing things they aren't supposed to return Self::unimplemented(); - } - (_, "eth_newFilter") => { - // TODO: 20 - return Self::unimplemented(); - } - (_, "eth_newPendingTransactionFilter") => { - // TODO: 20 - return Self::unimplemented(); - } - (_, "eth_pollSubscriptions") => { - return Self::unimplemented(); - } - (_, "eth_protocolVersion") => 0, - (_, "eth_sendRawTransaction") => 250, - (_, "eth_sendUserOperation") => 1000, - (_, "eth_subscribe") => 10, - (_, "eth_supportedEntryPoints") => 5, - (_, "eth_syncing") => 0, - (_, "eth_uninstallFilter") => 10, - (_, "eth_unsubscribe") => 10, - (_, "net_listening") => 0, - (_, "net_version") => 0, - (_, "test") => 0, - (_, "trace_block") => 24, - (_, "trace_call") => 75, - (_, "trace_callMany") => 75 * 3, - (_, "trace_filter") => 75, - (_, "trace_get") => 17, - (_, "trace_rawTransaction") => 75, - (_, "trace_replayBlockTransactions") => 2983, - (_, "trace_replayTransaction") => 2983, - (_, "trace_transaction") => 26, - (_, "txpool_content") => { - return Self::variable_price(chain_id, method, response_bytes) + 1000; - } - (_, "invalid_method") => 100, - (_, "web3_clientVersion") => 15, - (_, "web3_bundlerVersion") => 15, - (_, "web3_sha3") => 15, - (_, "ots_getInternalOperations") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_hasCode") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_getTransactionError") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_traceTransaction") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_getBlockDetails") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_getBlockDetailsByHash") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_getBlockTransactions") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_searchTransactionsBefore") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_searchTransactionsAfter") => { - return Self::variable_price(chain_id, method, response_bytes) + 100 - } - (_, "ots_getTransactionBySenderAndNonce") => 1000, - (_, "ots_getContractCreator") => 1000, - (_, method) => { - // TODO: emit a stat - warn!("unknown method {}", method); + + warn!(%response_bytes, "unknown method {}", method); return Self::unimplemented() + Self::variable_price(chain_id, method, response_bytes).0; }