Skip to content

Commit 83a9825

Browse files
committed
add blocks x val endpoint
1 parent f636523 commit 83a9825

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

api/api.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const (
6161
pathMemoryWrongFeeBlocks = "/memory/wrongfeeblocks"
6262
pathMemoryDonations = "/memory/donations"
6363
pathMemoryPoolStatistics = "/memory/statistics"
64+
pathMemoryValidatorBlocks = "/memory/validatorblocks"
6465

6566
// Onchain endpoints: what is submitted to the contract
6667
pathOnchainValidators = "/onchain/validators" // TODO
@@ -178,6 +179,13 @@ type httpOkProofs struct {
178179
PendingRewardsWei string `json:"pending_rewards_wei"`
179180
}
180181

182+
type httpOkValBlocks struct {
183+
ValidatorIndex uint64 `json:"validator_index"`
184+
ProposedBlocks []oracle.Block `json:"proposed_blocks"`
185+
MissedBlocks []oracle.Block `json:"missed_blocks"`
186+
WrongFeeBlocks []oracle.Block `json:"wrong_fee_blocks"`
187+
}
188+
181189
type ApiService struct {
182190
srv *http.Server
183191
cfg *config.Config
@@ -243,6 +251,7 @@ func (m *ApiService) getRouter() http.Handler {
243251
r.HandleFunc(pathMemoryMissedBlocks, m.handleMemoryMissedBlocks).Methods(http.MethodGet)
244252
r.HandleFunc(pathMemoryWrongFeeBlocks, m.handleMemoryWrongFeeBlocks).Methods(http.MethodGet)
245253
r.HandleFunc(pathMemoryDonations, m.handleMemoryDonations).Methods(http.MethodGet)
254+
r.HandleFunc(pathMemoryValidatorBlocks, m.handleMemoryValidatorBlocks).Methods(http.MethodGet)
246255

247256
// Onchain endpoints
248257
r.HandleFunc(pathOnchainMerkleProof, m.handleOnchainMerkleProof).Methods(http.MethodGet)
@@ -305,6 +314,70 @@ func (m *ApiService) handleRoot(w http.ResponseWriter, req *http.Request) {
305314
m.respondOK(w, "see api doc for available endpoints")
306315
}
307316

317+
func (m *ApiService) handleMemoryValidatorBlocks(w http.ResponseWriter, r *http.Request) {
318+
// Access the existing OracleState instance from the ApiService
319+
oracleState := m.oracle.State()
320+
321+
// Retrieve the ProposedBlocks, MissedBlocks, and WrongFeeBlocks from the OracleState
322+
proposedBlocks := oracleState.ProposedBlocks
323+
missedBlocks := oracleState.MissedBlocks
324+
wrongFeeBlocks := oracleState.WrongFeeBlocks
325+
326+
// Create a map to hold the ordered blocks, with the ValidatorIndex as the key
327+
orderedBlocks := make(map[uint64]*httpOkValBlocks)
328+
329+
// Iterate over the ProposedBlocks and add them to the orderedBlocks map
330+
for _, block := range proposedBlocks {
331+
validatorIndex := block.ValidatorIndex
332+
if valBlocks, ok := orderedBlocks[validatorIndex]; ok {
333+
valBlocks.ProposedBlocks = append(valBlocks.ProposedBlocks, block)
334+
} else {
335+
orderedBlocks[validatorIndex] = &httpOkValBlocks{
336+
ValidatorIndex: validatorIndex,
337+
ProposedBlocks: []oracle.Block{block},
338+
}
339+
}
340+
}
341+
342+
// Iterate over the MissedBlocks and add them to the orderedBlocks map
343+
for _, block := range missedBlocks {
344+
validatorIndex := block.ValidatorIndex
345+
if valBlocks, ok := orderedBlocks[validatorIndex]; ok {
346+
valBlocks.MissedBlocks = append(valBlocks.MissedBlocks, block)
347+
} else {
348+
orderedBlocks[validatorIndex] = &httpOkValBlocks{
349+
ValidatorIndex: validatorIndex,
350+
MissedBlocks: []oracle.Block{block},
351+
}
352+
}
353+
}
354+
355+
// Iterate over the WrongFeeBlocks and add them to the orderedBlocks map
356+
for _, block := range wrongFeeBlocks {
357+
validatorIndex := block.ValidatorIndex
358+
if valBlocks, ok := orderedBlocks[validatorIndex]; ok {
359+
valBlocks.WrongFeeBlocks = append(valBlocks.WrongFeeBlocks, block)
360+
} else {
361+
orderedBlocks[validatorIndex] = &httpOkValBlocks{
362+
ValidatorIndex: validatorIndex,
363+
WrongFeeBlocks: []oracle.Block{block},
364+
}
365+
}
366+
}
367+
368+
// Create a slice to hold the final JSON output
369+
finalOutput := make([]*httpOkValBlocks, 0, len(orderedBlocks))
370+
371+
// Iterate over the orderedBlocks map using the validator indices in ascending order
372+
for index := uint64(0); index < uint64(len(orderedBlocks)); index++ {
373+
if valBlocks, ok := orderedBlocks[index]; ok {
374+
finalOutput = append(finalOutput, valBlocks)
375+
}
376+
}
377+
378+
m.respondOK(w, finalOutput)
379+
}
380+
308381
func (m *ApiService) handleMemoryStatistics(w http.ResponseWriter, req *http.Request) {
309382
totalSubscribed := uint64(0)
310383
totalActive := uint64(0)

api/api_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ package api
22

33
import (
44
"encoding/hex"
5+
"fmt"
56
"math/big"
7+
"math/rand"
8+
"net/http"
9+
"net/http/httptest"
610
"testing"
711

812
v1 "github.com/attestantio/go-eth2-client/api/v1"
@@ -314,3 +318,120 @@ func Test_ApiEndpoint(t *testing.T) {
314318
require.Equal(t, 1, 1)
315319
*/
316320
}
321+
322+
func TestHandleGetOrderedBlocksByValidatorKey(t *testing.T) {
323+
324+
// Create a mock config
325+
mockConfig := &config.Config{
326+
ConsensusEndpoint: "http://consensus_endpoint",
327+
ExecutionEndpoint: "http://execution_endpoint",
328+
Network: "testnet",
329+
PoolAddress: "pool_address",
330+
DeployedSlot: 1000,
331+
DeployedBlock: 10000,
332+
CheckPointSizeInSlots: 10,
333+
PoolFeesPercent: 150,
334+
PoolFeesAddress: "fees_address",
335+
DryRun: true,
336+
NumRetries: 3,
337+
CollateralInWei: big.NewInt(1000),
338+
UpdaterKeyPass: "key_pass",
339+
UpdaterKeyPath: "key_path",
340+
}
341+
342+
// Create a mock Oracle using the NewOracle function
343+
mockOracle := oracle.NewOracle(mockConfig)
344+
oracle.NewOracleState(mockConfig)
345+
numBlocks := 100
346+
for i := 0; i < numBlocks; i++ {
347+
// Generate a random ValidatorIndex between 0 and 99
348+
validatorIndex := rand.Intn(100)
349+
350+
// Create mock blocks and add them to the OracleState's ProposedBlocks
351+
mockBlock := blockOkProposal(
352+
rand.Uint64()%101,
353+
uint64(validatorIndex),
354+
"PUBKEY",
355+
big.NewInt(int64(rand.Intn(1000)+10000)),
356+
"0xaaa0000000000000000000000000000000000000",
357+
)
358+
mockOracle.State().HandleCorrectBlockProposal(mockBlock)
359+
360+
// Create mock missed blocks and add them to the OracleState's MissedBlocks
361+
mockMissedBlock := MissedBlock(
362+
rand.Uint64()%101,
363+
uint64(validatorIndex),
364+
"PUBKEY",
365+
)
366+
mockOracle.State().HandleMissedBlock(mockMissedBlock)
367+
368+
// Create mock wrong fee blocks and add them to the OracleState's WrongFeeBlocks
369+
mockWrongFeeBlock := WrongFeeBlock(
370+
rand.Uint64()%101,
371+
uint64(validatorIndex),
372+
"PUBKEY",
373+
)
374+
mockOracle.State().HandleBanValidator(mockWrongFeeBlock)
375+
}
376+
// Create an instance of your ApiService with the mock Oracle
377+
apiService := &ApiService{
378+
oracle: mockOracle,
379+
// other fields initialization...
380+
}
381+
req, err := http.NewRequest("GET", "/memory/validatorblocks", nil)
382+
if err != nil {
383+
t.Fatal(err)
384+
}
385+
rr := httptest.NewRecorder()
386+
// Call the handler function directly, passing in the ResponseRecorder and the Request
387+
handler := http.HandlerFunc(apiService.handleMemoryValidatorBlocks)
388+
handler.ServeHTTP(rr, req)
389+
fmt.Println(rr.Body)
390+
391+
// handler2 := http.HandlerFunc(apiService.handleMemoryAllBlocks)
392+
// handler2.ServeHTTP(rr, req)
393+
// fmt.Print(rr.Body.String())
394+
395+
// Perform assertions on the response
396+
if status := rr.Code; status != http.StatusOK {
397+
t.Errorf("handler returned wrong status code: got %v, want %v", status, http.StatusOK)
398+
}
399+
// Perform additional assertions on the response body or headers if needed
400+
// For example, you can check the response body for expected JSON data
401+
402+
// Example assertion for JSON response
403+
// expectedResponse := `{"message":"success"}`
404+
// if rr.Body.String() != expectedResponse {
405+
// t.Errorf("handler returned unexpected body: got %v, want %v", rr.Body.String(), expectedResponse)
406+
// }
407+
}
408+
409+
func MissedBlock(slot uint64, valIndex uint64, pubKey string) oracle.Block {
410+
return oracle.Block{
411+
Slot: slot,
412+
ValidatorIndex: valIndex,
413+
ValidatorKey: pubKey,
414+
BlockType: oracle.MissedProposal,
415+
}
416+
}
417+
418+
func WrongFeeBlock(slot uint64, valIndex uint64, pubKey string) oracle.Block {
419+
return oracle.Block{
420+
Slot: slot,
421+
ValidatorIndex: valIndex,
422+
ValidatorKey: pubKey,
423+
BlockType: oracle.WrongFeeRecipient,
424+
}
425+
}
426+
427+
func blockOkProposal(slot uint64, valIndex uint64, pubKey string, reward *big.Int, withAddress string) oracle.Block {
428+
return oracle.Block{
429+
Slot: slot,
430+
ValidatorIndex: valIndex,
431+
ValidatorKey: pubKey,
432+
BlockType: oracle.OkPoolProposal,
433+
Reward: reward,
434+
RewardType: oracle.MevBlock,
435+
WithdrawalAddress: withAddress,
436+
}
437+
}

0 commit comments

Comments
 (0)