From aa4eac3edb2a71b177e13d260d4fe3f05a329c41 Mon Sep 17 00:00:00 2001 From: catalyst17 <37663786+catalyst17@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:47:00 +0100 Subject: [PATCH] feat: enable transactions look-up by signatures --- internal/handlers/transactions_handlers.go | 12 ++++++------ internal/rpc/serializer.go | 4 ++-- internal/storage/clickhouse.go | 17 ++++++++++++++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/internal/handlers/transactions_handlers.go b/internal/handlers/transactions_handlers.go index 284e17d..efb5c09 100644 --- a/internal/handlers/transactions_handlers.go +++ b/internal/handlers/transactions_handlers.go @@ -3,6 +3,7 @@ package handlers import ( "net/http" + "github.com/ethereum/go-ethereum/crypto" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" "github.com/thirdweb-dev/indexer/api" @@ -104,8 +105,8 @@ func GetTransactionsByContract(c *gin.Context) { // @Router /{chainId}/transactions/{to}/{signature} [get] func GetTransactionsByContractAndSignature(c *gin.Context) { to := c.Param("to") - // TODO: Implement signature lookup before activating this - handleTransactionsRequest(c, to, "") + signature := c.Param("signature") + handleTransactionsRequest(c, to, signature) } func handleTransactionsRequest(c *gin.Context, contractAddress, signature string) { @@ -122,10 +123,9 @@ func handleTransactionsRequest(c *gin.Context, contractAddress, signature string } signatureHash := "" - // TODO: implement signature lookup - // if signature != "" { - // signatureHash = crypto.Keccak256Hash([]byte(signature)).Hex() - // } + if signature != "" { + signatureHash = crypto.Keccak256Hash([]byte(signature)).Hex() + } mainStorage, err := getMainStorage() if err != nil { diff --git a/internal/rpc/serializer.go b/internal/rpc/serializer.go index cac2e31..030c198 100644 --- a/internal/rpc/serializer.go +++ b/internal/rpc/serializer.go @@ -185,7 +185,7 @@ func serializeTransaction(chainId *big.Int, tx map[string]interface{}, blockTime Gas: hexToUint64(tx["gas"]), GasPrice: hexToBigInt(tx["gasPrice"]), Data: interfaceToString(tx["input"]), - FunctionSelector: extractFunctionSelector(interfaceToString(tx["input"])), + FunctionSelector: ExtractFunctionSelector(interfaceToString(tx["input"])), MaxFeePerGas: hexToBigInt(tx["maxFeePerGas"]), MaxPriorityFeePerGas: hexToBigInt(tx["maxPriorityFeePerGas"]), TransactionType: uint8(hexToUint64(tx["type"])), @@ -270,7 +270,7 @@ func serializeTransaction(chainId *big.Int, tx map[string]interface{}, blockTime /** * Extracts the function selector (first 4 bytes) from a transaction input. */ -func extractFunctionSelector(s string) string { +func ExtractFunctionSelector(s string) string { if len(s) < 10 { return "" } diff --git a/internal/storage/clickhouse.go b/internal/storage/clickhouse.go index 320f5ed..9bbfc94 100644 --- a/internal/storage/clickhouse.go +++ b/internal/storage/clickhouse.go @@ -18,6 +18,7 @@ import ( zLog "github.com/rs/zerolog/log" config "github.com/thirdweb-dev/indexer/configs" "github.com/thirdweb-dev/indexer/internal/common" + "github.com/thirdweb-dev/indexer/internal/rpc" ) type ClickHouseConnector struct { @@ -339,7 +340,7 @@ func (c *ClickHouseConnector) GetBlocks(qf QueryFilter) (blocks []common.Block, } func (c *ClickHouseConnector) GetTransactions(qf QueryFilter) (QueryResult[common.Transaction], error) { - columns := "chain_id, hash, nonce, block_hash, block_number, block_timestamp, transaction_index, from_address, to_address, value, gas, gas_price, data, max_fee_per_gas, max_priority_fee_per_gas, transaction_type, r, s, v, access_list" + columns := "chain_id, hash, nonce, block_hash, block_number, block_timestamp, transaction_index, from_address, to_address, value, gas, gas_price, data, function_selector, max_fee_per_gas, max_priority_fee_per_gas, transaction_type, r, s, v, access_list" return executeQuery[common.Transaction](c, "transactions", columns, qf, scanTransaction) } @@ -359,7 +360,7 @@ func (c *ClickHouseConnector) GetAggregations(table string, qf QueryFilter) (Que } query = addContractAddress(table, query, qf.ContractAddress) if qf.Signature != "" { - query += fmt.Sprintf(" AND topic_0 = '%s'", qf.Signature) + query = addSignatureClause(table, query, qf.Signature) } for key, value := range qf.FilterParams { query = addFilterParams(key, strings.ToLower(value), query) @@ -452,7 +453,7 @@ func (c *ClickHouseConnector) buildQuery(table, columns string, qf QueryFilter) // Add signature clause if qf.Signature != "" { - query += fmt.Sprintf(" AND topic_0 = '%s'", qf.Signature) + query = addSignatureClause(table, query, qf.Signature) } // Add filter params for key, value := range qf.FilterParams { @@ -516,6 +517,15 @@ func addContractAddress(table, query string, contractAddress string) string { return query } +func addSignatureClause(table, query, signature string) string { + if table == "logs" { + query += fmt.Sprintf(" AND topic_0 = '%s'", signature) + } else if table == "transactions" { + query += fmt.Sprintf(" AND function_selector = '%s'", rpc.ExtractFunctionSelector(signature)) + } + return query +} + func getTopicValueFormat(topic string) string { if topic == "" { // if there is no indexed topic, indexer stores an empty string @@ -545,6 +555,7 @@ func scanTransaction(rows driver.Rows) (common.Transaction, error) { &tx.Gas, &tx.GasPrice, &tx.Data, + &tx.FunctionSelector, &tx.MaxFeePerGas, &tx.MaxPriorityFeePerGas, &tx.TransactionType,