Skip to content

Commit 0d2aba6

Browse files
authored
Merge pull request #31 from flare-foundation/list-transactions-api
Add new API route to list transactions for epoch
2 parents ac187bf + 6ea2153 commit 0d2aba6

5 files changed

Lines changed: 121 additions & 42 deletions

File tree

services/api/pchain.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,40 @@ func newApiPChainOutputs(inputs []database.PChainTxOutput) []ApiPChainTxOutput {
6767
}
6868
return result
6969
}
70+
71+
type ApiPChainTxListItem struct {
72+
Type database.PChainTxType `json:"type"`
73+
TxID *string `json:"txID"`
74+
BlockHeight uint64 `json:"blockHeight"`
75+
ChainID string `json:"chainID"`
76+
NodeID string `json:"nodeID"`
77+
StartTime *time.Time `json:"startTime"`
78+
EndTime *time.Time `json:"endTime"`
79+
Weight uint64 `json:"weight"`
80+
InputAddress string `json:"inputAddress"`
81+
InputIndex uint32 `json:"inputIndex"`
82+
}
83+
84+
func newApiPChainTxListItem(tx *database.PChainTxData) ApiPChainTxListItem {
85+
return ApiPChainTxListItem{
86+
Type: tx.Type,
87+
TxID: tx.TxID,
88+
BlockHeight: tx.BlockHeight,
89+
ChainID: tx.ChainID,
90+
NodeID: tx.NodeID,
91+
StartTime: tx.StartTime,
92+
EndTime: tx.EndTime,
93+
Weight: tx.Weight,
94+
InputAddress: tx.InputAddress,
95+
InputIndex: tx.InputIndex,
96+
}
97+
}
98+
99+
func NewApiPChainTxList(txs []database.PChainTxData) []ApiPChainTxListItem {
100+
result := make([]ApiPChainTxListItem, len(txs))
101+
for i, tx := range txs {
102+
result[i] = newApiPChainTxListItem(&tx)
103+
}
104+
105+
return result
106+
}

services/main/services.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,21 @@ func main() {
2121
log.Fatal(err) // logger possibly not initialized here so use builtin log
2222
}
2323

24+
epochs, err := utils.NewEpochInfo(ctx)
25+
if err != nil {
26+
log.Fatal(err)
27+
}
28+
2429
muxRouter := mux.NewRouter()
2530
router := utils.NewSwaggerRouter(muxRouter, "Flare P-Chain Indexer", "0.1.0")
2631
routes.AddTransferRoutes(router, ctx)
2732
routes.AddStakerRoutes(router, ctx)
28-
routes.AddTransactionRoutes(router, ctx)
33+
routes.AddTransactionRoutes(router, ctx, epochs)
34+
routes.AddMirroringRoutes(router, ctx, epochs)
2935

3036
// Disabled -- state connector routes are currently not used
3137
// routes.AddQueryRoutes(router, ctx)
3238

33-
if err := routes.AddMirroringRoutes(router, ctx); err != nil {
34-
logger.Fatal("Failed to add mirroring routes: %v", err)
35-
}
3639
router.Finalize()
3740

