Files
3a9331169b Update avalanchego to v1.9.0-fuji (#472)
Co-authored-by: dhrubabasu <[email protected]>
Co-authored-by: Patrick O'Grady <[email protected]>
Co-authored-by: Stephen <[email protected]>
2022-10-02 20:20:49 -04:00

762 lines
21 KiB
Go

// (c) 2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package api
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/ortelius/cfg"
"github.com/ava-labs/ortelius/services/indexes/params"
"github.com/ava-labs/ortelius/utils"
"github.com/gocraft/web"
"go.uber.org/zap"
)
const DefaultOffsetLimit = 10000
type V2Context struct {
*Context
version uint8
chainID *ids.ID
}
const MetricCount = "api_count"
const MetricMillis = "api_millis"
const MetricTransactionsCount = "api_transactions_count"
const MetricTransactionsMillis = "api_transactions_millis"
const MetricCTransactionsCount = "api_ctransactions_count"
const MetricCTransactionsMillis = "api_ctransactions_millis"
const MetricAddressesCount = "api_addresses_count"
const MetricAddressesMillis = "api_addresses_millis"
const MetricAddressChainsCount = "api_address_chains_count"
const MetricAddressChainsMillis = "api_address_chains_millis"
const MetricAggregateCount = "api_aggregate_count"
const MetricAggregateMillis = "api_aggregate_millis"
const MetricAssetCount = "api_asset_count"
const MetricAssetMillis = "api_asset_millis"
const MetricSearchCount = "api_search_count"
const MetricSearchMillis = "api_search_millis"
// AddV2Routes mounts a V2 API router at the given path, displaying the given
// indexBytes at the root. If chainID is not nil the handlers run in v1
// compatible mode where the `version` param is set to "1" and requests to
// default to filtering by the given chainID.
func AddV2Routes(ctx *Context, router *web.Router, path string, indexBytes []byte, chainID *ids.ID) {
utils.Prometheus.CounterInit(MetricCount, MetricCount)
utils.Prometheus.CounterInit(MetricMillis, MetricMillis)
utils.Prometheus.CounterInit(MetricTransactionsCount, MetricTransactionsCount)
utils.Prometheus.CounterInit(MetricTransactionsMillis, MetricTransactionsMillis)
utils.Prometheus.CounterInit(MetricCTransactionsCount, MetricCTransactionsCount)
utils.Prometheus.CounterInit(MetricTransactionsMillis, MetricCTransactionsMillis)
utils.Prometheus.CounterInit(MetricAddressesCount, MetricAddressesCount)
utils.Prometheus.CounterInit(MetricAddressesMillis, MetricAddressesMillis)
utils.Prometheus.CounterInit(MetricAddressChainsCount, MetricAddressChainsCount)
utils.Prometheus.CounterInit(MetricAddressChainsMillis, MetricAddressChainsMillis)
utils.Prometheus.CounterInit(MetricAggregateCount, MetricAggregateCount)
utils.Prometheus.CounterInit(MetricAggregateMillis, MetricAggregateMillis)
utils.Prometheus.CounterInit(MetricAssetCount, MetricAssetCount)
utils.Prometheus.CounterInit(MetricAssetMillis, MetricAssetMillis)
utils.Prometheus.CounterInit(MetricSearchCount, MetricSearchCount)
utils.Prometheus.CounterInit(MetricSearchMillis, MetricSearchMillis)
v2ctx := V2Context{Context: ctx}
router.Subrouter(v2ctx, path).
Get("/", func(c *V2Context, resp web.ResponseWriter, _ *web.Request) {
if _, err := resp.Write(indexBytes); err != nil {
ctx.sc.Log.Warn("response write failed",
zap.Error(err),
)
}
}).
// Handle legacy v1 logic
Middleware(func(c *V2Context, w web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
c.version = 2
if chainID != nil {
c.chainID = chainID
c.version = 1
}
next(w, r)
}).
Get("/search", (*V2Context).Search).
Get("/aggregates", (*V2Context).Aggregate).
Get("/txfeeAggregates", (*V2Context).TxfeeAggregate).
Get("/transactions/aggregates", (*V2Context).Aggregate).
Get("/addressChains", (*V2Context).AddressChains).
Post("/addressChains", (*V2Context).AddressChainsPost).
// List and Get routes
Get("/transactions", (*V2Context).ListTransactions).
Post("/transactions", (*V2Context).ListTransactionsPost).
Get("/transactions/:id", (*V2Context).GetTransaction).
Get("/addresses", (*V2Context).ListAddresses).
Get("/addresses/:id", (*V2Context).GetAddress).
Get("/outputs", (*V2Context).ListOutputs).
Get("/outputs/:id", (*V2Context).GetOutput).
Get("/assets", (*V2Context).ListAssets).
Get("/assets/:id", (*V2Context).GetAsset).
Get("/atxdata/:id", (*V2Context).ATxData).
Get("/ptxdata/:id", (*V2Context).PTxData).
Get("/ctxdata/:id", (*V2Context).CTxData).
Get("/etxdata/:id", (*V2Context).ETxData).
Get("/ctransactions", (*V2Context).ListCTransactions).
Get("/rawtransaction/:id", (*V2Context).RawTransaction).
Get("/cacheaddresscounts", (*V2Context).CacheAddressCounts).
Get("/cachetxscounts", (*V2Context).CacheTxCounts).
Get("/cacheassets", (*V2Context).CacheAssets).
Get("/cacheassetaggregates", (*V2Context).CacheAssetAggregates).
Get("/cacheaggregates/:id", (*V2Context).CacheAggregates)
}
//
// AVAX
//
func (c *V2Context) Search(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricSearchMillis),
utils.NewCounterIncCollect(MetricSearchCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.SearchParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForParams("search", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.Search(ctx, p, c.avaxAssetID)
},
})
}
func (c *V2Context) TxfeeAggregate(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.TxfeeAggregateParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForParams("aggregate_txfee", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.TxfeeAggregate(ctx, p)
},
})
}
func (c *V2Context) Aggregate(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAggregateMillis),
utils.NewCounterIncCollect(MetricAggregateCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.AggregateParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForParams("aggregate", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.Aggregate(ctx, p, nil)
},
})
}
func (c *V2Context) ListTransactions(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricTransactionsMillis),
utils.NewCounterIncCollect(MetricTransactionsCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListTransactionsParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
if p.ListParams.Offset > DefaultOffsetLimit {
c.WriteErr(w, 400, fmt.Errorf("invalid offset"))
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_transactions", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListTransactions(ctx, p, c.avaxAssetID)
},
})
}
func (c *V2Context) ListTransactionsPost(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricTransactionsMillis),
utils.NewCounterIncCollect(MetricTransactionsCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListTransactionsParams{}
q, err := ParseGetJSON(r, cfg.RequestGetMaxSize)
if err != nil {
c.WriteErr(w, 400, err)
return
}
if err := p.ForValues(c.version, q); err != nil {
c.WriteErr(w, 400, err)
return
}
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
if p.ListParams.Offset > DefaultOffsetLimit {
c.WriteErr(w, 400, fmt.Errorf("invalid offset"))
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_transactions", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListTransactions(ctx, p, c.avaxAssetID)
},
})
}
func (c *V2Context) GetTransaction(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricTransactionsMillis),
utils.NewCounterIncCollect(MetricTransactionsCount),
)
defer func() {
_ = collectors.Collect()
}()
id, err := ids.FromString(r.PathParams["id"])
if err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForID("get_transaction", r.PathParams["id"]),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.GetTransaction(ctx, id, c.avaxAssetID)
},
})
}
func (c *V2Context) ListCTransactions(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricCTransactionsMillis),
utils.NewCounterIncCollect(MetricCTransactionsCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListCTransactionsParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
if p.ListParams.Offset > DefaultOffsetLimit {
c.WriteErr(w, 400, fmt.Errorf("invalid offset"))
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_ctransactions", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListCTransactions(ctx, p)
},
})
}
func (c *V2Context) ListAddresses(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAddressesMillis),
utils.NewCounterIncCollect(MetricAddressesCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListAddressesParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
p.ListParams.DisableCounting = true
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_addresses", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListAddresses(ctx, p)
},
})
}
func (c *V2Context) GetAddress(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAddressesMillis),
utils.NewCounterIncCollect(MetricAddressesCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListAddressesParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
id, err := params.AddressFromString(r.PathParams["id"])
if err != nil {
c.WriteErr(w, 400, err)
return
}
p.Address = &id
p.ListParams.DisableCounting = true
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
c.WriteCacheable(w, utils.Cacheable{
TTL: 1 * time.Second,
Key: c.cacheKeyForParams("get_address", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.GetAddress(ctx, p)
},
})
}
func (c *V2Context) AddressChains(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAddressChainsMillis),
utils.NewCounterIncCollect(MetricAddressChainsCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.AddressChainsParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("address_chains", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.AddressChains(ctx, p)
},
})
}
func (c *V2Context) AddressChainsPost(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAddressChainsMillis),
utils.NewCounterIncCollect(MetricAddressChainsCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.AddressChainsParams{}
q, err := ParseGetJSON(r, cfg.RequestGetMaxSize)
if err != nil {
c.WriteErr(w, 400, err)
return
}
if err := p.ForValues(c.version, q); err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("address_chains", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.AddressChains(ctx, p)
},
})
}
func (c *V2Context) ListOutputs(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListOutputsParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
p.ChainIDs = params.ForValueChainID(c.chainID, p.ChainIDs)
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_outputs", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListOutputs(ctx, p)
},
})
}
func (c *V2Context) GetOutput(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()
id, err := ids.FromString(r.PathParams["id"])
if err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForID("get_output", r.PathParams["id"]),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.GetOutput(ctx, id)
},
})
}
//
// AVM
//
func (c *V2Context) ListAssets(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAssetMillis),
utils.NewCounterIncCollect(MetricAssetCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListAssetsParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForParams("list_assets", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListAssets(ctx, p, nil)
},
})
}
func (c *V2Context) GetAsset(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
utils.NewCounterObserveMillisCollect(MetricAssetMillis),
utils.NewCounterIncCollect(MetricAssetCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListAssetsParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
id := r.PathParams["id"]
p.PathParamID = id
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForParams("get_asset", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.GetAsset(ctx, p, id)
},
})
}
// PVM
func (c *V2Context) ListBlocks(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()
p := &params.ListBlocksParams{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
TTL: 5 * time.Second,
Key: c.cacheKeyForParams("list_blocks", p),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.ListBlocks(ctx, p)
},
})
}
func (c *V2Context) GetBlock(w web.ResponseWriter, r *web.Request) {
collectors := utils.NewCollectors(
utils.NewCounterObserveMillisCollect(MetricMillis),
utils.NewCounterIncCollect(MetricCount),
)
defer func() {
_ = collectors.Collect()
}()
id, err := ids.FromString(r.PathParams["id"])
if err != nil {
c.WriteErr(w, 400, err)
return
}
c.WriteCacheable(w, utils.Cacheable{
Key: c.cacheKeyForID("get_block", r.PathParams["id"]),
CacheableFn: func(ctx context.Context) (interface{}, error) {
return c.avaxReader.GetBlock(ctx, id)
},
})
}
func (c *V2Context) ATxData(w web.ResponseWriter, r *web.Request) {
ctx, cancel := context.WithTimeout(context.Background(), cfg.RequestTimeout)
defer cancel()
p := &params.TxDataParam{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
id := r.PathParams["id"]
p.ID = id
b, err := c.avaxReader.ATxDATA(ctx, p)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) PTxData(w web.ResponseWriter, r *web.Request) {
ctx, cancel := context.WithTimeout(context.Background(), cfg.RequestTimeout)
defer cancel()
p := &params.TxDataParam{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
id := r.PathParams["id"]
p.ID = id
b, err := c.avaxReader.PTxDATA(ctx, p)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) CTxData(w web.ResponseWriter, r *web.Request) {
ctx, cancel := context.WithTimeout(context.Background(), cfg.RequestTimeout)
defer cancel()
p := &params.TxDataParam{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
id := r.PathParams["id"]
p.ID = id
b, err := c.avaxReader.CTxDATA(ctx, p)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) ETxData(w web.ResponseWriter, r *web.Request) {
ctx, cancel := context.WithTimeout(context.Background(), cfg.RequestTimeout)
defer cancel()
p := &params.TxDataParam{}
if err := p.ForValues(c.version, r.URL.Query()); err != nil {
c.WriteErr(w, 400, err)
return
}
id := r.PathParams["id"]
p.ID = id
b, err := c.avaxReader.ETxDATA(ctx, p)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) RawTransaction(w web.ResponseWriter, r *web.Request) {
ctx, cancel := context.WithTimeout(context.Background(), cfg.RequestTimeout)
defer cancel()
id, err := ids.FromString(r.PathParams["id"])
if err != nil {
c.WriteErr(w, 400, err)
return
}
rawdata, err := c.avaxReader.RawTransaction(ctx, id)
if err != nil {
c.WriteErr(w, 400, err)
return
}
b, err := json.Marshal(rawdata)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) CacheAddressCounts(w web.ResponseWriter, r *web.Request) {
res := c.avaxReader.CacheAddressCounts()
b, err := json.Marshal(res)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) CacheTxCounts(w web.ResponseWriter, r *web.Request) {
res := c.avaxReader.CacheTxCounts()
b, err := json.Marshal(res)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) CacheAssets(w web.ResponseWriter, r *web.Request) {
res := c.avaxReader.CacheAssets()
b, err := json.Marshal(res)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) CacheAssetAggregates(w web.ResponseWriter, r *web.Request) {
res := c.avaxReader.CacheAssetAggregates()
b, err := json.Marshal(res)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}
func (c *V2Context) CacheAggregates(w web.ResponseWriter, r *web.Request) {
id := r.PathParams["id"]
res := c.avaxReader.CacheAggregates(id)
b, err := json.Marshal(res)
if err != nil {
c.WriteErr(w, 400, err)
return
}
WriteJSON(w, b)
}