Commit cd58784b authored by acud's avatar acud Committed by GitHub

feat: add bucket data endpoint (#2321)

parent 3ff1214a
......@@ -336,6 +336,29 @@ components:
exists:
type: boolean
StampBucketData:
type: object
properties:
bucketID:
type: integer
collisions:
type: integer
PostageStampBuckets:
type: object
properties:
depth:
type: integer
bucketDepth:
type: integer
bucketUpperBound:
type: integer
buckets:
type: array
nullable: true
items:
$ref: "#/components/schemas/StampBucketData"
Settlement:
type: object
properties:
......
......@@ -800,6 +800,30 @@ paths:
default:
description: Default response
"/stamps/{id}/buckets":
parameters:
- in: path
name: id
schema:
$ref: "SwarmCommon.yaml#/components/schemas/BatchID"
required: true
description: Swarm address of the stamp
get:
summary: Get extended bucket data of a batch
tags:
- Postage Stamps
responses:
"200":
description: Returns extended bucket data of the provided batch ID
content:
application/json:
schema:
$ref: "SwarmCommon.yaml#/components/schemas/PostageStampBuckets"
"400":
$ref: "SwarmCommon.yaml#/components/responses/400"
default:
description: Default response
"/stamps/{amount}/{depth}":
post:
summary: Buy a new postage batch.
......
......@@ -34,6 +34,8 @@ type (
PostageCreateResponse = postageCreateResponse
PostageStampResponse = postageStampResponse
PostageStampsResponse = postageStampsResponse
PostageStampBucketsResponse = postageStampBucketsResponse
BucketData = bucketData
)
var (
......
......@@ -108,6 +108,18 @@ type postageStampsResponse struct {
Stamps []postageStampResponse `json:"stamps"`
}
type postageStampBucketsResponse struct {
Depth uint8 `json:"depth"`
BucketDepth uint8 `json:"bucketDepth"`
BucketUpperBound uint32 `json:"bucketUpperBound"`
Buckets []bucketData `json:"buckets"`
}
type bucketData struct {
BucketID uint32 `json:"bucketID"`
Collisions uint32 `json:"collisions"`
}
func (s *Service) postageGetStampsHandler(w http.ResponseWriter, _ *http.Request) {
resp := postageStampsResponse{}
for _, v := range s.post.StampIssuers() {
......@@ -134,6 +146,44 @@ func (s *Service) postageGetStampsHandler(w http.ResponseWriter, _ *http.Request
jsonhttp.OK(w, resp)
}
func (s *Service) postageGetStampBucketsHandler(w http.ResponseWriter, r *http.Request) {
idStr := mux.Vars(r)["id"]
if len(idStr) != 64 {
s.logger.Error("get stamp issuer: invalid batchID")
jsonhttp.BadRequest(w, "invalid batchID")
return
}
id, err := hex.DecodeString(idStr)
if err != nil {
s.logger.Error("get stamp issuer: invalid batchID: %v", err)
s.logger.Error("get stamp issuer: invalid batchID")
jsonhttp.BadRequest(w, "invalid batchID")
return
}
issuer, err := s.post.GetStampIssuer(id)
if err != nil {
s.logger.Error("get stamp issuer: get issuer: %v", err)
s.logger.Error("get stamp issuer: get issuer")
jsonhttp.BadRequest(w, "cannot get batch")
return
}
b := issuer.Buckets()
resp := postageStampBucketsResponse{
Depth: issuer.Depth(),
BucketDepth: issuer.BucketDepth(),
BucketUpperBound: issuer.BucketUpperBound(),
Buckets: make([]bucketData, len(b)),
}
for i, v := range b {
resp.Buckets[i] = bucketData{BucketID: uint32(i), Collisions: v}
}
jsonhttp.OK(w, resp)
}
func (s *Service) postageGetStampHandler(w http.ResponseWriter, r *http.Request) {
idStr := mux.Vars(r)["id"]
if len(idStr) != 64 {
......
......@@ -239,7 +239,7 @@ func TestPostageGetStamp(t *testing.T) {
}),
)
})
t.Run("ok", func(t *testing.T) {
t.Run("bad request", func(t *testing.T) {
badBatch := []byte{0, 1, 2}
jsonhttptest.Request(t, ts.Client, http.MethodGet, "/stamps/"+hex.EncodeToString(badBatch), http.StatusBadRequest,
......@@ -249,7 +249,7 @@ func TestPostageGetStamp(t *testing.T) {
}),
)
})
t.Run("ok", func(t *testing.T) {
t.Run("bad request", func(t *testing.T) {
badBatch := []byte{0, 1, 2, 4}
jsonhttptest.Request(t, ts.Client, http.MethodGet, "/stamps/"+hex.EncodeToString(badBatch), http.StatusBadRequest,
......@@ -261,6 +261,47 @@ func TestPostageGetStamp(t *testing.T) {
})
}
func TestPostageGetBuckets(t *testing.T) {
si := postage.NewStampIssuer("", "", batchOk, big.NewInt(3), 11, 10, 1000, true)
mp := mockpost.New(mockpost.WithIssuer(si))
ts := newTestServer(t, testServerOptions{Post: mp})
buckets := make([]debugapi.BucketData, 1024)
for i := range buckets {
buckets[i] = debugapi.BucketData{BucketID: uint32(i)}
}
t.Run("ok", func(t *testing.T) {
jsonhttptest.Request(t, ts.Client, http.MethodGet, "/stamps/"+batchOkStr+"/buckets", http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(&debugapi.PostageStampBucketsResponse{
Depth: si.Depth(),
BucketDepth: si.BucketDepth(),
BucketUpperBound: si.BucketUpperBound(),
Buckets: buckets,
}),
)
})
t.Run("bad batch", func(t *testing.T) {
badBatch := []byte{0, 1, 2}
jsonhttptest.Request(t, ts.Client, http.MethodGet, "/stamps/"+hex.EncodeToString(badBatch)+"/buckets", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(&jsonhttp.StatusResponse{
Code: http.StatusBadRequest,
Message: "invalid batchID",
}),
)
})
t.Run("bad batch", func(t *testing.T) {
badBatch := []byte{0, 1, 2, 4}
jsonhttptest.Request(t, ts.Client, http.MethodGet, "/stamps/"+hex.EncodeToString(badBatch)+"/buckets", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(&jsonhttp.StatusResponse{
Code: http.StatusBadRequest,
Message: "invalid batchID",
}),
)
})
}
func TestReserveState(t *testing.T) {
t.Run("ok", func(t *testing.T) {
ts := newTestServer(t, testServerOptions{
......
......@@ -198,6 +198,12 @@ func (s *Service) newRouter() *mux.Router {
})),
)
router.Handle("/stamps/{id}/buckets", web.ChainHandlers(
web.FinalHandler(jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.postageGetStampBucketsHandler),
})),
)
router.Handle("/stamps/{amount}/{depth}", web.ChainHandlers(
web.FinalHandler(jsonhttp.MethodHandler{
"POST": http.HandlerFunc(s.postageCreateHandler),
......
......@@ -145,6 +145,13 @@ func (si *StampIssuer) BucketDepth() uint8 {
return si.data.BucketDepth
}
// BucketUpperBound returns the maximum number of collisions
// possible in a bucket given the batch's depth and bucket
// depth.
func (si *StampIssuer) BucketUpperBound() uint32 {
return 1 << (si.Depth() - si.BucketDepth())
}
// BlockNumber when this batch was created.
func (si *StampIssuer) BlockNumber() uint64 {
return si.data.BlockNumber
......@@ -154,3 +161,11 @@ func (si *StampIssuer) BlockNumber() uint64 {
func (si *StampIssuer) ImmutableFlag() bool {
return si.data.ImmutableFlag
}
func (si *StampIssuer) Buckets() []uint32 {
si.bucketMu.Lock()
b := make([]uint32, len(si.data.Buckets))
copy(b, si.data.Buckets)
si.bucketMu.Unlock()
return b
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment