Skip to content

Commit

Permalink
Add checks for correct commitmentIDs
Browse files Browse the repository at this point in the history
  • Loading branch information
muXxer committed Nov 21, 2023
1 parent 2dc7db9 commit dab4fad
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 33 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
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
31 changes: 21 additions & 10 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 @@ -235,26 +235,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
}

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

resp, err := getUTXOChanges(commitment.ID())
if err != nil {
return err
}
Expand All @@ -268,21 +274,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
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

0 comments on commit dab4fad

Please sign in to comment.