Skip to content

Commit

Permalink
indexer: unmarshal RawTx on GetTx methods
Browse files Browse the repository at this point in the history
  • Loading branch information
altergui committed Jul 26, 2024
1 parent d52ed23 commit 151a3a3
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 44 deletions.
10 changes: 5 additions & 5 deletions api/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ func (a *API) chainTxRefByHashHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCo
if err != nil {
return err
}
ref, err := a.indexer.GetTxReferenceByHash(hash)
ref, err := a.indexer.GetTxMetadataByHash(hash)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand Down Expand Up @@ -649,7 +649,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 @@ -670,8 +670,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 @@ -684,7 +684,7 @@ func (a *API) chainTxRefByIndexHandler(_ *apirest.APIdata, ctx *httprouter.HTTPC
if err != nil {
return err
}
ref, err := a.indexer.GetTxReferenceByID(index)
ref, err := a.indexer.GetTxMetadataByID(index)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand Down
6 changes: 3 additions & 3 deletions vochain/indexer/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func BenchmarkIndexer(b *testing.B) {
qt.Check(b, bytes.Equal(voteRef.Meta.TxHash, tx.TxID[:]), qt.IsTrue)
}

txRef, err := idx.GetTxReferenceByHash(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 Down Expand Up @@ -152,14 +152,14 @@ func BenchmarkFetchTx(b *testing.B) {

startTime := time.Now()
for j := 0; j < numTxs; j++ {
_, err = idx.GetTxReferenceByID(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.GetTxReferenceByHash([]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
4 changes: 2 additions & 2 deletions vochain/indexer/indexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1405,15 +1405,15 @@ func TestTxIndexer(t *testing.T) {

for i := 0; i < totalBlocks; i++ {
for j := 0; j < txsPerBlock; j++ {
ref, err := idx.GetTxReferenceByID(uint64(i*txsPerBlock + j + 1))
ref, err := idx.GetTxMetadataByID(uint64(i*txsPerBlock + j + 1))
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, ref.BlockHeight, qt.Equals, uint32(i))
qt.Assert(t, ref.TxBlockIndex, qt.Equals, int32(j))
qt.Assert(t, ref.TxType, qt.Equals, "setAccount")
h := make([]byte, 32)
id := getTxID(i, j)
copy(h, id[:])
hashRef, err := idx.GetTxReferenceByHash(h)
hashRef, err := idx.GetTxMetadataByHash(h)
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, hashRef.BlockHeight, qt.Equals, uint32(i))
qt.Assert(t, hashRef.TxBlockIndex, qt.Equals, int32(j))
Expand Down
53 changes: 36 additions & 17 deletions vochain/indexer/indexertypes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"go.vocdoni.io/dvote/types"
indexerdb "go.vocdoni.io/dvote/vochain/indexer/db"
"go.vocdoni.io/dvote/vochain/results"
"go.vocdoni.io/dvote/vochain/transaction/vochaintx"
"go.vocdoni.io/proto/build/go/models"
"google.golang.org/protobuf/proto"
)
Expand Down Expand Up @@ -176,46 +177,64 @@ type TxPackage struct {
Signature types.HexBytes `json:"signature"`
}

// TxMetadata contains tx information for the TransactionList api
type TxMetadata struct {
Type string `json:"type"`
BlockHeight uint32 `json:"blockHeight,omitempty"`
Index int32 `json:"index"`
Hash types.HexBytes `json:"hash"`
}

// Transaction holds the db reference for a single transaction
type Transaction struct {
// TransactionMetadata contains tx information for the TransactionList api
type TransactionMetadata struct {
Index uint64 `json:"transactionNumber" format:"int64" example:"944"`
Hash types.HexBytes `json:"transactionHash" swaggertype:"string" example:"75e8f822f5dd13973ac5158d600f0a2a5fea4bfefce9712ab5195bf17884cfad"`
BlockHeight uint32 `json:"blockHeight" format:"int32" example:"64924"`
TxBlockIndex int32 `json:"transactionIndex" format:"int32" example:"0"`
TxType string `json:"transactionType" enums:"vote,newProcess,admin,setProcess,registerKey,mintTokens,sendTokens,setTransactionCosts,setAccount,collectFaucet,setKeykeeper" example:"Vote"`
RawTx types.HexBytes `json:"rawTx"`
}

func TransactionFromDB(dbtx *indexerdb.Transaction) *Transaction {
return &Transaction{
func TransactionMetadataFromDB(dbtx *indexerdb.Transaction) *TransactionMetadata {
return &TransactionMetadata{
Index: uint64(dbtx.ID),
Hash: dbtx.Hash,
BlockHeight: uint32(dbtx.BlockHeight),
TxBlockIndex: int32(dbtx.BlockIndex),
TxType: dbtx.Type,
RawTx: dbtx.RawTx,
}
}

func TransactionFromDBRow(dbtx *indexerdb.SearchTransactionsRow) *Transaction {
return &Transaction{
func TransactionMetadataFromDBRow(dbtx *indexerdb.SearchTransactionsRow) *TransactionMetadata {
return &TransactionMetadata{
Index: uint64(dbtx.ID),
Hash: dbtx.Hash,
BlockHeight: uint32(dbtx.BlockHeight),
TxBlockIndex: int32(dbtx.BlockIndex),
TxType: dbtx.Type,
RawTx: dbtx.RawTx,
}
}

// Transaction holds the db reference for a single transaction
type Transaction struct {
*TransactionMetadata
RawTx types.HexBytes `json:"rawTx,omitempty"`
Tx *vochaintx.Tx
}

func TransactionFromDB(dbtx *indexerdb.Transaction, chainID string) *Transaction {
tx := &Transaction{
TransactionMetadata: TransactionMetadataFromDB(dbtx),
RawTx: dbtx.RawTx,
}
if err := tx.Tx.Unmarshal(tx.RawTx, chainID); err != nil {
log.Errorw(err, "couldn't unmarshal rawTx from indexer")
}
return tx
}

func TransactionFromDBRow(dbtx *indexerdb.TransactionListByHeightRow, chainID string) *Transaction {

Check failure on line 227 in vochain/indexer/indexertypes/types.go

View workflow job for this annotation

GitHub Actions / job_go_checks

undefined: indexerdb.TransactionListByHeightRow

Check failure on line 227 in vochain/indexer/indexertypes/types.go

View workflow job for this annotation

GitHub Actions / job_go_test

undefined: indexerdb.TransactionListByHeightRow
tx := &Transaction{
TransactionMetadata: TransactionMetadataFromDBRow(dbtx),
RawTx: dbtx.RawTx,
}
if err := tx.Tx.Unmarshal(tx.RawTx, chainID); err != nil {
log.Errorw(err, "couldn't unmarshal rawTx from indexer")
}
return tx
}

// TokenTransferMeta contains the information of a token transfer and some extra useful information.
// The types are compatible with the SQL defined schema.
type TokenTransferMeta struct {
Expand Down
42 changes: 25 additions & 17 deletions vochain/indexer/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,47 @@ func (idx *Indexer) CountTransactionsByHeight(height int64) (int64, error) {
return idx.readOnlyQuery.CountTransactionsByHeight(context.TODO(), height)
}

// GetTxReferenceByID fetches the txReference for the given tx height
func (idx *Indexer) GetTxReferenceByID(id uint64) (*indexertypes.Transaction, error) {
// GetTxMetadataByID fetches the tx metadata for the given tx height
func (idx *Indexer) GetTxMetadataByID(id uint64) (*indexertypes.TransactionMetadata, error) {
sqlTxRef, err := idx.readOnlyQuery.GetTransaction(context.TODO(), int64(id))
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrTransactionNotFound
}
return nil, fmt.Errorf("tx with id %d not found: %v", id, err)
}
return indexertypes.TransactionFromDB(&sqlTxRef), nil
return indexertypes.TransactionMetadataFromDB(&sqlTxRef), nil
}

// GetTxReferenceByBlockHeightAndBlockIndex fetches the txReference for the given tx height and block tx index
func (idx *Indexer) GetTxReferenceByBlockHeightAndBlockIndex(blockHeight, blockIndex int64) (*indexertypes.Transaction, error) {
sqlTxRef, err := idx.readOnlyQuery.GetTxReferenceByBlockHeightAndBlockIndex(context.TODO(), indexerdb.GetTxReferenceByBlockHeightAndBlockIndexParams{
BlockHeight: blockHeight,
BlockIndex: blockIndex,
})
// GetTxMetadataByHash fetches the tx metadata for the given tx hash
func (idx *Indexer) GetTxMetadataByHash(hash types.HexBytes) (*indexertypes.TransactionMetadata, error) {
sqlTxRef, err := idx.readOnlyQuery.GetTransactionByHash(context.TODO(), hash)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrTransactionNotFound
}
return nil, fmt.Errorf("tx at block %d and index %d not found: %v", blockHeight, blockIndex, err)
return nil, fmt.Errorf("tx hash %x not found: %v", hash, err)
}
return indexertypes.TransactionFromDB(&sqlTxRef), nil
return indexertypes.TransactionMetadataFromDB(&sqlTxRef), nil
}

// GetTxReferenceByHash fetches the txReference for the given tx hash
func (idx *Indexer) GetTxReferenceByHash(hash types.HexBytes) (*indexertypes.Transaction, error) {
sqlTxRef, err := idx.readOnlyQuery.GetTransactionByHash(context.TODO(), hash)
// GetTxByBlockHeightAndBlockIndex fetches the txReference for the given tx height and block tx index
func (idx *Indexer) GetTxByBlockHeightAndBlockIndex(blockHeight, blockIndex int64) (*indexertypes.Transaction, error) {
sqlTxRef, err := idx.readOnlyQuery.GetTxReferenceByBlockHeightAndBlockIndex(context.TODO(), indexerdb.GetTxReferenceByBlockHeightAndBlockIndexParams{
BlockHeight: blockHeight,
BlockIndex: blockIndex,
})
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrTransactionNotFound
}
return nil, fmt.Errorf("tx hash %x not found: %v", hash, err)
return nil, fmt.Errorf("tx at block %d and index %d not found: %v", blockHeight, blockIndex, err)
}
block, err := idx.readOnlyQuery.GetBlockByHeight(context.TODO(), blockHeight)
if err != nil {
return nil, fmt.Errorf("block %d not found: %w", blockHeight, err)
}
return indexertypes.TransactionFromDB(&sqlTxRef), nil
return indexertypes.TransactionFromDB(&sqlTxRef, block.ChainID), nil
}

// SearchTransactions returns the list of transactions indexed.
Expand Down Expand Up @@ -118,7 +122,11 @@ func (idx *Indexer) TransactionListByHeight(height, limit, offset int64) ([]*ind
}
list := make([]*indexertypes.Transaction, len(results))
for i, row := range results {
list[i] = indexertypes.TransactionFromDBRow(&row)
block, err := idx.readOnlyQuery.GetBlockByHeight(context.TODO(), row.BlockHeight)
if err != nil {
return nil, 0, fmt.Errorf("block %d not found: %w", row.BlockHeight, err)
}
list[i] = indexertypes.TransactionFromDBRow(&row, block.ChainID)
}
return list, uint64(results[0].TotalCount), nil
}
Expand Down

0 comments on commit 151a3a3

Please sign in to comment.