Skip to content

Commit

Permalink
Merge branches 'feat/api-refactor-pagination' (early part) and 'feat/…
Browse files Browse the repository at this point in the history
…index-blocks' (early part) into dev
  • Loading branch information
altergui committed Jul 23, 2024
2 parents f68c27c + f4715f1 commit 5e45732
Show file tree
Hide file tree
Showing 24 changed files with 475 additions and 148 deletions.
1 change: 1 addition & 0 deletions api/api_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,5 @@ func CensusTypeToOrigin(ctype CensusTypeDescription) (models.CensusOrigin, []byt
type Block struct {
comettypes.Block `json:",inline"`
Hash types.HexBytes `json:"hash" `
TxCount int64 `json:"txCount"`
}
65 changes: 45 additions & 20 deletions api/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"go.vocdoni.io/dvote/crypto/zk/circuit"
"go.vocdoni.io/dvote/httprouter"
"go.vocdoni.io/dvote/httprouter/apirest"
"go.vocdoni.io/dvote/types"
"go.vocdoni.io/dvote/util"
"go.vocdoni.io/dvote/vochain"
"go.vocdoni.io/dvote/vochain/genesis"
Expand Down Expand Up @@ -634,7 +633,7 @@ func (a *API) chainTxbyHashHandler(_ *apirest.APIdata, ctx *httprouter.HTTPConte
if err != nil {
return err
}
ref, err := a.indexer.GetTxHashReference(hash)
ref, err := a.indexer.GetTxReferenceByHash(hash)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand Down Expand Up @@ -713,7 +712,7 @@ func (a *API) chainTxByIndexHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCont
if err != nil {
return err
}
ref, err := a.indexer.GetTransaction(index)
ref, err := a.indexer.GetTxReferenceByID(index)
if err != nil {
if errors.Is(err, indexer.ErrTransactionNotFound) {
return ErrTransactionNotFound
Expand Down Expand Up @@ -776,7 +775,7 @@ func (a *API) chainTxByHeightHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCon
tx.ProtoReflect().Descriptor().Oneofs().Get(0)).Name())

// TODO: can we avoid indexer Get calls in a loop?
txRef, err := a.indexer.GetTxHashReference(block.Txs[i].Hash())
txRef, err := a.indexer.GetTxReferenceByHash(block.Txs[i].Hash())
if err != nil {
return ErrTransactionNotFound
}
Expand Down Expand Up @@ -845,18 +844,31 @@ func (a *API) chainBlockHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext)
if err != nil {
return err
}
tmblock := a.vocapp.GetBlockByHeight(int64(height))
if tmblock == nil {
return ErrBlockNotFound
idxblock, err := a.indexer.BlockByHeight(int64(height))
if err != nil {
if errors.Is(err, indexer.ErrBlockNotFound) {
return ErrBlockNotFound
}
return ErrBlockNotFound.WithErr(err)
}
txcount, err := a.indexer.CountTransactionsByHeight(int64(height))
if err != nil {
return ErrIndexerQueryFailed.WithErr(err)
}
block := &Block{
Block: comettypes.Block{
Header: tmblock.Header,
Data: tmblock.Data,
Evidence: tmblock.Evidence,
LastCommit: tmblock.LastCommit,
Header: comettypes.Header{
ChainID: idxblock.ChainID,
Height: idxblock.Height,
Time: idxblock.Time,
ProposerAddress: []byte(idxblock.ProposerAddress),
LastBlockID: comettypes.BlockID{
Hash: []byte(idxblock.LastBlockHash),
},
},
},
Hash: types.HexBytes(tmblock.Hash()),
Hash: idxblock.Hash,
TxCount: txcount,
}
data, err := json.Marshal(block)
if err != nil {
Expand All @@ -880,18 +892,31 @@ func (a *API) chainBlockByHashHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCo
if err != nil {
return err
}
tmblock := a.vocapp.GetBlockByHash(hash)
if tmblock == nil {
return ErrBlockNotFound
idxblock, err := a.indexer.BlockByHash(hash)
if err != nil {
if errors.Is(err, indexer.ErrBlockNotFound) {
return ErrBlockNotFound
}
return ErrBlockNotFound.WithErr(err)
}
txcount, err := a.indexer.CountTransactionsByHeight(idxblock.Height)
if err != nil {
return ErrIndexerQueryFailed.WithErr(err)
}
block := &Block{
Block: comettypes.Block{
Header: tmblock.Header,
Data: tmblock.Data,
Evidence: tmblock.Evidence,
LastCommit: tmblock.LastCommit,
Header: comettypes.Header{
ChainID: idxblock.ChainID,
Height: idxblock.Height,
Time: idxblock.Time,
ProposerAddress: []byte(idxblock.ProposerAddress),
LastBlockID: comettypes.BlockID{
Hash: []byte(idxblock.LastBlockHash),
},
},
},
Hash: types.HexBytes(tmblock.Hash()),
Hash: idxblock.Hash,
TxCount: txcount,
}
data, err := json.Marshal(block)
if err != nil {
Expand Down
35 changes: 35 additions & 0 deletions test/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,41 @@ func TestAPIAccountTokentxs(t *testing.T) {
qt.Assert(t, gotAcct1.Balance, qt.Equals, initBalance+amountAcc2toAcct1-amountAcc1toAcct2-uint64(txBasePrice))
}

func TestAPIBlocks(t *testing.T) {
server := testcommon.APIserver{}
server.Start(t,
api.ChainHandler,
api.CensusHandler,
api.VoteHandler,
api.AccountHandler,
api.ElectionHandler,
api.WalletHandler,
)
token1 := uuid.New()
c := testutil.NewTestHTTPclient(t, server.ListenAddr, &token1)

// Block 1
server.VochainAPP.AdvanceTestBlock()
waitUntilHeight(t, c, 1)

// create a new account
initBalance := uint64(80)
_ = createAccount(t, c, server, initBalance)

// Block 2
server.VochainAPP.AdvanceTestBlock()
waitUntilHeight(t, c, 2)

// check the txCount
resp, code := c.Request("GET", nil, "chain", "blocks", "1")
qt.Assert(t, code, qt.Equals, 200, qt.Commentf("response: %s", resp))

block := api.Block{}
err := json.Unmarshal(resp, &block)
qt.Assert(t, err, qt.IsNil)
qt.Assert(t, block.TxCount, qt.Equals, int64(1))
}

func runAPIElectionCostWithParams(t *testing.T,
electionParams electionprice.ElectionParameters,
startBlock uint32, initialBalance,
Expand Down
4 changes: 0 additions & 4 deletions vochain/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,6 @@ func (app *BaseApplication) beginBlock(t time.Time, height uint32) {
app.State.SetHeight(height)

go app.State.CachePurge(height)
app.State.OnBeginBlock(vstate.BeginBlock{
Height: int64(height),
Time: t,
})
}

// endBlock is called at the end of every block.
Expand Down
3 changes: 0 additions & 3 deletions vochain/appsetup.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ func (app *BaseApplication) SetNode(vochaincfg *config.VochainCfg) error {
if app.Node, err = newTendermint(app, vochaincfg); err != nil {
return fmt.Errorf("could not set tendermint node service: %s", err)
}
if vochaincfg.IsSeedNode {
return nil
}
// Note that cometcli.New logs any error rather than returning it.
app.NodeClient = cometcli.New(app.Node)
return nil
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.GetTxReferenceByHash(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.GetTxReferenceByID(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.GetTxReferenceByHash([]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
44 changes: 25 additions & 19 deletions vochain/indexer/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,41 @@ import (
"fmt"
"time"

"go.vocdoni.io/dvote/log"
indexerdb "go.vocdoni.io/dvote/vochain/indexer/db"
"go.vocdoni.io/dvote/vochain/state"
"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")

func (idx *Indexer) OnBeginBlock(bb state.BeginBlock) {
idx.blockMu.Lock()
defer idx.blockMu.Unlock()
queries := idx.blockTxQueries()
if _, err := queries.CreateBlock(context.TODO(), indexerdb.CreateBlockParams{
Height: bb.Height,
Time: bb.Time,
DataHash: nonNullBytes(bb.DataHash),
}); err != nil {
log.Errorw(err, "cannot index new block")
// BlockTimestamp returns the timestamp of the block at the given height
func (idx *Indexer) BlockTimestamp(height int64) (time.Time, error) {
block, err := idx.BlockByHeight(height)
if err != nil {
return time.Time{}, err
}
return block.Time, nil
}

// 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)
// 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 time.Time{}, ErrBlockNotFound
return nil, ErrBlockNotFound
}
return time.Time{}, err
return nil, err
}
return block.Time, nil
return indexertypes.BlockFromDB(&block), nil
}

// BlockByHeight 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
}
59 changes: 48 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 5e45732

Please sign in to comment.