Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix REST API #537

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading