Skip to content

Commit

Permalink
indexer: index more details about blocks and transactions
Browse files Browse the repository at this point in the history
* indexerdb: add block details chain_id, proposer_address and last_block_hash
* indexerdb: rename method GetBlock -> GetBlockByHeight
* indexerdb: new method GetBlockByHash
* indexerdb: new method SearchBlocks
* indexer: new method BlockByHeight
* indexer: new method SearchBlocks

transactions:
* indexerdb: add raw_tx and signature in transactions table
* indexer: add CountTransactionsByHeight and SearchTransactions
* indexer: rename GetTransaction* methods -> GetTxMetadata*
  • Loading branch information
altergui committed Aug 23, 2024
1 parent ff4aaa1 commit e27cf8a
Show file tree
Hide file tree
Showing 17 changed files with 528 additions and 172 deletions.
4 changes: 2 additions & 2 deletions api/api_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ type TransactionReference struct {

// TransactionsList is used to return a paginated list to the client
type TransactionsList struct {
Transactions []*indexertypes.Transaction `json:"transactions"`
Pagination *Pagination `json:"pagination"`
Transactions []*indexertypes.TransactionMetadata `json:"transactions"`
Pagination *Pagination `json:"pagination"`
}

// FeesList is used to return a paginated list to the client
Expand Down
10 changes: 5 additions & 5 deletions api/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ func (a *API) chainTxRefByHashHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCo
if err != nil {
return err
}
ref, err := a.indexer.GetTxHashReference(hash)
ref, err := a.indexer.GetTxMetadataByHash(hash)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand Down Expand Up @@ -698,7 +698,7 @@ func (a *API) chainTxHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) er
return ErrVochainGetTxFailed.WithErr(err)
}

ref, err := a.indexer.GetTxReferenceByBlockHeightAndBlockIndex(height, index)
ref, err := a.indexer.GetTxByBlockHeightAndBlockIndex(height, index)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand All @@ -719,8 +719,8 @@ func (a *API) chainTxHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) er

