/
get_signed_blocks.go
113 lines (94 loc) 路 3.2 KB
/
get_signed_blocks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package http
import (
"math/big"
"net/http"
"strconv"
echo "github.com/labstack/echo/v4"
"github.com/labstack/gommon/log"
guardianproverhealthcheck "github.com/taikoxyz/taiko-mono/packages/guardian-prover-health-check"
)
var (
numBlocks uint64 = 100
)
type block struct {
BlockHash string `json:"blockHash"`
Signature string `json:"signature"`
GuardianProverID uint64 `json:"guardianProverID"`
}
// map of blockID to signed block data
type blockResponse map[uint64][]block
// GetSignedBlocks
//
// returns signed block data by each guardian prover.
//
// @Summary Get signed blocks
// @ID get-signed-blocks
// @Accept json
// @Produce json
// @Success 200 {object} blockResponse
// @Router /signedBlocks[get]
// @Param start query string false "unix timestamp of starting block"
func (srv *Server) GetSignedBlocks(c echo.Context) error {
// getSignedBlocks should rewind either startingBlockID - numBlocksToReturn if startingBlockID
// is passed in, but it is optional, so if it is not, we should get latest and rewind from
// there.
var start uint64 = 0
if c.QueryParam("start") != "" {
var err error
start, err = strconv.ParseUint(c.QueryParam("start"), 10, 64)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
}
// if no start timestamp was provided, we can get the latest block, and return
// defaultNumBlocksToReturn blocks signed before latest, if our guardian prover has signed them.
if start == 0 {
latestBlock, err := srv.ethClient.BlockByNumber(c.Request().Context(), nil)
if err != nil {
if err != nil {
log.Error("Failed to get latest L2 block", "error", err)
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
}
// if latestBlock is greater than the number of blocks to return, we only want to return
// the most recent N blocks signed by this guardian prover.
if latestBlock.NumberU64() > numBlocks {
blockNum := latestBlock.NumberU64() - numBlocks
block, err := srv.ethClient.BlockByNumber(
c.Request().Context(),
new(big.Int).SetUint64(blockNum),
)
if err != nil {
log.Error("Failed to get L2 block", "error", err, "blockNum", blockNum)
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
start = block.NumberU64()
}
}
signedBlocks, err := srv.signedBlockRepo.GetByStartingBlockID(
guardianproverhealthcheck.GetSignedBlocksByStartingBlockIDOpts{
StartingBlockID: start,
},
)
if err != nil {
log.Error("Failed to get latest L2 block", "error", err)
return echo.NewHTTPError(http.StatusInternalServerError, err)
}
// sort signed blocks for easier to consume data
blocks := make(blockResponse)
// then iterate over each one and create a more easily parsable api response
// for the frontend to consume, arranged by a mapping of block ID
// to the signed blocks for each prover by that block ID.
for _, v := range signedBlocks {
b := block{
GuardianProverID: v.GuardianProverID,
BlockHash: v.BlockHash,
Signature: v.Signature,
}
if _, ok := blocks[v.BlockID]; !ok {
blocks[v.BlockID] = make([]block, 0)
}
blocks[v.BlockID] = append(blocks[v.BlockID], b)
}
return c.JSON(http.StatusOK, blocks)
}