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

[PSL-1214] handle duplicate burn-txid edge cases #897

Merged
merged 1 commit into from
Jul 12, 2024
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: 2 additions & 2 deletions mixins/pasteld_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ func (pt *PastelHandler) GetBurnAddress() string {
func (pt *PastelHandler) ValidateBurnTxID(ctx context.Context, burnTxnID string, estimatedFee float64) error {
var err error

if err := pt.checkBurnTxID(ctx, burnTxnID); err != nil {
if err := pt.CheckBurnTxID(ctx, burnTxnID); err != nil {
log.WithContext(ctx).WithError(err).Errorf("duplicate burnTXID")
err = errors.Errorf("validated burnTXID :%w", err)
return err
Expand All @@ -329,7 +329,7 @@ func (pt *PastelHandler) ValidateBurnTxID(ctx context.Context, burnTxnID string,
return nil
}

func (pt *PastelHandler) checkBurnTxID(ctx context.Context, burnTXID string) error {
func (pt *PastelHandler) CheckBurnTxID(ctx context.Context, burnTXID string) error {
actionTickets, err := pt.PastelClient.FindActionRegTicketsByLabel(ctx, burnTXID)
if err != nil {
return fmt.Errorf("action reg tickets by label: %w", err)
Expand Down
62 changes: 57 additions & 5 deletions walletnode/api/services/cascade.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ func (service *CascadeAPIHandler) StartProcessing(ctx context.Context, p *cascad
}
sortedRelatedFiles := service.register.SortFilesWithHigherAmounts(relatedFiles)

err = service.checkBurnTxIDsValidForRegistration(ctx, sortedBurnTxids, sortedRelatedFiles)
if err != nil {
log.WithContext(ctx).WithField("related_volumes", len(relatedFiles)).
WithError(err).
WithField("burn_txids", len(p.BurnTxids)).
Error("given burn-tx-ids are not valid")
return nil, cascade.MakeBadRequest(errors.New("given burn txids are not valid"))
}

var taskIDs []string
for index, file := range sortedRelatedFiles {
burnTxID := sortedBurnTxids[index]
Expand Down Expand Up @@ -587,12 +596,21 @@ func (service *CascadeAPIHandler) Restore(ctx context.Context, p *cascade.Restor
volumesWithPendingRegistration++
logger.WithField("volume_name", v.FileID).Info("find a volume with no registration, trying again...")

burnTxId, err := service.register.GetBurnTxIdByAmount(ctx, int64(v.ReqBurnTxnAmount))
if err != nil {
log.WithContext(ctx).WithField("amount", int64(v.ReqBurnTxnAmount)).WithError(err).Error("error getting burn TxId for amount")
return nil, cascade.MakeInternalServerError(err)
var burnTxId string
if service.IsBurnTxIDValidForRecovery(ctx, v.BurnTxnID, v.ReqAmount-10) {
log.WithContext(ctx).WithField("burn_txid", v.BurnTxnID).Info("existing burn-txid is valid")
burnTxId = v.BurnTxnID
} else {
log.WithContext(ctx).WithField("burn_txid", v.BurnTxnID).Info("existing burn-txid is not valid, burning the new txid")

burnTxId, err = service.register.GetBurnTxIdByAmount(ctx, int64(v.ReqBurnTxnAmount))
if err != nil {
log.WithContext(ctx).WithField("amount", int64(v.ReqBurnTxnAmount)).WithError(err).Error("error getting burn TxId for amount")
return nil, cascade.MakeInternalServerError(err)
}

logger.WithField("volume_name", v.FileID).Info("estimated fee has been burned, sending for registration")
}
logger.WithField("volume_name", v.FileID).Info("estimated fee has been burned, sending for registration")

addTaskPayload := &common.AddTaskPayload{
FileID: v.FileID,
Expand Down Expand Up @@ -668,6 +686,40 @@ func (service *CascadeAPIHandler) Restore(ctx context.Context, p *cascade.Restor
}, nil
}

func (service *CascadeAPIHandler) checkBurnTxIDsValidForRegistration(ctx context.Context, burnTxIDs []string, files types.Files) error {
if isDuplicateExists(burnTxIDs) {
return errors.New("duplicate burn-tx-ids provided")
}

for _, bid := range burnTxIDs {
if err := service.register.CheckBurnTxIDTicketDuplication(ctx, bid); err != nil {
return err
}
}

for i := 0; i < len(files); i++ {
err := service.register.ValidBurnTxnAmount(ctx, burnTxIDs[i], files[i].ReqBurnTxnAmount)
if err != nil {
return err
}
}

return nil
}

func (service *CascadeAPIHandler) IsBurnTxIDValidForRecovery(ctx context.Context, burnTxID string, estimatedFee float64) bool {
if err := service.register.CheckBurnTxIDTicketDuplication(ctx, burnTxID); err != nil {
return false
}

err := service.register.ValidateBurnTxn(ctx, burnTxID, estimatedFee)
if err != nil {
return false
}

return true
}

// NewCascadeAPIHandler returns the swagger OpenAPI implementation.
func NewCascadeAPIHandler(config *Config, filesMap *sync.Map, register *cascaderegister.CascadeRegistrationService, download *download.NftDownloadingService) *CascadeAPIHandler {
return &CascadeAPIHandler{
Expand Down
29 changes: 29 additions & 0 deletions walletnode/services/cascaderegister/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,35 @@ func (service *CascadeRegistrationService) RegisterVolumeTicket(ctx context.Cont
return txID, nil
}

func (service *CascadeRegistrationService) CheckBurnTxIDTicketDuplication(ctx context.Context, burnTxID string) error {
err := service.pastelHandler.CheckBurnTxID(ctx, burnTxID)
if err != nil {
return err
}

return nil
}

func (service *CascadeRegistrationService) ValidBurnTxnAmount(ctx context.Context, burnTxID string, estimatedFee float64) error {
txnDetail, err := service.pastelHandler.PastelClient.GetTransaction(ctx, burnTxID)
if err != nil {
return err
}

burnTxnAmount := math.Round(math.Abs(txnDetail.Amount)*100) / 100
estimatedFeeAmount := math.Round(estimatedFee*100) / 100

if burnTxnAmount >= estimatedFeeAmount {
return nil
}

return errors.New("the amounts are not equal")
}

func (service *CascadeRegistrationService) ValidateBurnTxn(ctx context.Context, burnTxID string, estimatedFee float64) error {
return service.pastelHandler.ValidateBurnTxID(ctx, burnTxID, estimatedFee)
}

// NewService returns a new Service instance
func NewService(config *Config, pastelClient pastel.Client, nodeClient node.ClientInterface,
fileStorage storage.FileStorageInterface, db storage.KeyValue,
Expand Down
Loading