Skip to content

Commit

Permalink
Merge pull request #537 from iotaledger/fix/rest-api
Browse files Browse the repository at this point in the history
Fix REST API
  • Loading branch information
muXxer authored Nov 21, 2023
2 parents 2dc7db9 + 1da92c1 commit 0e57f8b
Show file tree
Hide file tree
Showing 15 changed files with 106 additions and 72 deletions.
4 changes: 4 additions & 0 deletions components/dashboard/explorer_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ func getSlotDetailsByID(c echo.Context) error {
return err
}

if commitment.ID() != commitmentID {
return ierrors.Errorf("commitment in the store for slot %d does not match the given commitmentID (%s != %s)", commitmentID.Slot(), commitment.ID(), commitmentID)
}

diffs, err := deps.Protocol.MainEngineInstance().Ledger.SlotDiffs(commitmentID.Slot())
if err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions components/inx/server_commitments.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import (
)

func inxCommitment(commitment *model.Commitment) *inx.Commitment {
if commitment == nil {
return nil
}

return &inx.Commitment{
CommitmentId: inx.NewCommitmentId(commitment.ID()),
Commitment: &inx.RawCommitment{
Expand Down
10 changes: 8 additions & 2 deletions components/inx/server_utxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ func NewLedgerOutput(o *utxoledger.Output) (*inx.LedgerOutput, error) {
}

includedSlot := o.SlotBooked()
if includedSlot > 0 && includedSlot <= latestCommitment.Slot() {
if includedSlot > 0 &&
includedSlot <= latestCommitment.Slot() &&
includedSlot >= deps.Protocol.CommittedAPI().ProtocolParameters().GenesisSlot() {

includedCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(includedSlot)
if err != nil {
return nil, ierrors.Wrapf(err, "failed to load commitment with slot: %d", includedSlot)
Expand All @@ -55,7 +58,10 @@ func NewLedgerSpent(s *utxoledger.Spent) (*inx.LedgerSpent, error) {

latestCommitment := deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment()
spentSlot := s.SlotSpent()
if spentSlot > 0 && spentSlot <= latestCommitment.Slot() {
if spentSlot > 0 &&
spentSlot <= latestCommitment.Slot() &&
spentSlot >= deps.Protocol.CommittedAPI().ProtocolParameters().GenesisSlot() {

spentCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(spentSlot)
if err != nil {
return nil, ierrors.Wrapf(err, "failed to load commitment with slot: %d", spentSlot)
Expand Down
12 changes: 12 additions & 0 deletions components/restapi/core/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,19 @@ func congestionForAccountID(c echo.Context) (*apimodels.CongestionResponse, erro
return nil, err
}

commitmentID, err := httpserver.ParseCommitmentIDQueryParam(c, restapipkg.ParameterCommitmentID)
if err != nil {
return nil, err
}

commitment := deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment()
if commitmentID != iotago.EmptyCommitmentID {
// a commitment ID was provided, so we use the commitment for that ID
commitment, err = getCommitmentByID(commitmentID, commitment)
if err != nil {
return nil, err
}
}

acc, exists, err := deps.Protocol.MainEngineInstance().Ledger.Account(accountID, commitment.Slot())
if err != nil {
Expand Down
20 changes: 3 additions & 17 deletions components/restapi/core/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/inx-app/pkg/httpserver"
"github.com/iotaledger/iota-core/pkg/blockhandler"
"github.com/iotaledger/iota-core/pkg/model"
"github.com/iotaledger/iota-core/pkg/restapi"
iotago "github.com/iotaledger/iota.go/v4"
"github.com/iotaledger/iota.go/v4/nodeclient/apimodels"
Expand Down Expand Up @@ -66,31 +65,18 @@ func blockWithMetadataByID(c echo.Context) (*apimodels.BlockWithMetadataResponse
}, nil
}

func blockIssuanceBySlot(slotIndex iotago.SlotIndex) (*apimodels.IssuanceBlockHeaderResponse, error) {
func blockIssuance() (*apimodels.IssuanceBlockHeaderResponse, error) {
references := deps.Protocol.MainEngineInstance().TipSelection.SelectTips(iotago.BasicBlockMaxParents)

var slotCommitment *model.Commitment
var err error
// by default we use latest commitment
if slotIndex == 0 {
slotCommitment = deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment()
} else {
slotCommitment, err = deps.Protocol.MainEngineInstance().Storage.Commitments().Load(slotIndex)
if err != nil {
return nil, ierrors.Wrapf(echo.ErrNotFound, "failed to load commitment for requested slot %d: %s", slotIndex, err)
}
}

if len(references[iotago.StrongParentType]) == 0 {
return nil, ierrors.Wrap(echo.ErrServiceUnavailable, "get references failed")
return nil, ierrors.Wrap(echo.ErrServiceUnavailable, "no strong parents available")
}

resp := &apimodels.IssuanceBlockHeaderResponse{
StrongParents: references[iotago.StrongParentType],
WeakParents: references[iotago.WeakParentType],
ShallowLikeParents: references[iotago.ShallowLikeParentType],
LatestFinalizedSlot: deps.Protocol.MainEngineInstance().SyncManager.LatestFinalizedSlot(),
Commitment: slotCommitment.Commitment(),
Commitment: deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Commitment(),
}

return resp, nil
Expand Down
56 changes: 38 additions & 18 deletions components/restapi/core/commitment.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,59 @@ import (
"github.com/labstack/echo/v4"

"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/inx-app/pkg/httpserver"
restapipkg "github.com/iotaledger/iota-core/pkg/restapi"
"github.com/iotaledger/iota-core/pkg/model"
iotago "github.com/iotaledger/iota.go/v4"
"github.com/iotaledger/iota.go/v4/nodeclient/apimodels"
)

func indexByCommitmentID(c echo.Context) (iotago.SlotIndex, error) {
commitmentID, err := httpserver.ParseCommitmentIDParam(c, restapipkg.ParameterCommitmentID)
if err != nil {
return iotago.SlotIndex(0), ierrors.Wrapf(err, "failed to parse commitment ID %s", c.Param(restapipkg.ParameterCommitmentID))
func getCommitmentBySlot(slot iotago.SlotIndex, latestCommitment ...*model.Commitment) (*model.Commitment, error) {
var latest *model.Commitment
if len(latestCommitment) > 0 {
latest = latestCommitment[0]
} else {
latest = deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment()
}

return commitmentID.Slot(), nil
}
if slot > latest.Slot() {
return nil, ierrors.Wrapf(echo.ErrBadRequest, "commitment is from a future slot (%d > %d)", slot, latest.Slot())
}

func getCommitmentDetails(index iotago.SlotIndex) (*iotago.Commitment, error) {
commitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(index)
commitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(slot)
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment %d: %s", index, err)
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment, slot: %d, error: %w", slot, err)
}

return commitment.Commitment(), nil
return commitment, nil
}

func getUTXOChanges(slot iotago.SlotIndex) (*apimodels.UTXOChangesResponse, error) {
diffs, err := deps.Protocol.MainEngineInstance().Ledger.SlotDiffs(slot)
func getCommitmentByID(commitmentID iotago.CommitmentID, latestCommitment ...*model.Commitment) (*model.Commitment, error) {
var latest *model.Commitment
if len(latestCommitment) > 0 {
latest = latestCommitment[0]
} else {
latest = deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment()
}

if commitmentID.Slot() > latest.Slot() {
return nil, ierrors.Wrapf(echo.ErrBadRequest, "commitment ID (%s) is from a future slot (%d > %d)", commitmentID, commitmentID.Slot(), latest.Slot())
}

commitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(commitmentID.Slot())
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get slot diffs %d: %s", slot, err)
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment, commitmentID: %s, slot: %d, error: %w", commitmentID, commitmentID.Slot(), err)
}

if commitment.ID() != commitmentID {
return nil, ierrors.Wrapf(echo.ErrBadRequest, "commitment in the store for slot %d does not match the given commitmentID (%s != %s)", commitmentID.Slot(), commitment.ID(), commitmentID)
}

commitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(diffs.Slot)
return commitment, nil
}

func getUTXOChanges(commitmentID iotago.CommitmentID) (*apimodels.UTXOChangesResponse, error) {
diffs, err := deps.Protocol.MainEngineInstance().Ledger.SlotDiffs(commitmentID.Slot())
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment %d: %s", diffs.Slot, err)
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get slot diffs, commitmentID: %s, slot: %d, error: %w", commitmentID, commitmentID.Slot(), err)
}

createdOutputs := make(iotago.OutputIDs, len(diffs.Outputs))
Expand All @@ -51,7 +71,7 @@ func getUTXOChanges(slot iotago.SlotIndex) (*apimodels.UTXOChangesResponse, erro
}

return &apimodels.UTXOChangesResponse{
CommitmentID: commitment.ID(),
CommitmentID: commitmentID,
CreatedOutputs: createdOutputs,
ConsumedOutputs: consumedOutputs,
}, nil
Expand Down
35 changes: 22 additions & 13 deletions components/restapi/core/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const (
RouteCommitmentByIndexUTXOChanges = "/commitments/by-index/:" + restapipkg.ParameterSlotIndex + "/utxo-changes"

// RouteCongestion is the route for getting the current congestion state and all account related useful details as block issuance credits.
// GET returns the congestion state related to the specified account.
// GET returns the congestion state related to the specified account. (optional query parameters: "commitmentID" to specify the used commitment)
// MIMEApplicationJSON => json.
// MIMEApplicationVendorIOTASerializerV2 => bytes.
RouteCongestion = "/accounts/:" + restapipkg.ParameterAccountID + "/congestion"
Expand Down Expand Up @@ -224,9 +224,7 @@ func configure() error {
}, checkNodeSynced())

routeGroup.GET(RouteBlockIssuance, func(c echo.Context) error {
index, _ := httpserver.ParseSlotQueryParam(c, restapipkg.ParameterSlotIndex)

resp, err := blockIssuanceBySlot(index)
resp, err := blockIssuance()
if err != nil {
return err
}
Expand All @@ -235,26 +233,32 @@ func configure() error {
}, checkNodeSynced())

routeGroup.GET(RouteCommitmentByID, func(c echo.Context) error {
index, err := indexByCommitmentID(c)
commitmentID, err := httpserver.ParseCommitmentIDParam(c, restapipkg.ParameterCommitmentID)
if err != nil {
return err
}

commitment, err := getCommitmentDetails(index)
commitment, err := getCommitmentByID(commitmentID)
if err != nil {
return err
}

return responseByHeader(c, commitment)
return responseByHeader(c, commitment.Commitment())
})

routeGroup.GET(RouteCommitmentByIDUTXOChanges, func(c echo.Context) error {
index, err := indexByCommitmentID(c)
commitmentID, err := httpserver.ParseCommitmentIDParam(c, restapipkg.ParameterCommitmentID)
if err != nil {
return err
}

// load the commitment to check if it matches the given commitmentID
commitment, err := getCommitmentByID(commitmentID)
if err != nil {
return err
}

resp, err := getUTXOChanges(index)
resp, err := getUTXOChanges(commitment.ID())
if err != nil {
return err
}
Expand All @@ -268,21 +272,26 @@ func configure() error {
return err
}

resp, err := getCommitmentDetails(index)
commitment, err := getCommitmentBySlot(index)
if err != nil {
return err
}

return responseByHeader(c, resp)
return responseByHeader(c, commitment.Commitment())
})

routeGroup.GET(RouteCommitmentByIndexUTXOChanges, func(c echo.Context) error {
index, err := httpserver.ParseSlotParam(c, restapipkg.ParameterSlotIndex)
slot, err := httpserver.ParseSlotParam(c, restapipkg.ParameterSlotIndex)
if err != nil {
return err
}

commitment, err := getCommitmentBySlot(slot)
if err != nil {
return err
}

resp, err := getUTXOChanges(index)
resp, err := getUTXOChanges(commitment.ID())
if err != nil {
return err
}
Expand Down
8 changes: 5 additions & 3 deletions components/restapi/core/utxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ func newOutputMetadataResponse(output *utxoledger.Output) (*apimodels.OutputMeta
}

includedSlotIndex := output.SlotBooked()
if includedSlotIndex <= latestCommitment.Slot() {
genesisSlot := deps.Protocol.MainEngineInstance().CommittedAPI().ProtocolParameters().GenesisSlot()
if includedSlotIndex <= latestCommitment.Slot() && includedSlotIndex >= genesisSlot {
includedCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(includedSlotIndex)
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment with index %d: %s", includedSlotIndex, err)
Expand All @@ -117,7 +118,8 @@ func newSpentMetadataResponse(spent *utxoledger.Spent) (*apimodels.OutputMetadat
}

includedSlotIndex := spent.Output().SlotBooked()
if includedSlotIndex <= latestCommitment.Slot() {
genesisSlot := deps.Protocol.MainEngineInstance().CommittedAPI().ProtocolParameters().GenesisSlot()
if includedSlotIndex <= latestCommitment.Slot() && includedSlotIndex >= genesisSlot {
includedCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(includedSlotIndex)
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment with index %d: %s", includedSlotIndex, err)
Expand All @@ -126,7 +128,7 @@ func newSpentMetadataResponse(spent *utxoledger.Spent) (*apimodels.OutputMetadat
}

spentSlotIndex := spent.SlotSpent()
if spentSlotIndex <= latestCommitment.Slot() {
if spentSlotIndex <= latestCommitment.Slot() && spentSlotIndex >= genesisSlot {
spentCommitment, err := deps.Protocol.MainEngineInstance().Storage.Commitments().Load(spentSlotIndex)
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to load commitment with index %d: %s", spentSlotIndex, err)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
github.com/iotaledger/hive.go/runtime v0.0.0-20231113110812-4ca2b6cc9a42
github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231113110812-4ca2b6cc9a42
github.com/iotaledger/hive.go/stringify v0.0.0-20231113110812-4ca2b6cc9a42
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231120094046-1308e2a5e072
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231121121055-b13a176c5180
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231120082637-ccd5b8465251
github.com/iotaledger/iota.go/v4 v4.0.0-20231120063545-80c263f28140
github.com/labstack/echo/v4 v4.11.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,8 @@ github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231113110812-4ca2b6c
github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231113110812-4ca2b6cc9a42/go.mod h1:FoH3T6yKlZJp8xm8K+zsQiibSynp32v21CpWx8xkek8=
github.com/iotaledger/hive.go/stringify v0.0.0-20231113110812-4ca2b6cc9a42 h1:9c7NiX2cnNPHR9UNWINDqNkolupXiDF3543pR6KLwIg=
github.com/iotaledger/hive.go/stringify v0.0.0-20231113110812-4ca2b6cc9a42/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs=
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231120094046-1308e2a5e072 h1:xbaW2dnDZy0ThcEcdK7ir3b+ynBXsn0R14lgxiFVuB0=
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231120094046-1308e2a5e072/go.mod h1:iFiY6UukYeL8D3N1mtg4jh/9lxTBhzG0QgtD+w0gpps=
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231121121055-b13a176c5180 h1:hAVWoyAF4FE+1gUd2IqvTBDTnQ4Z0GKE6qc8qw9QPqg=
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231121121055-b13a176c5180/go.mod h1:iFiY6UukYeL8D3N1mtg4jh/9lxTBhzG0QgtD+w0gpps=
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231120082637-ccd5b8465251 h1:bYGO8jXNXJNMGPG9etGW7WXfLbRU9ofx1xdd29/sS9M=
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231120082637-ccd5b8465251/go.mod h1:chzj8FDIeXHIh3D52QTZ7imADlzdkhg7o7E2Qr85MJ8=
github.com/iotaledger/iota.go/v4 v4.0.0-20231120063545-80c263f28140 h1:8zHRYT1KADR9bOLUg7Ia4XA3StBHzV4Tb2Qtp42KLN8=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/hive.go/runtime/module"
"github.com/iotaledger/hive.go/runtime/options"
"github.com/iotaledger/iota-core/pkg/model"
"github.com/iotaledger/iota-core/pkg/protocol/engine"
"github.com/iotaledger/iota-core/pkg/protocol/engine/accounts"
"github.com/iotaledger/iota-core/pkg/protocol/engine/blocks"
Expand All @@ -19,9 +18,6 @@ type CommitmentFilter struct {

apiProvider iotago.APIProvider

// commitmentFunc is a function that returns the commitment corresponding to the given slot index.
commitmentFunc func(iotago.SlotIndex) (*model.Commitment, error)

rmcRetrieveFunc func(iotago.SlotIndex) (iotago.Mana, error)

accountRetrieveFunc func(accountID iotago.AccountID, targetIndex iotago.SlotIndex) (*accounts.AccountData, bool, error)
Expand All @@ -33,8 +29,6 @@ func NewProvider(opts ...options.Option[CommitmentFilter]) module.Provider[*engi
return module.Provide(func(e *engine.Engine) commitmentfilter.CommitmentFilter {
c := New(e, opts...)
e.HookConstructed(func() {
c.commitmentFunc = e.Storage.Commitments().Load

c.accountRetrieveFunc = e.Ledger.Account

e.Ledger.HookConstructed(func() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ func NewTestFramework(t *testing.T, apiProvider iotago.APIProvider, optsFilter .
}
tf.CommitmentFilter = New(apiProvider, optsFilter...)

tf.CommitmentFilter.commitmentFunc = func(slot iotago.SlotIndex) (*model.Commitment, error) {
if commitment, ok := tf.commitments[slot]; ok {
return commitment, nil
}
return nil, ierrors.Errorf("no commitment available for slot index %d", slot)
}

tf.CommitmentFilter.accountRetrieveFunc = func(accountID iotago.AccountID, targetSlot iotago.SlotIndex) (*accounts.AccountData, bool, error) {
if accountData, ok := tf.accountData[accountID]; ok {
return accountData, true, nil
Expand Down
4 changes: 4 additions & 0 deletions pkg/protocol/engine/committed_slot_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ func (c *CommittedSlotAPI) Commitment() (commitment *model.Commitment, err error
return nil, ierrors.Wrapf(err, "failed to load commitment for slot %d", c.CommitmentID)
}

if commitment.ID() != c.CommitmentID {
return nil, ierrors.Errorf("commitment in the store does not match the given commitmentID (%s != %s)", commitment.ID(), c.CommitmentID)
}

return commitment, nil
}

Expand Down
2 changes: 1 addition & 1 deletion tools/gendoc/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ require (
github.com/iotaledger/hive.go/runtime v0.0.0-20231113110812-4ca2b6cc9a42 // indirect
github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20231113110812-4ca2b6cc9a42 // indirect
github.com/iotaledger/hive.go/stringify v0.0.0-20231113110812-4ca2b6cc9a42 // indirect
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231120094046-1308e2a5e072 // indirect
github.com/iotaledger/inx-app v1.0.0-rc.3.0.20231121121055-b13a176c5180 // indirect
github.com/iotaledger/inx/go v1.0.0-rc.2.0.20231120082637-ccd5b8465251 // indirect
github.com/iotaledger/iota.go/v4 v4.0.0-20231120063545-80c263f28140 // indirect
github.com/ipfs/boxo v0.13.1 // indirect
Expand Down
Loading

0 comments on commit 0e57f8b

Please sign in to comment.