3841
cors := cors.New(cors.Options{

services/routes/mirroring.go

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ package routes
22

33
import (
44
"errors"
5-
globalConfig "flare-indexer/config"
65
"flare-indexer/database"
7-
"flare-indexer/services/config"
86
"flare-indexer/services/context"
97
"flare-indexer/services/utils"
108
"flare-indexer/utils/contracts/mirroring"
11-
"flare-indexer/utils/contracts/voting"
129
"flare-indexer/utils/staking"
1310
"fmt"
1411
"net/http"
@@ -50,32 +47,11 @@ type mirroringRouteHandlers struct {
5047
epochs staking.EpochInfo
5148
}
5249

53-
func newMirroringRouteHandlers(ctx context.ServicesContext) (*mirroringRouteHandlers, error) {
54-
cfg := ctx.Config()
55-
56-
start, period, err := getEpochStartAndPeriod(cfg)
57-
if err != nil {
58-
return nil, err
59-
}
60-
50+
func newMirroringRouteHandlers(ctx context.ServicesContext, epochs staking.EpochInfo) *mirroringRouteHandlers {
6151
return &mirroringRouteHandlers{
6252
db: NewMirrorDBGorm(ctx.DB()),
63-
epochs: staking.NewEpochInfo(&globalConfig.EpochConfig{}, start, period),
64-
}, nil
65-
}
66-
67-
func getEpochStartAndPeriod(cfg *config.Config) (time.Time, time.Duration, error) {
68-
eth, err := cfg.Chain.DialETH()
69-
if err != nil {
70-
return time.Time{}, 0, err
53+
epochs: epochs,
7154
}
72-
73-
votingContract, err := voting.NewVoting(cfg.ContractAddresses.Voting, eth)
74-
if err != nil {
75-
return time.Time{}, 0, err
76-
}
77-
78-
return staking.GetEpochConfig(votingContract)
7955
}
8056

8157
func (rh *mirroringRouteHandlers) listMirroringTransactions() utils.RouteHandler {
@@ -101,16 +77,11 @@ func (rh *mirroringRouteHandlers) listMirroringTransactions() utils.RouteHandler
10177
GetMirroringResponse{})
10278
}
10379

104-
func AddMirroringRoutes(router utils.Router, ctx context.ServicesContext) error {
105-
rh, err := newMirroringRouteHandlers(ctx)
106-
if err != nil {
107-
return err
108-
}
80+
func AddMirroringRoutes(router utils.Router, ctx context.ServicesContext, epochs staking.EpochInfo) {
81+
rh := newMirroringRouteHandlers(ctx, epochs)
10982

11083
mirroringSubrouter := router.WithPrefix("/mirroring", "Mirroring")
11184
mirroringSubrouter.AddRoute("/tx_data/{tx_id:[0-9a-zA-Z]+}", rh.listMirroringTransactions())
112-
113-
return nil
11485
}
11586

11687
func (rh *mirroringRouteHandlers) createMirroringData(tx *database.PChainTx) ([]MirroringResponse, error) {

services/routes/transactions.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,22 @@ import (
55
"flare-indexer/services/api"
66
"flare-indexer/services/context"
77
"flare-indexer/services/utils"
8+
"flare-indexer/utils/staking"
89
"net/http"
10+
"strconv"
911

1012
"gorm.io/gorm"
1113
)
1214

1315
type transactionRouteHandlers struct {
14-
db *gorm.DB
16+
db *gorm.DB
17+
epochs staking.EpochInfo
1518
}
1619

17-
func newTransactionRouteHandlers(ctx context.ServicesContext) *transactionRouteHandlers {
20+
func newTransactionRouteHandlers(ctx context.ServicesContext, epochs staking.EpochInfo) *transactionRouteHandlers {
1821
return &transactionRouteHandlers{
19-
db: ctx.DB(),
22+
db: ctx.DB(),
23+
epochs: epochs,
2024
}
2125
}
2226

@@ -41,8 +45,37 @@ func (rh *transactionRouteHandlers) getTransaction() utils.RouteHandler {
4145
&api.ApiPChainTx{})
4246
}
4347

44-
func AddTransactionRoutes(router utils.Router, ctx context.ServicesContext) {
45-
vr := newTransactionRouteHandlers(ctx)
48+
func (rh *transactionRouteHandlers) listTransactions() utils.RouteHandler {
49+
handler := func(params map[string]string) ([]api.ApiPChainTxListItem, *utils.ErrorHandler) {
50+
epoch, err := strconv.ParseInt(params["epoch"], 10, 64)
51+
if err != nil {
52+
return nil, utils.HttpErrorHandler(http.StatusBadRequest, "Invalid epoch")
53+
}
54+
55+
startTimestamp, endTimestamp := rh.epochs.GetTimeRange(epoch)
56+
txs, err := database.GetPChainTxsForEpoch(&database.GetPChainTxsForEpochInput{
57+
DB: rh.db,
58+
StartTimestamp: startTimestamp,
59+
EndTimestamp: endTimestamp,
60+
})
61+
if err != nil {
62+
return nil, utils.InternalServerErrorHandler(err)
63+
}
64+
65+
return api.NewApiPChainTxList(txs), nil
66+
}
67+
68+
return utils.NewParamRouteHandler(handler, http.MethodGet,
69+
map[string]string{"epoch:[0-9]+": "Epoch"},
70+
[]api.ApiPChainTxListItem{},
71+
)
72+
}
73+
74+
func AddTransactionRoutes(
75+
router utils.Router, ctx context.ServicesContext, epochs staking.EpochInfo,
76+
) {
77+
vr := newTransactionRouteHandlers(ctx, epochs)
4678
subrouter := router.WithPrefix("/transactions", "Transactions")
4779
subrouter.AddRoute("/get/{tx_id:[0-9a-zA-Z]+}", vr.getTransaction())
80+
subrouter.AddRoute("/list/{epoch:[0-9]+}", vr.listTransactions())
4881
}

services/utils/epochs.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package utils
2+
3+
import (
4+
globalconfig "flare-indexer/config"
5+
"flare-indexer/services/config"
6+
"flare-indexer/services/context"
7+
"flare-indexer/utils/contracts/voting"
8+
"flare-indexer/utils/staking"
9+
"time"
10+
)
11+
12+
func NewEpochInfo(ctx context.ServicesContext) (staking.EpochInfo, error) {
13+
cfg := ctx.Config()
14+
15+
start, period, err := getEpochStartAndPeriod(cfg)
16+
if err != nil {
17+
return staking.EpochInfo{}, err
18+
}
19+
20+
return staking.NewEpochInfo(&globalconfig.EpochConfig{}, start, period), nil
21+
}
22+
23+
func getEpochStartAndPeriod(cfg *config.Config) (time.Time, time.Duration, error) {
24+
eth, err := cfg.Chain.DialETH()
25+
if err != nil {
26+
return time.Time{}, 0, err
27+
}
28+
29+
votingContract, err := voting.NewVoting(cfg.ContractAddresses.Voting, eth)
30+
if err != nil {
31+
return time.Time{}, 0, err
32+
}
33+
34+
return staking.GetEpochConfig(votingContract)
35+
}

0 commit comments

Comments
 (0)