Skip to content

Commit 90bef0e

Browse files
committed
Small name change for the sql data tables for the validator signing, added address txs query and get all validator signers
1 parent f2a39d6 commit 90bef0e

12 files changed

Lines changed: 368 additions & 21 deletions

File tree

api/config/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type ApiConfig struct {
1111
CorsAllowedMethods []string `yaml:"cors_allowed_methods"`
1212
CorsAllowedHeaders []string `yaml:"cors_allowed_headers"`
1313
CorsMaxAge int `yaml:"cors_max_age"`
14+
ChainName string `yaml:"chain_name"`
1415
}
1516

1617
type ApiEnv struct {

api/handlers/address.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package handlers
2+
3+
import (
4+
"context"
5+
6+
humatypes "github.com/Cogwheel-Validator/spectra-gnoland-indexer/api/huma-types"
7+
"github.com/Cogwheel-Validator/spectra-gnoland-indexer/pkgs/database"
8+
"github.com/danielgtaylor/huma/v2"
9+
)
10+
11+
type AddressHandler struct {
12+
db *database.TimescaleDb
13+
chainName string
14+
}
15+
16+
func NewAddressHandler(db *database.TimescaleDb, chainName string) *AddressHandler {
17+
return &AddressHandler{db: db, chainName: chainName}
18+
}
19+
20+
func (h *AddressHandler) GetAddressTxs(
21+
ctx context.Context,
22+
input *humatypes.AddressGetInput,
23+
) (*humatypes.AddressGetOutput, error) {
24+
address, err := h.db.GetAddressTxs(input.Address, h.chainName, input.FromTimestamp, input.ToTimestamp)
25+
if err != nil {
26+
return nil, huma.Error404NotFound("Address not found", err)
27+
}
28+
return &humatypes.AddressGetOutput{
29+
Body: *address,
30+
}, nil
31+
}

api/handlers/blocks.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,16 @@ func (h *BlocksHandler) GetBlock(ctx context.Context, input *humatypes.BlockGetI
4141
return response, nil
4242
}
4343

44+
// Get from block height a to block height b
4445
func (h *BlocksHandler) GetFromToBlocks(
4546
ctx context.Context,
4647
input *humatypes.FromToBlocksGetInput,
4748
) (*humatypes.FromToBlocksGetOutput, error) {
4849
// Fetch from database
50+
// validate input
51+
if input.FromHeight > input.ToHeight {
52+
return nil, huma.Error400BadRequest("From height must be less than to height", nil)
53+
}
4954
blocks, err := h.db.GetFromToBlocks(input.FromHeight, input.ToHeight, h.chainName)
5055
if err != nil {
5156
return nil, huma.Error404NotFound(fmt.Sprintf("Blocks from height %d to height %d not found", input.FromHeight, input.ToHeight), err)
@@ -65,3 +70,22 @@ func (h *BlocksHandler) GetFromToBlocks(
6570
}
6671
return response, nil
6772
}
73+
74+
func (h *BlocksHandler) GetAllBlockSigners(
75+
ctx context.Context,
76+
input *humatypes.AllBlockSignersGetInput,
77+
) (*humatypes.AllBlockSignersGetOutput, error) {
78+
// Fetch from database
79+
blockSigners, err := h.db.GetAllBlockSigners(h.chainName, input.BlockHeight)
80+
if err != nil {
81+
return nil, huma.Error404NotFound("Block signers not found", err)
82+
}
83+
response := &humatypes.AllBlockSignersGetOutput{
84+
Body: database.BlockSigners{
85+
BlockHeight: blockSigners.BlockHeight,
86+
Proposer: blockSigners.Proposer,
87+
SignedVals: blockSigners.SignedVals,
88+
},
89+
}
90+
return response, nil
91+
}

api/handlers/transactions.go

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,39 +53,80 @@ func (h *TransactionsHandler) GetTransactionMessage(
5353
if err != nil {
5454
return nil, huma.Error404NotFound(fmt.Sprintf("Transaction with hash %s not found", input.TxHash), err)
5555
}
56+
57+
var message humatypes.TransactionMessage
58+
5659
switch msgType {
5760
case "bank_msg_send":
5861
data, err := h.db.GetBankSend(txHashBase64, h.chainName)
5962
if err != nil {
6063
return nil, huma.Error404NotFound(fmt.Sprintf("Transaction with hash %s not found", input.TxHash), err)
6164
}
62-
return &humatypes.TransactionMessageGetOutput{
63-
Body: *data,
64-
}, nil
65+
message = humatypes.TransactionMessage{
66+
MessageType: msgType,
67+
TxHash: data.TxHash,
68+
Timestamp: data.Timestamp,
69+
Signers: data.Signers,
70+
FromAddress: data.FromAddress,
71+
ToAddress: data.ToAddress,
72+
Amount: data.Amount,
73+
}
6574
case "vm_msg_call":
6675
data, err := h.db.GetMsgCall(txHashBase64, h.chainName)
6776
if err != nil {
6877
return nil, huma.Error404NotFound(fmt.Sprintf("Transaction with hash %s not found", input.TxHash), err)
6978
}
70-
return &humatypes.TransactionMessageGetOutput{
71-
Body: *data,
72-
}, nil
79+
message = humatypes.TransactionMessage{
80+
MessageType: msgType,
81+
TxHash: data.TxHash,
82+
Timestamp: data.Timestamp,
83+
Signers: data.Signers,
84+
Caller: data.Caller,
85+
Send: data.Send,
86+
PkgPath: data.PkgPath,
87+
FuncName: data.FuncName,
88+
Args: data.Args,
89+
MaxDeposit: data.MaxDeposit,
90+
}
7391
case "vm_msg_add_package":
7492
data, err := h.db.GetMsgAddPackage(txHashBase64, h.chainName)
7593
if err != nil {
7694
return nil, huma.Error404NotFound(fmt.Sprintf("Transaction with hash %s not found", input.TxHash), err)
7795
}
78-
return &humatypes.TransactionMessageGetOutput{
79-
Body: *data,
80-
}, nil
96+
message = humatypes.TransactionMessage{
97+
MessageType: msgType,
98+
TxHash: data.TxHash,
99+
Timestamp: data.Timestamp,
100+
Signers: data.Signers,
101+
Creator: data.Creator,
102+
PkgPath: data.PkgPath,
103+
PkgName: data.PkgName,
104+
PkgFileNames: data.PkgFileNames,
105+
Send: data.Send,
106+
MaxDeposit: data.MaxDeposit,
107+
}
81108
case "vm_msg_run":
82109
data, err := h.db.GetMsgRun(txHashBase64, h.chainName)
83110
if err != nil {
84111
return nil, huma.Error404NotFound(fmt.Sprintf("Transaction with hash %s not found", input.TxHash), err)
85112
}
86-
return &humatypes.TransactionMessageGetOutput{
87-
Body: *data,
88-
}, nil
113+
message = humatypes.TransactionMessage{
114+
MessageType: msgType,
115+
TxHash: data.TxHash,
116+
Timestamp: data.Timestamp,
117+
Signers: data.Signers,
118+
Caller: data.Caller,
119+
PkgPath: data.PkgPath,
120+
PkgName: data.PkgName,
121+
PkgFileNames: data.PkgFileNames,
122+
Send: data.Send,
123+
MaxDeposit: data.MaxDeposit,
124+
}
125+
default:
126+
return nil, huma.Error400BadRequest("Transaction message type not found", nil)
89127
}
90-
return nil, huma.Error400BadRequest("Transaction message type not found", nil)
128+
129+
return &humatypes.TransactionMessageGetOutput{
130+
Body: message,
131+
}, nil
91132
}

api/huma-types/address.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package humatypes
2+
3+
import (
4+
"time"
5+
6+
"github.com/Cogwheel-Validator/spectra-gnoland-indexer/pkgs/database"
7+
)
8+
9+
type AddressGetInput struct {
10+
Address string `path:"address" doc:"Address" required:"true"`
11+
FromTimestamp time.Time `query:"from_timestamp" doc:"From timestamp" format:"2025-01-01T00:00:00+00:00 or 2025-01-01T00:00:00Z" required:"true"`
12+
ToTimestamp time.Time `query:"to_timestamp" doc:"To timestamp" format:"2025-01-01T00:00:00+00:00 or 2025-01-01T00:00:00Z" required:"true"`
13+
}
14+
15+
type AddressGetOutput struct {
16+
Body []database.AddressTx
17+
}

api/huma-types/block.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@ type BlockGetOutput struct {
2222
type FromToBlocksGetOutput struct {
2323
Body []database.BlockData
2424
}
25+
26+
type AllBlockSignersGetInput struct {
27+
BlockHeight uint64 `path:"block_height" minimum:"1" example:"12345" doc:"Block height" required:"true"`
28+
}
29+
30+
type AllBlockSignersGetOutput struct {
31+
Body database.BlockSigners
32+
}

api/huma-types/transaction.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,53 @@
11
package humatypes
22

3-
import "github.com/Cogwheel-Validator/spectra-gnoland-indexer/pkgs/database"
3+
import (
4+
"time"
5+
6+
"github.com/Cogwheel-Validator/spectra-gnoland-indexer/pkgs/database"
7+
)
48

59
type TransactionGetInput struct {
6-
TxHash string `path:"tx_hash" doc:"Transaction hash (base64url encoded)" required:"true"`
10+
// tx hash needs to be exactly 44 characters long
11+
TxHash string `path:"tx_hash" minLength:"44" maxLength:"44" doc:"Transaction hash (base64url encoded)" required:"true"`
712
}
813

914
type TransactionBasicGetOutput struct {
1015
Body database.Transaction
1116
}
1217

18+
// TransactionMessage represents a unified transaction message type that can be one of:
19+
// bank_msg_send, vm_msg_call, vm_msg_add_package, or vm_msg_run
20+
// not maybe the best implementation, but this one works for now
21+
// to future me, if you figure out a better way to do this, please do so
22+
// for now this is good enough
23+
type TransactionMessage struct {
24+
// Common fields (always present)
25+
MessageType string `json:"message_type" doc:"Type of message: bank_msg_send, vm_msg_call, vm_msg_add_package, or vm_msg_run" enum:"bank_msg_send,vm_msg_call,vm_msg_add_package,vm_msg_run"`
26+
TxHash string `json:"tx_hash" doc:"Transaction hash (base64 encoded)"`
27+
Timestamp time.Time `json:"timestamp" doc:"Transaction timestamp"`
28+
Signers []string `json:"signers" doc:"Signers (addresses)"`
29+
30+
// BankSend specific fields
31+
FromAddress string `json:"from_address,omitempty" doc:"From address (only for bank_msg_send)"`
32+
ToAddress string `json:"to_address,omitempty" doc:"To address (only for bank_msg_send)"`
33+
Amount []database.Amount `json:"amount,omitempty" doc:"Amount (only for bank_msg_send)"`
34+
35+
// MsgCall specific fields
36+
Caller string `json:"caller,omitempty" doc:"Caller address (for vm_msg_call and vm_msg_run)"`
37+
FuncName string `json:"func_name,omitempty" doc:"Function name (only for vm_msg_call)"`
38+
Args string `json:"args,omitempty" doc:"Arguments (only for vm_msg_call)"`
39+
40+
// MsgAddPackage and MsgRun specific fields
41+
Creator string `json:"creator,omitempty" doc:"Creator address (only for vm_msg_add_package)"`
42+
PkgName string `json:"pkg_name,omitempty" doc:"Package name (for vm_msg_add_package and vm_msg_run)"`
43+
PkgFileNames []string `json:"pkg_file_names,omitempty" doc:"Package file names (for vm_msg_add_package and vm_msg_run)"`
44+
45+
// Shared fields for vm_* messages
46+
PkgPath string `json:"pkg_path,omitempty" doc:"Package path (for vm_msg_call, vm_msg_add_package, and vm_msg_run)"`
47+
Send []database.Amount `json:"send,omitempty" doc:"Send amount (for vm_msg_call, vm_msg_add_package, and vm_msg_run)"`
48+
MaxDeposit []database.Amount `json:"max_deposit,omitempty" doc:"Max deposit (for vm_msg_call, vm_msg_add_package, and vm_msg_run)"`
49+
}
50+
1351
type TransactionMessageGetOutput struct {
14-
Body any // database.MsgRun | database.MsgCall | database.MsgAddPackage | database.BankSend
52+
Body TransactionMessage
1553
}

api/main.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ var rootCmd = &cobra.Command{
8484
corsOptions.AllowedMethods = []string{"GET"}
8585
}
8686
if len(corsOptions.AllowedHeaders) == 0 {
87-
corsOptions.AllowedHeaders = []string{"Origin", "Content-Type", "Accept", "Origin"}
87+
corsOptions.AllowedHeaders = []string{"Origin", "Content-Type", "Accept"}
8888
}
8989
if corsOptions.MaxAge == 0 {
9090
corsOptions.MaxAge = 600
@@ -124,29 +124,36 @@ var rootCmd = &cobra.Command{
124124
})
125125

126126
// Initialize handlers with dependencies
127-
blocksHandler := handlers.NewBlocksHandler(db, env.ApiDbName)
128-
transactionsHandler := handlers.NewTransactionsHandler(db, env.ApiDbName)
127+
blocksHandler := handlers.NewBlocksHandler(db, conf.ChainName)
128+
transactionsHandler := handlers.NewTransactionsHandler(db, conf.ChainName)
129+
addressHandler := handlers.NewAddressHandler(db, conf.ChainName)
129130

130131
// Register Block API routes
131132
huma.Get(api, "/block/{height}", blocksHandler.GetBlock)
132133
huma.Get(api, "/blocks/{from_height}/{to_height}", blocksHandler.GetFromToBlocks)
134+
huma.Get(api, "/blocks/{block_height}/signers", blocksHandler.GetAllBlockSigners)
133135

134136
// Register Transaction API routes
135137
huma.Get(api, "/transaction/{tx_hash}", transactionsHandler.GetTransactionBasic)
136138
huma.Get(api, "/transaction/{tx_hash}/message", transactionsHandler.GetTransactionMessage)
137139

140+
// Register Address API routes
141+
huma.Get(api, "/address/{address}/txs", addressHandler.GetAddressTxs)
142+
138143
// Start server using config values
139144
addr := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
140145
log.Printf("Starting server on %s", addr)
141146

142147
// if cert file and key file are provided, use https
143148
if certFilePath != "" && keyFilePath != "" {
144149
err = http.ListenAndServeTLS(addr, certFilePath, keyFilePath, router)
150+
log.Printf("Starting server on %s with HTTPS", addr)
145151
if err != nil {
146152
log.Fatalf("failed to start server: %v", err)
147153
}
148154
} else {
149155
err = http.ListenAndServe(addr, router)
156+
log.Printf("Starting server on %s with HTTP", addr)
150157
if err != nil {
151158
log.Fatalf("failed to start server: %v", err)
152159
}

config-api.yml.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ cors_allowed_headers:
88
- "Origin"
99
- "Content-Type"
1010
- "Accept"
11-
cors_max_age: 600
11+
cors_max_age: 600
12+
chain_name: gnoland

0 commit comments

Comments
 (0)