github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/beneficiary/change_keeper.go (about)

     1  /*
     2   * Copyright (C) 2021 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package beneficiary
    19  
    20  import (
    21  	"fmt"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/mysteriumnetwork/node/identity"
    25  	"github.com/rs/zerolog/log"
    26  )
    27  
    28  // SettleState represents the state of settle with beneficiary transaction
    29  type SettleState string
    30  
    31  const (
    32  	// Pending transaction is pending
    33  	Pending SettleState = "pending"
    34  	// Completed transaction is completed
    35  	Completed SettleState = "completed"
    36  	// NotFound transaction state
    37  	NotFound SettleState = "not_found"
    38  
    39  	bucketChangeStatus = "beneficiary-change-status"
    40  )
    41  
    42  type beneficiaryChangeKeeper struct {
    43  	st      storage
    44  	chainID int64
    45  }
    46  
    47  func newBeneficiaryChangeKeeper(chainID int64, st storage) *beneficiaryChangeKeeper {
    48  	return &beneficiaryChangeKeeper{
    49  		chainID: chainID,
    50  		st:      st,
    51  	}
    52  }
    53  
    54  // ChangeStatus holds Beneficiary settlement transaction information
    55  type ChangeStatus struct {
    56  	ChangeTo string
    57  	State    SettleState
    58  	Error    string
    59  }
    60  
    61  func newChangeStatus(changeTo string, state SettleState, err error) *ChangeStatus {
    62  	n := &ChangeStatus{
    63  		ChangeTo: changeTo,
    64  		State:    state,
    65  		Error:    "",
    66  	}
    67  
    68  	if err != nil {
    69  		n.Error = err.Error()
    70  	}
    71  
    72  	return n
    73  }
    74  
    75  func (bcs *beneficiaryChangeKeeper) updateChangeStatus(id identity.Identity, sbs SettleState, beneficiary string, settleError error) (*ChangeStatus, error) {
    76  	entry := newChangeStatus(beneficiary, sbs, settleError)
    77  	err := bcs.st.SetValue(bucketChangeStatus, storageKey(bcs.chainID, id.Address), entry)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return entry, nil
    83  }
    84  
    85  func (bcs *beneficiaryChangeKeeper) executeWithStatusTracking(id identity.Identity, bf common.Address, fn func() error) error {
    86  	if _, err := bcs.updateChangeStatus(id, Pending, bf.Hex(), nil); err != nil {
    87  		return fmt.Errorf("failed to start tracking status change: %w", err)
    88  	}
    89  	callbackErr := fn()
    90  
    91  	if _, err := bcs.updateChangeStatus(id, Completed, bf.Hex(), callbackErr); err != nil {
    92  		log.Err(err).Msg("saving beneficiary change status")
    93  	}
    94  
    95  	return callbackErr
    96  }
    97  
    98  // GetChangeStatus returns current change transaction status.
    99  func (bcs *beneficiaryChangeKeeper) GetChangeStatus(id identity.Identity) (*ChangeStatus, error) {
   100  	var b ChangeStatus
   101  	if err := bcs.st.GetValue(bucketChangeStatus, storageKey(bcs.chainID, id.Address), &b); err != nil {
   102  		return nil, err
   103  	}
   104  	return &b, nil
   105  }
   106  
   107  // CleanupAndGetChangeStatus cleans up current change status and returns it.
   108  //
   109  // Cleanup is done using the provided currentBeneficiary, if the beneficiaries match
   110  // and transaction is still in state "Pending" it will be bumped to completed, else
   111  // nothing is done.
   112  func (bcs *beneficiaryChangeKeeper) CleanupAndGetChangeStatus(id identity.Identity, currentBeneficiary string) (*ChangeStatus, error) {
   113  	b, err := bcs.GetChangeStatus(id)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	// Not pending, no need to cleanup.
   119  	if b.State != Pending {
   120  		return b, nil
   121  	}
   122  
   123  	if b.ChangeTo != currentBeneficiary {
   124  		return b, nil
   125  	}
   126  
   127  	return bcs.updateChangeStatus(id, Completed, currentBeneficiary, nil)
   128  }