// chainTxRefByIndexHandler
//
// @Summary Transaction by index
// @Description Get transaction by its index. This is not transaction reference (hash), and neither the block height and block index. The transaction index is an incremental counter for each transaction. You could use the transaction `block` and `index` to retrieve full info using [transaction by block and index](transaction-by-block-index).
// @Summary Transaction metadata (by db index)
// @Description Get transaction by its internal index. This is not the transaction hash, and neither the block height and block index. The transaction index is an incremental counter for each transaction. You could use the transaction `block` and `index` to retrieve full info using [transaction by block and index](transaction-by-block-index).
// @Tags Chain
// @Accept json
// @Produce json
Expand All @@ -733,7 +733,7 @@ func (a *API) chainTxRefByIndexHandler(_ *apirest.APIdata, ctx *httprouter.HTTPC
if err != nil {
return err
}
ref, err := a.indexer.GetTransaction(index)
ref, err := a.indexer.GetTxMetadataByID(index)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand Down
13 changes: 9 additions & 4 deletions vochain/indexer/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func BenchmarkIndexer(b *testing.B) {
tx := &vochaintx.Tx{
TxID: rnd.Random32(),
TxModelType: "vote",
Tx: &models.Tx{Payload: &models.Tx_Vote{}},
}
idx.OnNewTx(tx, height, txBlockIndex)
curTxs = append(curTxs, tx)
Expand Down Expand Up @@ -112,7 +113,7 @@ func BenchmarkIndexer(b *testing.B) {
qt.Check(b, bytes.Equal(voteRef.Meta.TxHash, tx.TxID[:]), qt.IsTrue)
}

txRef, err := idx.GetTxHashReference(tx.TxID[:])
txRef, err := idx.GetTxMetadataByHash(tx.TxID[:])
qt.Check(b, err, qt.IsNil)
if err == nil {
qt.Check(b, txRef.BlockHeight, qt.Equals, vote.Height)
Expand All @@ -138,7 +139,11 @@ func BenchmarkFetchTx(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < numTxs; j++ {
idx.OnNewTx(&vochaintx.Tx{TxID: util.Random32()}, uint32(i), int32(j))
idx.OnNewTx(&vochaintx.Tx{
TxID: util.Random32(),
TxModelType: "vote",
Tx: &models.Tx{Payload: &models.Tx_Vote{}},
}, uint32(i), int32(j))
}
err := idx.Commit(uint32(i))
qt.Assert(b, err, qt.IsNil)
Expand All @@ -147,14 +152,14 @@ func BenchmarkFetchTx(b *testing.B) {

startTime := time.Now()
for j := 0; j < numTxs; j++ {
_, err = idx.GetTransaction(uint64((i * numTxs) + j + 1))
_, err = idx.GetTxMetadataByID(uint64((i * numTxs) + j + 1))
qt.Assert(b, err, qt.IsNil)
}
log.Infof("fetched %d transactions (out of %d total) by index, took %s",
numTxs, (i+1)*numTxs, time.Since(startTime))
startTime = time.Now()
for j := 0; j < numTxs; j++ {
_, err = idx.GetTxHashReference([]byte(fmt.Sprintf("hash%d%d", i, j)))
_, err = idx.GetTxMetadataByHash([]byte(fmt.Sprintf("hash%d%d", i, j)))
qt.Assert(b, err, qt.IsNil)
}
log.Infof("fetched %d transactions (out of %d total) by hash, took %s",
Expand Down
62 changes: 58 additions & 4 deletions vochain/indexer/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,73 @@ import (
"errors"
"fmt"
"time"

indexerdb "go.vocdoni.io/dvote/vochain/indexer/db"
"go.vocdoni.io/dvote/vochain/indexer/indexertypes"
)

// ErrBlockNotFound is returned if the block is not found in the indexer database.
var ErrBlockNotFound = fmt.Errorf("block not found")

// BlockTimestamp returns the timestamp of the block at the given height
func (idx *Indexer) BlockTimestamp(height int64) (time.Time, error) {
block, err := idx.readOnlyQuery.GetBlock(context.TODO(), height)
block, err := idx.BlockByHeight(height)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return time.Time{}, ErrBlockNotFound
}
return time.Time{}, err
}
return block.Time, nil
}

// BlockByHeight returns the available information of the block at the given height
func (idx *Indexer) BlockByHeight(height int64) (*indexertypes.Block, error) {
block, err := idx.readOnlyQuery.GetBlockByHeight(context.TODO(), height)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrBlockNotFound
}
return nil, err
}
return indexertypes.BlockFromDB(&block), nil
}

// BlockByHash returns the available information of the block with the given hash
func (idx *Indexer) BlockByHash(hash []byte) (*indexertypes.Block, error) {
block, err := idx.readOnlyQuery.GetBlockByHash(context.TODO(), hash)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrBlockNotFound
}
return nil, err
}
return indexertypes.BlockFromDB(&block), nil
}

// BlockList returns the list of blocks indexed.
// chainID, hash, proposerAddress are optional, if declared as zero-value will be ignored.
// The first one returned is the newest, so they are in descending order.
func (idx *Indexer) BlockList(limit, offset int, chainID, hash, proposerAddress string) ([]*indexertypes.Block, uint64, error) {
if offset < 0 {
return nil, 0, fmt.Errorf("invalid value: offset cannot be %d", offset)
}
if limit <= 0 {
return nil, 0, fmt.Errorf("invalid value: limit cannot be %d", limit)
}
results, err := idx.readOnlyQuery.SearchBlocks(context.TODO(), indexerdb.SearchBlocksParams{
Limit: int64(limit),
Offset: int64(offset),
ChainID: chainID,
HashSubstr: hash,
ProposerAddress: proposerAddress,
})
if err != nil {
return nil, 0, err
}
list := []*indexertypes.Block{}
for _, row := range results {
list = append(list, indexertypes.BlockFromDBRow(&row))
}
if len(results) == 0 {
return list, 0, nil
}
return list, uint64(results[0].TotalCount), nil
}
141 changes: 130 additions & 11 deletions vochain/indexer/db/blocks.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e27cf8a

Please sign in to comment.